From 2255b4ac2180816e5e7989b7b6800fb18b734ee0 Mon Sep 17 00:00:00 2001 From: LasNikas Date: Mon, 5 Feb 2024 19:10:34 +0100 Subject: [PATCH 001/107] implement `ExtrudeFace` --- src/TrixiParticles.jl | 2 +- src/setups/extrude_face.jl | 91 ++++++++++++++++++++++++++++++++++++++ src/setups/setups.jl | 1 + 3 files changed, 93 insertions(+), 1 deletion(-) create mode 100644 src/setups/extrude_face.jl diff --git a/src/TrixiParticles.jl b/src/TrixiParticles.jl index f232a664b..2bcc759a4 100644 --- a/src/TrixiParticles.jl +++ b/src/TrixiParticles.jl @@ -53,7 +53,7 @@ export BoundaryMovement export GridNeighborhoodSearch, TrivialNeighborhoodSearch export examples_dir, trixi_include export trixi2vtk -export RectangularTank, RectangularShape, SphereShape +export RectangularTank, RectangularShape, SphereShape, ExtrudeFace export VoxelSphere, RoundSphere, reset_wall! export SourceTermDamping export ShepardKernelCorrection, KernelCorrection, AkinciFreeSurfaceCorrection, diff --git a/src/setups/extrude_face.jl b/src/setups/extrude_face.jl new file mode 100644 index 000000000..27ff8ff60 --- /dev/null +++ b/src/setups/extrude_face.jl @@ -0,0 +1,91 @@ +function ExtrudeFace(face_points::NTuple; particle_spacing, direction, n_extrude::Int, + velocity=zeros(length(direction)), + mass=nothing, density=nothing, pressure=0.0) + NDIMS = length(direction) + face_coords, particle_spacing = generate_face_coords(face_points, particle_spacing) + coordinates_ = (face_coords .+ i * particle_spacing * normalize(direction) for i in 0:n_extrude) + + coordinates = reshape(stack(coordinates_), + (NDIMS, size(face_coords, 2) * (n_extrude + 1))) + + return InitialCondition(; coordinates, velocity, density, mass, pressure, + particle_spacing) +end + +function ExtrudeFace(face_coords::AbstractArray; particle_spacing, direction, + n_extrude::Int, velocity=zeros(length(direction)), + mass=nothing, density=nothing, pressure=0.0) + NDIMS = length(direction) + + coordinates_ = (face_coords .+ i * particle_spacing * normalize(direction) for i in 0:n_extrude) + + coordinates = reshape(stack(coordinates_), + (NDIMS, size(face_coords, 2) * (n_extrude + 1))) + + return InitialCondition(; coordinates, velocity, density, mass, pressure, + particle_spacing) +end + +function generate_face_coords(face_points::NTuple{2}, particle_spacing) + # Verify that points are in 2D space + if any(length.(face_points) .!= 2) + throw(ArgumentError("all points must be 2D coordinates")) + end + + n_points = ceil(Int, norm(face_points[2] - face_points[1]) / particle_spacing) + + coords = stack(range(face_points[1], face_points[2], length=n_points)) + particle_spacing_ = norm(coords[:, 1] - coords[:, 2]) + + if round(particle_spacing, digits=4) != round(particle_spacing_, digits=4) + @info "The desired size ($(norm(face_points[2] - face_points[1])) is not a " * + "multiple of the particle spacing $particle_spacing." * + "\nNew particle spacing is set to $particle_spacing_." + end + + return coords, particle_spacing_ +end + +function generate_face_coords(face_points::NTuple{3}, particle_spacing) + # Verify that points are in 3D space + if any(length.(face_points) .!= 3) + throw(ArgumentError("all points must be 3D coordinates")) + end + + # Vectors defining the edges of the parallelogram + edge1 = face_points[2] - face_points[1] + edge2 = face_points[3] - face_points[1] + + # Check if the points are collinear + if norm(cross(edge1, edge2)) == 0 + throw(ArgumentError("the points must not be collinear")) + end + + # Determine the number of points along each edge + num_points_edge1 = ceil(Int, norm(edge1) / particle_spacing) + num_points_edge2 = ceil(Int, norm(edge2) / particle_spacing) + + points_coords = Vector{SVector{3, Float64}}(undef, + (num_points_edge1 + 1) * + (num_points_edge2 + 1)) + index = 1 + for i in 0:num_points_edge1 + for j in 0:num_points_edge2 + point_on_plane = face_points[1] + (i / num_points_edge1) * edge1 + + (j / num_points_edge2) * edge2 + points_coords[index] = point_on_plane + index += 1 + end + end + + coords = stack(points_coords) + particle_spacing_ = norm(coords[:, 1] - coords[:, 2]) + + if round(particle_spacing, digits=4) != round(particle_spacing_, digits=4) + @info "The desired size $(norm(face_points[2] - face_points[1])) is not a " * + "multiple of the particle spacing $particle_spacing." * + "\nNew particle spacing is set to $particle_spacing_." + end + + return coords, particle_spacing_ +end diff --git a/src/setups/setups.jl b/src/setups/setups.jl index a4754edb5..a08cb7510 100644 --- a/src/setups/setups.jl +++ b/src/setups/setups.jl @@ -1,3 +1,4 @@ include("sphere_shape.jl") include("rectangular_shape.jl") include("rectangular_tank.jl") +include("extrude_face.jl") From e29996049106a8879a0f42f0e433b3d66652260b Mon Sep 17 00:00:00 2001 From: LasNikas Date: Wed, 7 Feb 2024 12:54:15 +0100 Subject: [PATCH 002/107] use `sample_face` in `interpolate_plane_3d` --- src/general/interpolation.jl | 37 +++----------------- src/setups/extrude_face.jl | 65 +++++++++++++++--------------------- 2 files changed, 32 insertions(+), 70 deletions(-) diff --git a/src/general/interpolation.jl b/src/general/interpolation.jl index 29db4dd43..9ef5874fd 100644 --- a/src/general/interpolation.jl +++ b/src/general/interpolation.jl @@ -117,41 +117,14 @@ results = interpolate_plane_3d([0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0] function interpolate_plane_3d(point1, point2, point3, resolution, semi, ref_system, sol; smoothing_length=ref_system.smoothing_length, cut_off_bnd=true) - # Verify that points are in 3D space - if length(point1) != 3 || length(point2) != 3 || length(point3) != 3 - throw(ArgumentError("all points must be 3D coordinates")) - end - - point1_ = SVector{3}(point1) - point2_ = SVector{3}(point2) - point3_ = SVector{3}(point3) - - # Vectors defining the edges of the parallelogram - edge1 = point2_ - point1_ - edge2 = point3_ - point1_ + coords, resolution_ = sample_face((point1, point2, point3), resolution) - # Check if the points are collinear - if norm(cross(edge1, edge2)) == 0 - throw(ArgumentError("the points must not be collinear")) + if round(resolution, digits=3) != round(resolution_, digits=3) + @info "The desired plane size is not a multiple of the resolution $resolution." * + "\nNew resolution is set to $resolution_." end - # Determine the number of points along each edge - num_points_edge1 = ceil(Int, norm(edge1) / resolution) - num_points_edge2 = ceil(Int, norm(edge2) / resolution) - - # Create a set of points on the plane - points_coords = Vector{SVector{3, Float64}}(undef, - (num_points_edge1 + 1) * - (num_points_edge2 + 1)) - index = 1 - for i in 0:num_points_edge1 - for j in 0:num_points_edge2 - point_on_plane = point1 + (i / num_points_edge1) * edge1 + - (j / num_points_edge2) * edge2 - points_coords[index] = point_on_plane - index += 1 - end - end + points_coords = reinterpret(reshape, SVector{3, Float64}, coords) # Interpolate using the generated points results = interpolate_point(points_coords, semi, ref_system, sol, diff --git a/src/setups/extrude_face.jl b/src/setups/extrude_face.jl index 27ff8ff60..654913c3a 100644 --- a/src/setups/extrude_face.jl +++ b/src/setups/extrude_face.jl @@ -1,32 +1,35 @@ -function ExtrudeFace(face_points::NTuple; particle_spacing, direction, n_extrude::Int, +function ExtrudeFace(face_points; particle_spacing, direction, n_extrude=0, velocity=zeros(length(direction)), mass=nothing, density=nothing, pressure=0.0) NDIMS = length(direction) - face_coords, particle_spacing = generate_face_coords(face_points, particle_spacing) - coordinates_ = (face_coords .+ i * particle_spacing * normalize(direction) for i in 0:n_extrude) + face_coords, particle_spacing_ = sample_face(face_points, particle_spacing) - coordinates = reshape(stack(coordinates_), - (NDIMS, size(face_coords, 2) * (n_extrude + 1))) + if round(particle_spacing, digits=4) != round(particle_spacing_, digits=4) + @info "The desired size is not a multiple of the particle spacing $particle_spacing." * + "\nNew particle spacing is set to $particle_spacing_." + end + + coords = (face_coords .+ i * particle_spacing * normalize(direction) for i in 0:n_extrude) + + coords_ = reshape(stack(coords), (NDIMS, size(face_coords, 2) * (n_extrude + 1))) - return InitialCondition(; coordinates, velocity, density, mass, pressure, + return InitialCondition(; coords_, velocity, density, mass, pressure, particle_spacing) end -function ExtrudeFace(face_coords::AbstractArray; particle_spacing, direction, - n_extrude::Int, velocity=zeros(length(direction)), - mass=nothing, density=nothing, pressure=0.0) - NDIMS = length(direction) +function sample_face(face_points::AbstractMatrix, particle_spacing) - coordinates_ = (face_coords .+ i * particle_spacing * normalize(direction) for i in 0:n_extrude) + # `face_points` is already a sampled face + return face_points, particle_spacing +end - coordinates = reshape(stack(coordinates_), - (NDIMS, size(face_coords, 2) * (n_extrude + 1))) +function sample_face(face_points, particle_spacing) - return InitialCondition(; coordinates, velocity, density, mass, pressure, - particle_spacing) + # Convert to tuple + return sample_face(tuple(face_points...), particle_spacing) end -function generate_face_coords(face_points::NTuple{2}, particle_spacing) +function sample_face(face_points::NTuple{2}, particle_spacing) # Verify that points are in 2D space if any(length.(face_points) .!= 2) throw(ArgumentError("all points must be 2D coordinates")) @@ -35,18 +38,12 @@ function generate_face_coords(face_points::NTuple{2}, particle_spacing) n_points = ceil(Int, norm(face_points[2] - face_points[1]) / particle_spacing) coords = stack(range(face_points[1], face_points[2], length=n_points)) - particle_spacing_ = norm(coords[:, 1] - coords[:, 2]) + particle_spacing_new = norm(coords[:, 1] - coords[:, 2]) - if round(particle_spacing, digits=4) != round(particle_spacing_, digits=4) - @info "The desired size ($(norm(face_points[2] - face_points[1])) is not a " * - "multiple of the particle spacing $particle_spacing." * - "\nNew particle spacing is set to $particle_spacing_." - end - - return coords, particle_spacing_ + return coords, particle_spacing_new end -function generate_face_coords(face_points::NTuple{3}, particle_spacing) +function sample_face(face_points::NTuple{3}, particle_spacing) # Verify that points are in 3D space if any(length.(face_points) .!= 3) throw(ArgumentError("all points must be 3D coordinates")) @@ -65,27 +62,19 @@ function generate_face_coords(face_points::NTuple{3}, particle_spacing) num_points_edge1 = ceil(Int, norm(edge1) / particle_spacing) num_points_edge2 = ceil(Int, norm(edge2) / particle_spacing) - points_coords = Vector{SVector{3, Float64}}(undef, - (num_points_edge1 + 1) * - (num_points_edge2 + 1)) + coords = zeros(3, (num_points_edge1 + 1) * (num_points_edge2 + 1)) + index = 1 for i in 0:num_points_edge1 for j in 0:num_points_edge2 point_on_plane = face_points[1] + (i / num_points_edge1) * edge1 + (j / num_points_edge2) * edge2 - points_coords[index] = point_on_plane + coords[:, index] = point_on_plane index += 1 end end - coords = stack(points_coords) - particle_spacing_ = norm(coords[:, 1] - coords[:, 2]) - - if round(particle_spacing, digits=4) != round(particle_spacing_, digits=4) - @info "The desired size $(norm(face_points[2] - face_points[1])) is not a " * - "multiple of the particle spacing $particle_spacing." * - "\nNew particle spacing is set to $particle_spacing_." - end + particle_spacing_new = norm(coords[:, 1] - coords[:, 2]) - return coords, particle_spacing_ + return coords, particle_spacing_new end From 68b35463c67762377fa5512381a437693560abb6 Mon Sep 17 00:00:00 2001 From: LasNikas Date: Wed, 7 Feb 2024 15:59:38 +0100 Subject: [PATCH 003/107] add docs --- src/TrixiParticles.jl | 2 +- src/general/interpolation.jl | 2 +- src/setups/extrude_face.jl | 80 ------------------ src/setups/extrude_geometry.jl | 147 +++++++++++++++++++++++++++++++++ src/setups/setups.jl | 2 +- 5 files changed, 150 insertions(+), 83 deletions(-) delete mode 100644 src/setups/extrude_face.jl create mode 100644 src/setups/extrude_geometry.jl diff --git a/src/TrixiParticles.jl b/src/TrixiParticles.jl index 2bcc759a4..1eb1057fc 100644 --- a/src/TrixiParticles.jl +++ b/src/TrixiParticles.jl @@ -53,7 +53,7 @@ export BoundaryMovement export GridNeighborhoodSearch, TrivialNeighborhoodSearch export examples_dir, trixi_include export trixi2vtk -export RectangularTank, RectangularShape, SphereShape, ExtrudeFace +export RectangularTank, RectangularShape, SphereShape, ExtrudeGeometry export VoxelSphere, RoundSphere, reset_wall! export SourceTermDamping export ShepardKernelCorrection, KernelCorrection, AkinciFreeSurfaceCorrection, diff --git a/src/general/interpolation.jl b/src/general/interpolation.jl index 9ef5874fd..16e316c60 100644 --- a/src/general/interpolation.jl +++ b/src/general/interpolation.jl @@ -117,7 +117,7 @@ results = interpolate_plane_3d([0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0] function interpolate_plane_3d(point1, point2, point3, resolution, semi, ref_system, sol; smoothing_length=ref_system.smoothing_length, cut_off_bnd=true) - coords, resolution_ = sample_face((point1, point2, point3), resolution) + coords, resolution_ = sample_plane((point1, point2, point3), resolution) if round(resolution, digits=3) != round(resolution_, digits=3) @info "The desired plane size is not a multiple of the resolution $resolution." * diff --git a/src/setups/extrude_face.jl b/src/setups/extrude_face.jl deleted file mode 100644 index 654913c3a..000000000 --- a/src/setups/extrude_face.jl +++ /dev/null @@ -1,80 +0,0 @@ -function ExtrudeFace(face_points; particle_spacing, direction, n_extrude=0, - velocity=zeros(length(direction)), - mass=nothing, density=nothing, pressure=0.0) - NDIMS = length(direction) - face_coords, particle_spacing_ = sample_face(face_points, particle_spacing) - - if round(particle_spacing, digits=4) != round(particle_spacing_, digits=4) - @info "The desired size is not a multiple of the particle spacing $particle_spacing." * - "\nNew particle spacing is set to $particle_spacing_." - end - - coords = (face_coords .+ i * particle_spacing * normalize(direction) for i in 0:n_extrude) - - coords_ = reshape(stack(coords), (NDIMS, size(face_coords, 2) * (n_extrude + 1))) - - return InitialCondition(; coords_, velocity, density, mass, pressure, - particle_spacing) -end - -function sample_face(face_points::AbstractMatrix, particle_spacing) - - # `face_points` is already a sampled face - return face_points, particle_spacing -end - -function sample_face(face_points, particle_spacing) - - # Convert to tuple - return sample_face(tuple(face_points...), particle_spacing) -end - -function sample_face(face_points::NTuple{2}, particle_spacing) - # Verify that points are in 2D space - if any(length.(face_points) .!= 2) - throw(ArgumentError("all points must be 2D coordinates")) - end - - n_points = ceil(Int, norm(face_points[2] - face_points[1]) / particle_spacing) - - coords = stack(range(face_points[1], face_points[2], length=n_points)) - particle_spacing_new = norm(coords[:, 1] - coords[:, 2]) - - return coords, particle_spacing_new -end - -function sample_face(face_points::NTuple{3}, particle_spacing) - # Verify that points are in 3D space - if any(length.(face_points) .!= 3) - throw(ArgumentError("all points must be 3D coordinates")) - end - - # Vectors defining the edges of the parallelogram - edge1 = face_points[2] - face_points[1] - edge2 = face_points[3] - face_points[1] - - # Check if the points are collinear - if norm(cross(edge1, edge2)) == 0 - throw(ArgumentError("the points must not be collinear")) - end - - # Determine the number of points along each edge - num_points_edge1 = ceil(Int, norm(edge1) / particle_spacing) - num_points_edge2 = ceil(Int, norm(edge2) / particle_spacing) - - coords = zeros(3, (num_points_edge1 + 1) * (num_points_edge2 + 1)) - - index = 1 - for i in 0:num_points_edge1 - for j in 0:num_points_edge2 - point_on_plane = face_points[1] + (i / num_points_edge1) * edge1 + - (j / num_points_edge2) * edge2 - coords[:, index] = point_on_plane - index += 1 - end - end - - particle_spacing_new = norm(coords[:, 1] - coords[:, 2]) - - return coords, particle_spacing_new -end diff --git a/src/setups/extrude_geometry.jl b/src/setups/extrude_geometry.jl new file mode 100644 index 000000000..2a44c882a --- /dev/null +++ b/src/setups/extrude_geometry.jl @@ -0,0 +1,147 @@ +""" + ExtrudeGeometry(geometry; particle_spacing, direction, n_extrude=0, + velocity=zeros(length(direction)), + mass=nothing, density=nothing, pressure=0.0) +Extrude either a line, a plane or a shape along a specific direction. + +# Arguments +- `geometry`: Either points defining a 3D plane (2D line) + or particle coordinates defining a specific shape. + +# Keywords +- `particle_spacing`: Spacing between the particles. +- `direction`: Vector defining the extrusion direction. +- `n_extrude=0` Number of `geometry` layers in extrude direction. +- `velocity`: Either a function mapping each particle's coordinates to its velocity, + or, for a constant fluid velocity, a vector holding this velocity. + Velocity is constant zero by default. +- `mass`: Either `nothing` (default) to automatically compute particle mass from particle + density and spacing, or a function mapping each particle's coordinates to its mass, + or a scalar for a constant mass over all particles. +- `density`: Either a function mapping each particle's coordinates to its density, + or a scalar for a constant density over all particles. + Obligatory when not using a state equation. Cannot be used together with + `state_equation`. +- `pressure`: Scalar to set the pressure of all particles to this value. + This is only used by the [`EntropicallyDampedSPHSystem`](@ref) and + will be overwritten when using an initial pressure function in the system. + Cannot be used together with hydrostatic pressure gradient. + +# Examples +```julia +# 2D +p1 = [0.0, 0.0] +p2 = [1.0, 1.0] + +direction = [-1.0, 1.0] + +shape = ExtrudeGeometry((p1, p2); direction, particle_spacing=0.1, n_extrude=4, density=1000.0) + +# 3D Plane +p1 = [0.0, 0.0, 0.0] +p2 = [0.5, 1.0, 0.0] +p3 = [1.0, 0.2, 0.0] + +direction = [0.0, 0.0, 1.0] + +shape = ExtrudeGeometry((p1, p2, p3); direction, particle_spacing=0.1, n_extrude=4, density=1000.0) + +# Extrude a 2D shape to a 3D shape +shape = SphereShape(0.1, 0.5, (0.2, 0.4), 1000.0, n_layers=3) + +direction = [0.0, 0.0, 1.0] + +shape = ExtrudeGeometry(shape; direction, particle_spacing=0.1, n_extrude=4, density=1000.0) +``` +""" +function ExtrudeGeometry(geometry; particle_spacing, direction, n_extrude=0, + velocity=zeros(length(direction)), + mass=nothing, density=nothing, pressure=0.0) + NDIMS = length(direction) + face_coords, particle_spacing_ = sample_plane(geometry, particle_spacing) + + if round(particle_spacing, digits=4) != round(particle_spacing_, digits=4) + @info "The desired size is not a multiple of the particle spacing $particle_spacing." * + "\nNew particle spacing is set to $particle_spacing_." + end + + coords = (face_coords .+ i * particle_spacing * normalize(direction) for i in 0:n_extrude) + + coordinates = reshape(stack(coords), (NDIMS, size(face_coords, 2) * (n_extrude + 1))) + + return InitialCondition(; coordinates, velocity, density, mass, pressure, + particle_spacing) +end + +function sample_plane(geometry::AbstractMatrix, particle_spacing) + + # `geometry` is already a sampled shape + return geometry, particle_spacing +end + +function sample_plane(shape::InitialCondition, particle_spacing) + if ndims(shape) == 2 + # Extruding a 2D shape results in a 3D shape + coords = vcat(shape.coordinates, zeros(1, size(shape.coordinates, 2))) + + return coords, particle_spacing + end + + return shape.coordinates, particle_spacing +end + +function sample_plane(plane_points, particle_spacing) + + # Convert to tuple + return sample_plane(tuple(plane_points...), particle_spacing) +end + +function sample_plane(plane_points::NTuple{2}, particle_spacing) + # Verify that points are in 2D space + if any(length.(plane_points) .!= 2) + throw(ArgumentError("all points must be 2D coordinates")) + end + + n_points = ceil(Int, norm(plane_points[2] - plane_points[1]) / particle_spacing) + + coords = stack(range(plane_points[1], plane_points[2], length=n_points)) + particle_spacing_new = norm(coords[:, 1] - coords[:, 2]) + + return coords, particle_spacing_new +end + +function sample_plane(plane_points::NTuple{3}, particle_spacing) + # Verify that points are in 3D space + if any(length.(plane_points) .!= 3) + throw(ArgumentError("all points must be 3D coordinates")) + end + + # Vectors defining the edges of the parallelogram + edge1 = plane_points[2] - plane_points[1] + edge2 = plane_points[3] - plane_points[1] + + # Check if the points are collinear + if norm(cross(edge1, edge2)) == 0 + throw(ArgumentError("the points must not be collinear")) + end + + # Determine the number of points along each edge + num_points_edge1 = ceil(Int, norm(edge1) / particle_spacing) + num_points_edge2 = ceil(Int, norm(edge2) / particle_spacing) + + coords = zeros(3, (num_points_edge1 + 1) * (num_points_edge2 + 1)) + + index = 1 + for i in 0:num_points_edge1 + for j in 0:num_points_edge2 + point_on_plane = plane_points[1] + (i / num_points_edge1) * edge1 + + (j / num_points_edge2) * edge2 + coords[:, index] = point_on_plane + index += 1 + end + end + + particle_spacing_new = norm(coords[:, 1] - coords[:, 2]) + + return coords, particle_spacing_new +end diff --git a/src/setups/setups.jl b/src/setups/setups.jl index a08cb7510..f8c625874 100644 --- a/src/setups/setups.jl +++ b/src/setups/setups.jl @@ -1,4 +1,4 @@ include("sphere_shape.jl") include("rectangular_shape.jl") include("rectangular_tank.jl") -include("extrude_face.jl") +include("extrude_geometry.jl") From 198eadd52c1f79629b7c28cc3346987cef81a668 Mon Sep 17 00:00:00 2001 From: LasNikas Date: Wed, 7 Feb 2024 17:49:22 +0100 Subject: [PATCH 004/107] add tests --- src/setups/extrude_geometry.jl | 6 +- test/setups/extrude_geometry.jl | 107 ++++++++++++++++++++++++++++++++ test/setups/setups.jl | 1 + 3 files changed, 113 insertions(+), 1 deletion(-) create mode 100644 test/setups/extrude_geometry.jl diff --git a/src/setups/extrude_geometry.jl b/src/setups/extrude_geometry.jl index 2a44c882a..f2eb95518 100644 --- a/src/setups/extrude_geometry.jl +++ b/src/setups/extrude_geometry.jl @@ -47,12 +47,16 @@ direction = [0.0, 0.0, 1.0] shape = ExtrudeGeometry((p1, p2, p3); direction, particle_spacing=0.1, n_extrude=4, density=1000.0) # Extrude a 2D shape to a 3D shape -shape = SphereShape(0.1, 0.5, (0.2, 0.4), 1000.0, n_layers=3) +shape = SphereShape(0.1, 0.5, (0.2, 0.4), 1000.0, n_layers=3, + sphere_type=RoundSphere(end_angle=pi)) direction = [0.0, 0.0, 1.0] shape = ExtrudeGeometry(shape; direction, particle_spacing=0.1, n_extrude=4, density=1000.0) ``` + +!!! warning + `particle_spacing` between extrusion layers may differ from shapes `particle_spacing`. """ function ExtrudeGeometry(geometry; particle_spacing, direction, n_extrude=0, velocity=zeros(length(direction)), diff --git a/test/setups/extrude_geometry.jl b/test/setups/extrude_geometry.jl new file mode 100644 index 000000000..b884d500e --- /dev/null +++ b/test/setups/extrude_geometry.jl @@ -0,0 +1,107 @@ +# 2D +@testset verbose=true "Extrude Geometry 2D" begin + point1 = [0.0, 0.0] + point2 = [0.5, 1.0] + directions = [ + [-1.0, 2.0], + -[-1.0, 2.0], + [-2.0, 1.0], + -[-2.0, 1.0], + [1.0, 0.0], + [0.0, 1.0], + ] + + @testset verbose=true "Extrude Line-Coordinates" begin + line = stack(range(point1, point2, length=10)) + + expected_coords = [ + [0.0 0.05555555555555555 0.1111111111111111 0.16666666666666666 0.2222222222222222 0.2777777777777778 0.3333333333333333 0.3888888888888889 0.4444444444444444 0.5 -0.06708203932499368 -0.011526483769438128 0.044029071786117424 0.09958462734167298 0.15514018289722853 0.2106957384527841 0.26625129400833963 0.3218068495638952 0.37736240511945074 0.4329179606750063 -0.13416407864998736 -0.07860852309443181 -0.023052967538876257 0.032502588016679296 0.08805814357223485 0.14361369912779043 0.19916925468334595 0.25472481023890153 0.31028036579445706 0.36583592135001264 -0.20124611797498104 -0.1456905624194255 -0.09013500686386994 -0.034579451308314385 0.020976104247241167 0.07653165980279675 0.13208721535835227 0.18764277091390785 0.24319832646946338 0.29875388202501896 -0.2683281572999747 -0.21277260174441917 -0.15721704618886362 -0.10166149063330807 -0.04610593507775251 0.009449620477803067 0.06500517603335859 0.12056073158891417 0.1761162871444697 0.23167184270002528; + 0.0 0.1111111111111111 0.2222222222222222 0.3333333333333333 0.4444444444444444 0.5555555555555556 0.6666666666666666 0.7777777777777778 0.8888888888888888 1.0 0.13416407864998736 0.24527518976109847 0.35638630087220957 0.4674974119833207 0.5786085230944318 0.6897196342055429 0.800830745316654 0.9119418564277652 1.0230529675388762 1.1341640786499874 0.2683281572999747 0.37943926841108583 0.49055037952219693 0.601661490633308 0.7127726017444191 0.8238837128555303 0.9349948239666414 1.0461059350777524 1.1572170461888636 1.2683281572999747 0.4024922359499621 0.5136033470610732 0.6247144581721843 0.7358255692832953 0.8469366803944065 0.9580477915055177 1.0691589026166288 1.18027001372774 1.291381124838851 1.402492235949962 0.5366563145999494 0.6477674257110606 0.7588785368221717 0.8699896479332827 0.9811007590443939 1.092211870155505 1.203322981266616 1.3144340923777271 1.4255452034888383 1.5366563145999494], + [0.0 0.05555555555555555 0.1111111111111111 0.16666666666666666 0.2222222222222222 0.2777777777777778 0.3333333333333333 0.3888888888888889 0.4444444444444444 0.5 0.06708203932499368 0.12263759488054923 0.17819315043610479 0.23374870599166034 0.2893042615472159 0.34485981710277147 0.400415372658327 0.4559709282138826 0.5115264837694381 0.5670820393249937 0.13416407864998736 0.18971963420554291 0.24527518976109847 0.300830745316654 0.35638630087220957 0.41194185642776515 0.4674974119833207 0.5230529675388762 0.5786085230944318 0.6341640786499874 0.20124611797498104 0.2568016735305366 0.31235722908609215 0.36791278464164767 0.42346834019720325 0.47902389575275883 0.5345794513083144 0.59013500686387 0.6456905624194255 0.701246117974981 0.2683281572999747 0.3238837128555303 0.37943926841108583 0.43499482396664135 0.49055037952219693 0.5461059350777525 0.601661490633308 0.6572170461888636 0.7127726017444191 0.7683281572999747; + 0.0 0.1111111111111111 0.2222222222222222 0.3333333333333333 0.4444444444444444 0.5555555555555556 0.6666666666666666 0.7777777777777778 0.8888888888888888 1.0 -0.13416407864998736 -0.023052967538876257 0.08805814357223485 0.19916925468334595 0.31028036579445706 0.4213914769055682 0.5325025880166793 0.6436136991277904 0.7547248102389015 0.8658359213500126 -0.2683281572999747 -0.15721704618886362 -0.04610593507775251 0.06500517603335859 0.1761162871444697 0.28722739825558086 0.3983385093666919 0.5094496204778031 0.6205607315889141 0.7316718427000253 -0.4024922359499621 -0.291381124838851 -0.18027001372773988 -0.06915890261662877 0.041952208494482335 0.1530633196055935 0.26417443071670454 0.3752855418278157 0.48639665293892675 0.5975077640500379 -0.5366563145999494 -0.42554520348883834 -0.31443409237772724 -0.20332298126661613 -0.09221187015550503 0.018899240955606134 0.13001035206671718 0.24112146317782834 0.3522325742889394 0.46334368540005055], + [0.0 0.05555555555555555 0.1111111111111111 0.16666666666666666 0.2222222222222222 0.2777777777777778 0.3333333333333333 0.3888888888888889 0.4444444444444444 0.5 -0.13416407864998736 -0.07860852309443181 -0.023052967538876257 0.032502588016679296 0.08805814357223485 0.14361369912779043 0.19916925468334595 0.25472481023890153 0.31028036579445706 0.36583592135001264 -0.2683281572999747 -0.21277260174441917 -0.15721704618886362 -0.10166149063330807 -0.04610593507775251 0.009449620477803067 0.06500517603335859 0.12056073158891417 0.1761162871444697 0.23167184270002528 -0.4024922359499621 -0.3469366803944065 -0.291381124838851 -0.23582556928329543 -0.18027001372773988 -0.1247144581721843 -0.06915890261662877 -0.01360334706107319 0.041952208494482335 0.09750776405003792 -0.5366563145999494 -0.48110075904439387 -0.42554520348883834 -0.3699896479332828 -0.31443409237772724 -0.25887853682217166 -0.20332298126661613 -0.14776742571106055 -0.09221187015550503 -0.03665631459994945; + 0.0 0.1111111111111111 0.2222222222222222 0.3333333333333333 0.4444444444444444 0.5555555555555556 0.6666666666666666 0.7777777777777778 0.8888888888888888 1.0 0.06708203932499368 0.17819315043610479 0.2893042615472159 0.400415372658327 0.5115264837694381 0.6226375948805493 0.7337487059916603 0.8448598171027715 0.9559709282138825 1.0670820393249936 0.13416407864998736 0.24527518976109847 0.35638630087220957 0.4674974119833207 0.5786085230944318 0.6897196342055429 0.800830745316654 0.9119418564277652 1.0230529675388762 1.1341640786499874 0.20124611797498104 0.31235722908609215 0.42346834019720325 0.5345794513083144 0.6456905624194255 0.7568016735305366 0.8679127846416477 0.9790238957527588 1.09013500686387 1.2012461179749812 0.2683281572999747 0.37943926841108583 0.49055037952219693 0.601661490633308 0.7127726017444191 0.8238837128555303 0.9349948239666414 1.0461059350777524 1.1572170461888636 1.2683281572999747], + [0.0 0.05555555555555555 0.1111111111111111 0.16666666666666666 0.2222222222222222 0.2777777777777778 0.3333333333333333 0.3888888888888889 0.4444444444444444 0.5 0.13416407864998736 0.18971963420554291 0.24527518976109847 0.300830745316654 0.35638630087220957 0.41194185642776515 0.4674974119833207 0.5230529675388762 0.5786085230944318 0.6341640786499874 0.2683281572999747 0.3238837128555303 0.37943926841108583 0.43499482396664135 0.49055037952219693 0.5461059350777525 0.601661490633308 0.6572170461888636 0.7127726017444191 0.7683281572999747 0.4024922359499621 0.45804779150551767 0.5136033470610732 0.5691589026166287 0.6247144581721843 0.6802700137277399 0.7358255692832953 0.7913811248388509 0.8469366803944065 0.9024922359499621 0.5366563145999494 0.592211870155505 0.6477674257110606 0.7033229812666161 0.7588785368221717 0.8144340923777272 0.8699896479332827 0.9255452034888383 0.9811007590443939 1.0366563145999494; + 0.0 0.1111111111111111 0.2222222222222222 0.3333333333333333 0.4444444444444444 0.5555555555555556 0.6666666666666666 0.7777777777777778 0.8888888888888888 1.0 -0.06708203932499368 0.044029071786117424 0.15514018289722853 0.26625129400833963 0.37736240511945074 0.4884735162305619 0.599584627341673 0.7106957384527841 0.8218068495638952 0.9329179606750063 -0.13416407864998736 -0.023052967538876257 0.08805814357223485 0.19916925468334595 0.31028036579445706 0.4213914769055682 0.5325025880166793 0.6436136991277904 0.7547248102389015 0.8658359213500126 -0.20124611797498104 -0.09013500686386994 0.020976104247241167 0.13208721535835227 0.24319832646946338 0.35430943758057454 0.4654205486916856 0.5765316598027967 0.6876427709139078 0.798753882025019 -0.2683281572999747 -0.15721704618886362 -0.04610593507775251 0.06500517603335859 0.1761162871444697 0.28722739825558086 0.3983385093666919 0.5094496204778031 0.6205607315889141 0.7316718427000253], + [0.0 0.05555555555555555 0.1111111111111111 0.16666666666666666 0.2222222222222222 0.2777777777777778 0.3333333333333333 0.3888888888888889 0.4444444444444444 0.5 0.15 0.20555555555555555 0.26111111111111107 0.31666666666666665 0.37222222222222223 0.4277777777777778 0.4833333333333333 0.5388888888888889 0.5944444444444444 0.65 0.3 0.3555555555555555 0.4111111111111111 0.4666666666666667 0.5222222222222221 0.5777777777777777 0.6333333333333333 0.6888888888888889 0.7444444444444445 0.8 0.44999999999999996 0.5055555555555555 0.5611111111111111 0.6166666666666666 0.6722222222222222 0.7277777777777777 0.7833333333333332 0.8388888888888888 0.8944444444444444 0.95 0.6 0.6555555555555556 0.711111111111111 0.7666666666666666 0.8222222222222222 0.8777777777777778 0.9333333333333333 0.9888888888888889 1.0444444444444443 1.1; + 0.0 0.1111111111111111 0.2222222222222222 0.3333333333333333 0.4444444444444444 0.5555555555555556 0.6666666666666666 0.7777777777777778 0.8888888888888888 1.0 0.0 0.1111111111111111 0.2222222222222222 0.3333333333333333 0.4444444444444444 0.5555555555555556 0.6666666666666666 0.7777777777777778 0.8888888888888888 1.0 0.0 0.1111111111111111 0.2222222222222222 0.3333333333333333 0.4444444444444444 0.5555555555555556 0.6666666666666666 0.7777777777777778 0.8888888888888888 1.0 0.0 0.1111111111111111 0.2222222222222222 0.3333333333333333 0.4444444444444444 0.5555555555555556 0.6666666666666666 0.7777777777777778 0.8888888888888888 1.0 0.0 0.1111111111111111 0.2222222222222222 0.3333333333333333 0.4444444444444444 0.5555555555555556 0.6666666666666666 0.7777777777777778 0.8888888888888888 1.0], + [0.0 0.05555555555555555 0.1111111111111111 0.16666666666666666 0.2222222222222222 0.2777777777777778 0.3333333333333333 0.3888888888888889 0.4444444444444444 0.5 0.0 0.05555555555555555 0.1111111111111111 0.16666666666666666 0.2222222222222222 0.2777777777777778 0.3333333333333333 0.3888888888888889 0.4444444444444444 0.5 0.0 0.05555555555555555 0.1111111111111111 0.16666666666666666 0.2222222222222222 0.2777777777777778 0.3333333333333333 0.3888888888888889 0.4444444444444444 0.5 0.0 0.05555555555555555 0.1111111111111111 0.16666666666666666 0.2222222222222222 0.2777777777777778 0.3333333333333333 0.3888888888888889 0.4444444444444444 0.5 0.0 0.05555555555555555 0.1111111111111111 0.16666666666666666 0.2222222222222222 0.2777777777777778 0.3333333333333333 0.3888888888888889 0.4444444444444444 0.5; + 0.0 0.1111111111111111 0.2222222222222222 0.3333333333333333 0.4444444444444444 0.5555555555555556 0.6666666666666666 0.7777777777777778 0.8888888888888888 1.0 0.15 0.26111111111111107 0.37222222222222223 0.4833333333333333 0.5944444444444444 0.7055555555555556 0.8166666666666667 0.9277777777777778 1.0388888888888888 1.15 0.3 0.4111111111111111 0.5222222222222221 0.6333333333333333 0.7444444444444445 0.8555555555555556 0.9666666666666666 1.0777777777777777 1.1888888888888889 1.3 0.44999999999999996 0.5611111111111111 0.6722222222222222 0.7833333333333332 0.8944444444444444 1.0055555555555555 1.1166666666666667 1.2277777777777779 1.3388888888888888 1.45 0.6 0.711111111111111 0.8222222222222222 0.9333333333333333 1.0444444444444443 1.1555555555555554 1.2666666666666666 1.3777777777777778 1.488888888888889 1.6], + ] + + @testset "Direction $i" for i in eachindex(directions) + shape = ExtrudeGeometry(line; direction=directions[i], particle_spacing=0.15, + n_extrude=4, density=1.0) + + @test shape.coordinates == expected_coords[i] + end + end + + @testset verbose=true "Extrude Line-Points" begin + expected_coords = [ + [0.0 0.07142857142857142 0.14285714285714285 0.21428571428571427 0.2857142857142857 0.35714285714285715 0.42857142857142855 0.5 -0.07142001120134328 8.560227228143757e-6 0.07143713165579957 0.142865703084371 0.21429427451294242 0.28572284594151387 0.35715141737008527 0.4285799887986567 -0.14284002240268656 -0.07141145097411514 1.7120454456287515e-5 0.07144569188302771 0.14287426331159914 0.2143028347401706 0.285731406168742 0.35715997759731344 -0.21426003360402984 -0.14283146217545842 -0.071402890746887 2.5680681684431272e-5 0.07145425211025586 0.1428828235388273 0.2143113949673987 0.28573996639597016 -0.2856800448053731 -0.2142514733768017 -0.14282290194823027 -0.07139433051965885 3.424090891257503e-5 0.07146281233748403 0.14289138376605542 0.21431995519462688; + 0.0 0.14285714285714285 0.2857142857142857 0.42857142857142855 0.5714285714285714 0.7142857142857143 0.8571428571428571 1.0 0.14284002240268656 0.2856971652598294 0.42855430811697226 0.571411450974115 0.714268593831258 0.8571257366884009 0.9999828795455437 1.1428400224026865 0.2856800448053731 0.428537187662516 0.5713943305196588 0.7142514733768017 0.8571086162339445 0.9999657590910874 1.14282290194823 1.2856800448053731 0.4285200672080597 0.5713772100652026 0.7142343529223454 0.8570914957794882 0.9999486386366311 1.142805781493774 1.2856629243509168 1.4285200672080598 0.5713600896107462 0.714217232467889 0.857074375325032 0.9999315181821748 1.1427886610393176 1.2856458038964607 1.4285029467536035 1.5713600896107462], + [0.0 0.07142857142857142 0.14285714285714285 0.21428571428571427 0.2857142857142857 0.35714285714285715 0.42857142857142855 0.5 0.07142001120134328 0.1428485826299147 0.21427715405848613 0.2857057254870575 0.357134296915629 0.42856286834420043 0.49999143977277183 0.5714200112013432 0.14284002240268656 0.214268593831258 0.2856971652598294 0.35712573668840086 0.42855430811697226 0.4999828795455437 0.571411450974115 0.6428400224026866 0.21426003360402984 0.2856886050326013 0.3571171764611727 0.4285457478897441 0.49997431931831554 0.571402890746887 0.6428314621754584 0.7142600336040299 0.2856800448053731 0.3571086162339445 0.428537187662516 0.4999657590910874 0.5713943305196588 0.6428229019482303 0.7142514733768017 0.7856800448053731; + 0.0 0.14285714285714285 0.2857142857142857 0.42857142857142855 0.5714285714285714 0.7142857142857143 0.8571428571428571 1.0 -0.14284002240268656 1.7120454456287515e-5 0.14287426331159914 0.285731406168742 0.42858854902588484 0.5714456918830277 0.7143028347401705 0.8571599775973134 -0.2856800448053731 -0.14282290194823027 3.424090891257503e-5 0.14289138376605542 0.2857485266231983 0.4286056694803412 0.571462812337484 0.7143199551946269 -0.4285200672080597 -0.28566292435091684 -0.142805781493774 5.1361363368862545e-5 0.1429085042205117 0.2857656470776546 0.4286227899347974 0.5714799327919403 -0.5713600896107462 -0.4285029467536034 -0.28564580389646055 -0.1427886610393177 6.848181782515006e-5 0.14292562467496805 0.28578276753211085 0.42863991038925375], + [0.0 0.07142857142857142 0.14285714285714285 0.21428571428571427 0.2857142857142857 0.35714285714285715 0.42857142857142855 0.5 -0.14284002240268656 -0.07141145097411514 1.7120454456287515e-5 0.07144569188302771 0.14287426331159914 0.2143028347401706 0.285731406168742 0.35715997759731344 -0.2856800448053731 -0.2142514733768017 -0.14282290194823027 -0.07139433051965885 3.424090891257503e-5 0.07146281233748403 0.14289138376605542 0.21431995519462688 -0.4285200672080597 -0.3570914957794883 -0.28566292435091684 -0.2142343529223454 -0.142805781493774 -0.07137721006520253 5.1361363368862545e-5 0.07147993279194031 -0.5713600896107462 -0.49993151818217485 -0.4285029467536034 -0.35707437532503195 -0.28564580389646055 -0.2142172324678891 -0.1427886610393177 -0.07136008961074625; + 0.0 0.14285714285714285 0.2857142857142857 0.42857142857142855 0.5714285714285714 0.7142857142857143 0.8571428571428571 1.0 0.07142001120134328 0.21427715405848613 0.357134296915629 0.49999143977277183 0.6428485826299146 0.7857057254870576 0.9285628683442004 1.0714200112013432 0.14284002240268656 0.2856971652598294 0.42855430811697226 0.571411450974115 0.714268593831258 0.8571257366884009 0.9999828795455437 1.1428400224026865 0.21426003360402984 0.3571171764611727 0.49997431931831554 0.6428314621754584 0.7856886050326013 0.9285457478897441 1.0714028907468869 1.21426003360403 0.2856800448053731 0.428537187662516 0.5713943305196588 0.7142514733768017 0.8571086162339445 0.9999657590910874 1.14282290194823 1.2856800448053731], + [0.0 0.07142857142857142 0.14285714285714285 0.21428571428571427 0.2857142857142857 0.35714285714285715 0.42857142857142855 0.5 0.14284002240268656 0.214268593831258 0.2856971652598294 0.35712573668840086 0.42855430811697226 0.4999828795455437 0.571411450974115 0.6428400224026866 0.2856800448053731 0.3571086162339445 0.428537187662516 0.4999657590910874 0.5713943305196588 0.6428229019482303 0.7142514733768017 0.7856800448053731 0.4285200672080597 0.4999486386366311 0.5713772100652026 0.642805781493774 0.7142343529223454 0.7856629243509168 0.8570914957794882 0.9285200672080597 0.5713600896107462 0.6427886610393176 0.714217232467889 0.7856458038964605 0.857074375325032 0.9285029467536035 0.9999315181821748 1.0713600896107462; + 0.0 0.14285714285714285 0.2857142857142857 0.42857142857142855 0.5714285714285714 0.7142857142857143 0.8571428571428571 1.0 -0.07142001120134328 0.07143713165579957 0.21429427451294242 0.35715141737008527 0.5000085602272282 0.642865703084371 0.7857228459415138 0.9285799887986568 -0.14284002240268656 1.7120454456287515e-5 0.14287426331159914 0.285731406168742 0.42858854902588484 0.5714456918830277 0.7143028347401705 0.8571599775973134 -0.21426003360402984 -0.071402890746887 0.07145425211025586 0.2143113949673987 0.35716853782454155 0.5000256806816845 0.6428828235388273 0.7857399663959701 -0.2856800448053731 -0.14282290194823027 3.424090891257503e-5 0.14289138376605542 0.2857485266231983 0.4286056694803412 0.571462812337484 0.7143199551946269], + [0.0 0.07142857142857142 0.14285714285714285 0.21428571428571427 0.2857142857142857 0.35714285714285715 0.42857142857142855 0.5 0.1597 0.23112857142857143 0.30255714285714286 0.37398571428571425 0.4454142857142857 0.5168428571428572 0.5882714285714286 0.6597 0.3194 0.3908285714285714 0.46225714285714287 0.5336857142857143 0.6051142857142857 0.6765428571428571 0.7479714285714285 0.8194 0.4791 0.5505285714285715 0.6219571428571429 0.6933857142857143 0.7648142857142857 0.8362428571428572 0.9076714285714286 0.9791000000000001 0.6388 0.7102285714285714 0.7816571428571428 0.8530857142857143 0.9245142857142857 0.9959428571428572 1.0673714285714286 1.1388; + 0.0 0.14285714285714285 0.2857142857142857 0.42857142857142855 0.5714285714285714 0.7142857142857143 0.8571428571428571 1.0 0.0 0.14285714285714285 0.2857142857142857 0.42857142857142855 0.5714285714285714 0.7142857142857143 0.8571428571428571 1.0 0.0 0.14285714285714285 0.2857142857142857 0.42857142857142855 0.5714285714285714 0.7142857142857143 0.8571428571428571 1.0 0.0 0.14285714285714285 0.2857142857142857 0.42857142857142855 0.5714285714285714 0.7142857142857143 0.8571428571428571 1.0 0.0 0.14285714285714285 0.2857142857142857 0.42857142857142855 0.5714285714285714 0.7142857142857143 0.8571428571428571 1.0], + [0.0 0.07142857142857142 0.14285714285714285 0.21428571428571427 0.2857142857142857 0.35714285714285715 0.42857142857142855 0.5 0.0 0.07142857142857142 0.14285714285714285 0.21428571428571427 0.2857142857142857 0.35714285714285715 0.42857142857142855 0.5 0.0 0.07142857142857142 0.14285714285714285 0.21428571428571427 0.2857142857142857 0.35714285714285715 0.42857142857142855 0.5 0.0 0.07142857142857142 0.14285714285714285 0.21428571428571427 0.2857142857142857 0.35714285714285715 0.42857142857142855 0.5 0.0 0.07142857142857142 0.14285714285714285 0.21428571428571427 0.2857142857142857 0.35714285714285715 0.42857142857142855 0.5; + 0.0 0.14285714285714285 0.2857142857142857 0.42857142857142855 0.5714285714285714 0.7142857142857143 0.8571428571428571 1.0 0.1597 0.30255714285714286 0.4454142857142857 0.5882714285714286 0.7311285714285713 0.8739857142857144 1.0168428571428572 1.1597 0.3194 0.46225714285714287 0.6051142857142857 0.7479714285714285 0.8908285714285714 1.0336857142857143 1.1765428571428571 1.3194 0.4791 0.6219571428571429 0.7648142857142857 0.9076714285714286 1.0505285714285715 1.1933857142857143 1.336242857142857 1.4791 0.6388 0.7816571428571428 0.9245142857142857 1.0673714285714286 1.2102285714285714 1.3530857142857142 1.495942857142857 1.6388], + ] + + @testset "Direction $i" for i in eachindex(directions) + shape = ExtrudeGeometry((point1, point2); direction=directions[i], + particle_spacing=0.1597, n_extrude=4, density=1.0) + + @test shape.coordinates == expected_coords[i] + end + end +end + +# 3D +@testset verbose=true "Extrude Geometry 3D" begin + @testset verbose=true "Extrude 2D Shape" begin + geometry = SphereShape(0.1, 0.5, (0.2, 0.4), 1000.0, n_layers=3, + sphere_type=RoundSphere(end_angle=pi)) + particle_spacing = geometry.particle_spacing + + directions = [[0.0, 0.0, 1.0], [0.0, -1.0, 1.0]] + + expected_coords = [ + [0.44999999999999996 0.43096988312782164 0.3767766952966369 0.29567085809127247 0.20000000000000004 0.10432914190872761 0.023223304703363173 -0.030969883127821618 -0.04999999999999993 0.55 0.5358225407650741 0.4944387364909134 0.42920125688084976 0.3453952545506602 0.24981019339564986 0.15018980660435027 0.0546047454493398 -0.029201256880849707 -0.09443873649091344 -0.135822540765074 -0.14999999999999997 0.6499999999999999 0.6387175604818206 0.6054359905560887 0.5518241671106134 0.4805704108364301 0.39524768260290116 0.3001344202803415 0.20000000000000004 0.09986557971965856 0.0047523173970988875 -0.08057041083643002 -0.1518241671106133 -0.20543599055608852 -0.23871756048182058 -0.24999999999999994 0.44999999999999996 0.43096988312782164 0.3767766952966369 0.29567085809127247 0.20000000000000004 0.10432914190872761 0.023223304703363173 -0.030969883127821618 -0.04999999999999993 0.55 0.5358225407650741 0.4944387364909134 0.42920125688084976 0.3453952545506602 0.24981019339564986 0.15018980660435027 0.0546047454493398 -0.029201256880849707 -0.09443873649091344 -0.135822540765074 -0.14999999999999997 0.6499999999999999 0.6387175604818206 0.6054359905560887 0.5518241671106134 0.4805704108364301 0.39524768260290116 0.3001344202803415 0.20000000000000004 0.09986557971965856 0.0047523173970988875 -0.08057041083643002 -0.1518241671106133 -0.20543599055608852 -0.23871756048182058 -0.24999999999999994 0.44999999999999996 0.43096988312782164 0.3767766952966369 0.29567085809127247 0.20000000000000004 0.10432914190872761 0.023223304703363173 -0.030969883127821618 -0.04999999999999993 0.55 0.5358225407650741 0.4944387364909134 0.42920125688084976 0.3453952545506602 0.24981019339564986 0.15018980660435027 0.0546047454493398 -0.029201256880849707 -0.09443873649091344 -0.135822540765074 -0.14999999999999997 0.6499999999999999 0.6387175604818206 0.6054359905560887 0.5518241671106134 0.4805704108364301 0.39524768260290116 0.3001344202803415 0.20000000000000004 0.09986557971965856 0.0047523173970988875 -0.08057041083643002 -0.1518241671106133 -0.20543599055608852 -0.23871756048182058 -0.24999999999999994 0.44999999999999996 0.43096988312782164 0.3767766952966369 0.29567085809127247 0.20000000000000004 0.10432914190872761 0.023223304703363173 -0.030969883127821618 -0.04999999999999993 0.55 0.5358225407650741 0.4944387364909134 0.42920125688084976 0.3453952545506602 0.24981019339564986 0.15018980660435027 0.0546047454493398 -0.029201256880849707 -0.09443873649091344 -0.135822540765074 -0.14999999999999997 0.6499999999999999 0.6387175604818206 0.6054359905560887 0.5518241671106134 0.4805704108364301 0.39524768260290116 0.3001344202803415 0.20000000000000004 0.09986557971965856 0.0047523173970988875 -0.08057041083643002 -0.1518241671106133 -0.20543599055608852 -0.23871756048182058 -0.24999999999999994 0.44999999999999996 0.43096988312782164 0.3767766952966369 0.29567085809127247 0.20000000000000004 0.10432914190872761 0.023223304703363173 -0.030969883127821618 -0.04999999999999993 0.55 0.5358225407650741 0.4944387364909134 0.42920125688084976 0.3453952545506602 0.24981019339564986 0.15018980660435027 0.0546047454493398 -0.029201256880849707 -0.09443873649091344 -0.135822540765074 -0.14999999999999997 0.6499999999999999 0.6387175604818206 0.6054359905560887 0.5518241671106134 0.4805704108364301 0.39524768260290116 0.3001344202803415 0.20000000000000004 0.09986557971965856 0.0047523173970988875 -0.08057041083643002 -0.1518241671106133 -0.20543599055608852 -0.23871756048182058 -0.24999999999999994; + 0.4 0.4956708580912724 0.5767766952966369 0.6309698831278217 0.6499999999999999 0.6309698831278217 0.5767766952966369 0.4956708580912725 0.4000000000000001 0.4 0.4986063948945004 0.5892242861094592 0.6645123510239904 0.7183711983740815 0.7464375046583265 0.7464375046583265 0.7183711983740815 0.6645123510239904 0.5892242861094591 0.49860639489450054 0.4000000000000001 0.4 0.5001344202803415 0.5952476826029012 0.6805704108364301 0.7518241671106134 0.8054359905560886 0.8387175604818207 0.85 0.8387175604818207 0.8054359905560886 0.7518241671106134 0.6805704108364301 0.5952476826029012 0.5001344202803415 0.4000000000000001 0.4 0.4956708580912724 0.5767766952966369 0.6309698831278217 0.6499999999999999 0.6309698831278217 0.5767766952966369 0.4956708580912725 0.4000000000000001 0.4 0.4986063948945004 0.5892242861094592 0.6645123510239904 0.7183711983740815 0.7464375046583265 0.7464375046583265 0.7183711983740815 0.6645123510239904 0.5892242861094591 0.49860639489450054 0.4000000000000001 0.4 0.5001344202803415 0.5952476826029012 0.6805704108364301 0.7518241671106134 0.8054359905560886 0.8387175604818207 0.85 0.8387175604818207 0.8054359905560886 0.7518241671106134 0.6805704108364301 0.5952476826029012 0.5001344202803415 0.4000000000000001 0.4 0.4956708580912724 0.5767766952966369 0.6309698831278217 0.6499999999999999 0.6309698831278217 0.5767766952966369 0.4956708580912725 0.4000000000000001 0.4 0.4986063948945004 0.5892242861094592 0.6645123510239904 0.7183711983740815 0.7464375046583265 0.7464375046583265 0.7183711983740815 0.6645123510239904 0.5892242861094591 0.49860639489450054 0.4000000000000001 0.4 0.5001344202803415 0.5952476826029012 0.6805704108364301 0.7518241671106134 0.8054359905560886 0.8387175604818207 0.85 0.8387175604818207 0.8054359905560886 0.7518241671106134 0.6805704108364301 0.5952476826029012 0.5001344202803415 0.4000000000000001 0.4 0.4956708580912724 0.5767766952966369 0.6309698831278217 0.6499999999999999 0.6309698831278217 0.5767766952966369 0.4956708580912725 0.4000000000000001 0.4 0.4986063948945004 0.5892242861094592 0.6645123510239904 0.7183711983740815 0.7464375046583265 0.7464375046583265 0.7183711983740815 0.6645123510239904 0.5892242861094591 0.49860639489450054 0.4000000000000001 0.4 0.5001344202803415 0.5952476826029012 0.6805704108364301 0.7518241671106134 0.8054359905560886 0.8387175604818207 0.85 0.8387175604818207 0.8054359905560886 0.7518241671106134 0.6805704108364301 0.5952476826029012 0.5001344202803415 0.4000000000000001 0.4 0.4956708580912724 0.5767766952966369 0.6309698831278217 0.6499999999999999 0.6309698831278217 0.5767766952966369 0.4956708580912725 0.4000000000000001 0.4 0.4986063948945004 0.5892242861094592 0.6645123510239904 0.7183711983740815 0.7464375046583265 0.7464375046583265 0.7183711983740815 0.6645123510239904 0.5892242861094591 0.49860639489450054 0.4000000000000001 0.4 0.5001344202803415 0.5952476826029012 0.6805704108364301 0.7518241671106134 0.8054359905560886 0.8387175604818207 0.85 0.8387175604818207 0.8054359905560886 0.7518241671106134 0.6805704108364301 0.5952476826029012 0.5001344202803415 0.4000000000000001; + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.30000000000000004 0.30000000000000004 0.30000000000000004 0.30000000000000004 0.30000000000000004 0.30000000000000004 0.30000000000000004 0.30000000000000004 0.30000000000000004 0.30000000000000004 0.30000000000000004 0.30000000000000004 0.30000000000000004 0.30000000000000004 0.30000000000000004 0.30000000000000004 0.30000000000000004 0.30000000000000004 0.30000000000000004 0.30000000000000004 0.30000000000000004 0.30000000000000004 0.30000000000000004 0.30000000000000004 0.30000000000000004 0.30000000000000004 0.30000000000000004 0.30000000000000004 0.30000000000000004 0.30000000000000004 0.30000000000000004 0.30000000000000004 0.30000000000000004 0.30000000000000004 0.30000000000000004 0.30000000000000004 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4], + [0.44999999999999996 0.43096988312782164 0.3767766952966369 0.29567085809127247 0.20000000000000004 0.10432914190872761 0.023223304703363173 -0.030969883127821618 -0.04999999999999993 0.55 0.5358225407650741 0.4944387364909134 0.42920125688084976 0.3453952545506602 0.24981019339564986 0.15018980660435027 0.0546047454493398 -0.029201256880849707 -0.09443873649091344 -0.135822540765074 -0.14999999999999997 0.6499999999999999 0.6387175604818206 0.6054359905560887 0.5518241671106134 0.4805704108364301 0.39524768260290116 0.3001344202803415 0.20000000000000004 0.09986557971965856 0.0047523173970988875 -0.08057041083643002 -0.1518241671106133 -0.20543599055608852 -0.23871756048182058 -0.24999999999999994 0.44999999999999996 0.43096988312782164 0.3767766952966369 0.29567085809127247 0.20000000000000004 0.10432914190872761 0.023223304703363173 -0.030969883127821618 -0.04999999999999993 0.55 0.5358225407650741 0.4944387364909134 0.42920125688084976 0.3453952545506602 0.24981019339564986 0.15018980660435027 0.0546047454493398 -0.029201256880849707 -0.09443873649091344 -0.135822540765074 -0.14999999999999997 0.6499999999999999 0.6387175604818206 0.6054359905560887 0.5518241671106134 0.4805704108364301 0.39524768260290116 0.3001344202803415 0.20000000000000004 0.09986557971965856 0.0047523173970988875 -0.08057041083643002 -0.1518241671106133 -0.20543599055608852 -0.23871756048182058 -0.24999999999999994 0.44999999999999996 0.43096988312782164 0.3767766952966369 0.29567085809127247 0.20000000000000004 0.10432914190872761 0.023223304703363173 -0.030969883127821618 -0.04999999999999993 0.55 0.5358225407650741 0.4944387364909134 0.42920125688084976 0.3453952545506602 0.24981019339564986 0.15018980660435027 0.0546047454493398 -0.029201256880849707 -0.09443873649091344 -0.135822540765074 -0.14999999999999997 0.6499999999999999 0.6387175604818206 0.6054359905560887 0.5518241671106134 0.4805704108364301 0.39524768260290116 0.3001344202803415 0.20000000000000004 0.09986557971965856 0.0047523173970988875 -0.08057041083643002 -0.1518241671106133 -0.20543599055608852 -0.23871756048182058 -0.24999999999999994 0.44999999999999996 0.43096988312782164 0.3767766952966369 0.29567085809127247 0.20000000000000004 0.10432914190872761 0.023223304703363173 -0.030969883127821618 -0.04999999999999993 0.55 0.5358225407650741 0.4944387364909134 0.42920125688084976 0.3453952545506602 0.24981019339564986 0.15018980660435027 0.0546047454493398 -0.029201256880849707 -0.09443873649091344 -0.135822540765074 -0.14999999999999997 0.6499999999999999 0.6387175604818206 0.6054359905560887 0.5518241671106134 0.4805704108364301 0.39524768260290116 0.3001344202803415 0.20000000000000004 0.09986557971965856 0.0047523173970988875 -0.08057041083643002 -0.1518241671106133 -0.20543599055608852 -0.23871756048182058 -0.24999999999999994 0.44999999999999996 0.43096988312782164 0.3767766952966369 0.29567085809127247 0.20000000000000004 0.10432914190872761 0.023223304703363173 -0.030969883127821618 -0.04999999999999993 0.55 0.5358225407650741 0.4944387364909134 0.42920125688084976 0.3453952545506602 0.24981019339564986 0.15018980660435027 0.0546047454493398 -0.029201256880849707 -0.09443873649091344 -0.135822540765074 -0.14999999999999997 0.6499999999999999 0.6387175604818206 0.6054359905560887 0.5518241671106134 0.4805704108364301 0.39524768260290116 0.3001344202803415 0.20000000000000004 0.09986557971965856 0.0047523173970988875 -0.08057041083643002 -0.1518241671106133 -0.20543599055608852 -0.23871756048182058 -0.24999999999999994; + 0.4 0.4956708580912724 0.5767766952966369 0.6309698831278217 0.6499999999999999 0.6309698831278217 0.5767766952966369 0.4956708580912725 0.4000000000000001 0.4 0.4986063948945004 0.5892242861094592 0.6645123510239904 0.7183711983740815 0.7464375046583265 0.7464375046583265 0.7183711983740815 0.6645123510239904 0.5892242861094591 0.49860639489450054 0.4000000000000001 0.4 0.5001344202803415 0.5952476826029012 0.6805704108364301 0.7518241671106134 0.8054359905560886 0.8387175604818207 0.85 0.8387175604818207 0.8054359905560886 0.7518241671106134 0.6805704108364301 0.5952476826029012 0.5001344202803415 0.4000000000000001 0.3292893218813453 0.4249601799726177 0.5060660171779822 0.5602592050091669 0.5792893218813452 0.5602592050091669 0.5060660171779822 0.4249601799726177 0.3292893218813453 0.3292893218813453 0.4278957167758457 0.5185136079908045 0.5938016729053357 0.6476605202554268 0.6757268265396718 0.6757268265396718 0.6476605202554268 0.5938016729053357 0.5185136079908044 0.4278957167758458 0.3292893218813453 0.3292893218813453 0.4294237421616868 0.5245370044842464 0.6098597327177754 0.6811134889919587 0.7347253124374339 0.7680068823631659 0.7792893218813453 0.7680068823631659 0.7347253124374339 0.6811134889919587 0.6098597327177754 0.5245370044842464 0.4294237421616868 0.3292893218813453 0.2585786437626905 0.3542495018539629 0.4353553390593274 0.48954852689051215 0.5085786437626905 0.48954852689051215 0.4353553390593274 0.354249501853963 0.2585786437626906 0.2585786437626905 0.3571850386571909 0.4478029298721497 0.5230909947866809 0.576949842136772 0.605016148421017 0.605016148421017 0.576949842136772 0.5230909947866809 0.4478029298721496 0.35718503865719103 0.2585786437626906 0.2585786437626905 0.358713064043032 0.45382632636559167 0.5391490545991207 0.610402810873304 0.6640146343187792 0.6972962042445112 0.7085786437626904 0.6972962042445112 0.6640146343187792 0.610402810873304 0.5391490545991207 0.45382632636559167 0.358713064043032 0.2585786437626906 0.18786796564403574 0.28353882373530814 0.3646446609406726 0.41883784877185737 0.43786796564403563 0.41883784877185737 0.3646446609406726 0.2835388237353082 0.1878679656440358 0.18786796564403574 0.28647436053853614 0.3770922517534949 0.45238031666802614 0.5062391640181172 0.5343054703023622 0.5343054703023622 0.5062391640181172 0.45238031666802614 0.3770922517534948 0.28647436053853625 0.1878679656440358 0.18786796564403574 0.2880023859243772 0.3831156482469369 0.4684383764804658 0.5396921327546491 0.5933039562001243 0.6265855261258564 0.6378679656440357 0.6265855261258564 0.5933039562001243 0.5396921327546491 0.4684383764804658 0.3831156482469369 0.2880023859243772 0.1878679656440358 0.11715728752538102 0.21282814561665342 0.2939339828220179 0.34812717065320264 0.3671572875253809 0.34812717065320264 0.2939339828220179 0.21282814561665347 0.11715728752538107 0.11715728752538102 0.21576368241988142 0.3063815736348402 0.3816696385493714 0.43552848589946247 0.46359479218370747 0.46359479218370747 0.43552848589946247 0.3816696385493714 0.3063815736348401 0.21576368241988153 0.11715728752538107 0.11715728752538102 0.2172917078057225 0.31240497012828217 0.3977276983618111 0.4689814546359944 0.5225932780814696 0.5558748480072017 0.567157287525381 0.5558748480072017 0.5225932780814696 0.4689814546359944 0.3977276983618111 0.31240497012828217 0.2172917078057225 0.11715728752538107; + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.07071067811865475 0.07071067811865475 0.07071067811865475 0.07071067811865475 0.07071067811865475 0.07071067811865475 0.07071067811865475 0.07071067811865475 0.07071067811865475 0.07071067811865475 0.07071067811865475 0.07071067811865475 0.07071067811865475 0.07071067811865475 0.07071067811865475 0.07071067811865475 0.07071067811865475 0.07071067811865475 0.07071067811865475 0.07071067811865475 0.07071067811865475 0.07071067811865475 0.07071067811865475 0.07071067811865475 0.07071067811865475 0.07071067811865475 0.07071067811865475 0.07071067811865475 0.07071067811865475 0.07071067811865475 0.07071067811865475 0.07071067811865475 0.07071067811865475 0.07071067811865475 0.07071067811865475 0.07071067811865475 0.1414213562373095 0.1414213562373095 0.1414213562373095 0.1414213562373095 0.1414213562373095 0.1414213562373095 0.1414213562373095 0.1414213562373095 0.1414213562373095 0.1414213562373095 0.1414213562373095 0.1414213562373095 0.1414213562373095 0.1414213562373095 0.1414213562373095 0.1414213562373095 0.1414213562373095 0.1414213562373095 0.1414213562373095 0.1414213562373095 0.1414213562373095 0.1414213562373095 0.1414213562373095 0.1414213562373095 0.1414213562373095 0.1414213562373095 0.1414213562373095 0.1414213562373095 0.1414213562373095 0.1414213562373095 0.1414213562373095 0.1414213562373095 0.1414213562373095 0.1414213562373095 0.1414213562373095 0.1414213562373095 0.21213203435596428 0.21213203435596428 0.21213203435596428 0.21213203435596428 0.21213203435596428 0.21213203435596428 0.21213203435596428 0.21213203435596428 0.21213203435596428 0.21213203435596428 0.21213203435596428 0.21213203435596428 0.21213203435596428 0.21213203435596428 0.21213203435596428 0.21213203435596428 0.21213203435596428 0.21213203435596428 0.21213203435596428 0.21213203435596428 0.21213203435596428 0.21213203435596428 0.21213203435596428 0.21213203435596428 0.21213203435596428 0.21213203435596428 0.21213203435596428 0.21213203435596428 0.21213203435596428 0.21213203435596428 0.21213203435596428 0.21213203435596428 0.21213203435596428 0.21213203435596428 0.21213203435596428 0.21213203435596428 0.282842712474619 0.282842712474619 0.282842712474619 0.282842712474619 0.282842712474619 0.282842712474619 0.282842712474619 0.282842712474619 0.282842712474619 0.282842712474619 0.282842712474619 0.282842712474619 0.282842712474619 0.282842712474619 0.282842712474619 0.282842712474619 0.282842712474619 0.282842712474619 0.282842712474619 0.282842712474619 0.282842712474619 0.282842712474619 0.282842712474619 0.282842712474619 0.282842712474619 0.282842712474619 0.282842712474619 0.282842712474619 0.282842712474619 0.282842712474619 0.282842712474619 0.282842712474619 0.282842712474619 0.282842712474619 0.282842712474619 0.282842712474619], + ] + + @testset "Direction $i" for i in eachindex(directions) + shape = ExtrudeGeometry(geometry; direction=directions[i], particle_spacing, + n_extrude=4, density=1.0) + + @test shape.coordinates == expected_coords[i] + end + end + + @testset verbose=true "Extrude 3D Plane" begin + p1 = [0.0, 0.0, 0.0] + p2 = [0.5, 1.0, 1.0] + p3 = [1.0, 0.2, 0.0] + + direction = [0.0, 0.0, 1.0] + + expected_coords = [0.0 0.09090909090909091 0.18181818181818182 0.2727272727272727 0.36363636363636365 0.45454545454545453 0.5454545454545454 0.6363636363636364 0.7272727272727273 0.8181818181818182 0.9090909090909091 1.0 0.03333333333333333 0.12424242424242424 0.21515151515151515 0.30606060606060603 0.396969696969697 0.48787878787878786 0.5787878787878787 0.6696969696969697 0.7606060606060606 0.8515151515151516 0.9424242424242424 1.0333333333333334 0.06666666666666667 0.1575757575757576 0.24848484848484848 0.33939393939393936 0.4303030303030303 0.5212121212121212 0.6121212121212121 0.703030303030303 0.793939393939394 0.8848484848484849 0.9757575757575757 1.0666666666666667 0.1 0.19090909090909092 0.28181818181818186 0.3727272727272727 0.4636363636363636 0.5545454545454546 0.6454545454545454 0.7363636363636363 0.8272727272727273 0.9181818181818182 1.009090909090909 1.1 0.13333333333333333 0.22424242424242424 0.3151515151515152 0.406060606060606 0.49696969696969695 0.5878787878787879 0.6787878787878787 0.7696969696969697 0.8606060606060606 0.9515151515151515 1.0424242424242425 1.1333333333333333 0.16666666666666666 0.25757575757575757 0.3484848484848485 0.43939393939393934 0.5303030303030303 0.6212121212121212 0.712121212121212 0.803030303030303 0.8939393939393939 0.9848484848484849 1.0757575757575757 1.1666666666666667 0.2 0.2909090909090909 0.38181818181818183 0.4727272727272727 0.5636363636363637 0.6545454545454545 0.7454545454545454 0.8363636363636364 0.9272727272727272 1.0181818181818183 1.1090909090909091 1.2 0.23333333333333334 0.3242424242424242 0.41515151515151516 0.5060606060606061 0.5969696969696969 0.6878787878787879 0.7787878787878788 0.8696969696969696 0.9606060606060607 1.0515151515151515 1.1424242424242423 1.2333333333333334 0.26666666666666666 0.35757575757575755 0.4484848484848485 0.5393939393939393 0.6303030303030304 0.7212121212121212 0.812121212121212 0.9030303030303031 0.9939393939393939 1.084848484848485 1.1757575757575758 1.2666666666666666 0.3 0.3909090909090909 0.4818181818181818 0.5727272727272728 0.6636363636363636 0.7545454545454545 0.8454545454545455 0.9363636363636363 1.0272727272727273 1.1181818181818182 1.209090909090909 1.3 0.3333333333333333 0.4242424242424242 0.5151515151515151 0.606060606060606 0.696969696969697 0.7878787878787878 0.8787878787878787 0.9696969696969697 1.0606060606060606 1.1515151515151516 1.2424242424242424 1.3333333333333333 0.36666666666666664 0.4575757575757575 0.5484848484848485 0.6393939393939394 0.7303030303030302 0.8212121212121212 0.9121212121212121 1.003030303030303 1.093939393939394 1.1848484848484848 1.2757575757575756 1.3666666666666667 0.4 0.49090909090909096 0.5818181818181818 0.6727272727272727 0.7636363636363637 0.8545454545454545 0.9454545454545454 1.0363636363636364 1.1272727272727274 1.2181818181818183 1.309090909090909 1.4 0.43333333333333335 0.5242424242424243 0.6151515151515152 0.706060606060606 0.796969696969697 0.8878787878787879 0.9787878787878788 1.0696969696969698 1.1606060606060606 1.2515151515151515 1.3424242424242423 1.4333333333333333 0.4666666666666667 0.5575757575757576 0.6484848484848484 0.7393939393939394 0.8303030303030303 0.9212121212121211 1.0121212121212122 1.103030303030303 1.1939393939393939 1.284848484848485 1.3757575757575757 1.4666666666666668 0.5 0.5909090909090909 0.6818181818181819 0.7727272727272727 0.8636363636363636 0.9545454545454546 1.0454545454545454 1.1363636363636362 1.2272727272727273 1.3181818181818183 1.4090909090909092 1.5 0.0 0.09090909090909091 0.18181818181818182 0.2727272727272727 0.36363636363636365 0.45454545454545453 0.5454545454545454 0.6363636363636364 0.7272727272727273 0.8181818181818182 0.9090909090909091 1.0 0.03333333333333333 0.12424242424242424 0.21515151515151515 0.30606060606060603 0.396969696969697 0.48787878787878786 0.5787878787878787 0.6696969696969697 0.7606060606060606 0.8515151515151516 0.9424242424242424 1.0333333333333334 0.06666666666666667 0.1575757575757576 0.24848484848484848 0.33939393939393936 0.4303030303030303 0.5212121212121212 0.6121212121212121 0.703030303030303 0.793939393939394 0.8848484848484849 0.9757575757575757 1.0666666666666667 0.1 0.19090909090909092 0.28181818181818186 0.3727272727272727 0.4636363636363636 0.5545454545454546 0.6454545454545454 0.7363636363636363 0.8272727272727273 0.9181818181818182 1.009090909090909 1.1 0.13333333333333333 0.22424242424242424 0.3151515151515152 0.406060606060606 0.49696969696969695 0.5878787878787879 0.6787878787878787 0.7696969696969697 0.8606060606060606 0.9515151515151515 1.0424242424242425 1.1333333333333333 0.16666666666666666 0.25757575757575757 0.3484848484848485 0.43939393939393934 0.5303030303030303 0.6212121212121212 0.712121212121212 0.803030303030303 0.8939393939393939 0.9848484848484849 1.0757575757575757 1.1666666666666667 0.2 0.2909090909090909 0.38181818181818183 0.4727272727272727 0.5636363636363637 0.6545454545454545 0.7454545454545454 0.8363636363636364 0.9272727272727272 1.0181818181818183 1.1090909090909091 1.2 0.23333333333333334 0.3242424242424242 0.41515151515151516 0.5060606060606061 0.5969696969696969 0.6878787878787879 0.7787878787878788 0.8696969696969696 0.9606060606060607 1.0515151515151515 1.1424242424242423 1.2333333333333334 0.26666666666666666 0.35757575757575755 0.4484848484848485 0.5393939393939393 0.6303030303030304 0.7212121212121212 0.812121212121212 0.9030303030303031 0.9939393939393939 1.084848484848485 1.1757575757575758 1.2666666666666666 0.3 0.3909090909090909 0.4818181818181818 0.5727272727272728 0.6636363636363636 0.7545454545454545 0.8454545454545455 0.9363636363636363 1.0272727272727273 1.1181818181818182 1.209090909090909 1.3 0.3333333333333333 0.4242424242424242 0.5151515151515151 0.606060606060606 0.696969696969697 0.7878787878787878 0.8787878787878787 0.9696969696969697 1.0606060606060606 1.1515151515151516 1.2424242424242424 1.3333333333333333 0.36666666666666664 0.4575757575757575 0.5484848484848485 0.6393939393939394 0.7303030303030302 0.8212121212121212 0.9121212121212121 1.003030303030303 1.093939393939394 1.1848484848484848 1.2757575757575756 1.3666666666666667 0.4 0.49090909090909096 0.5818181818181818 0.6727272727272727 0.7636363636363637 0.8545454545454545 0.9454545454545454 1.0363636363636364 1.1272727272727274 1.2181818181818183 1.309090909090909 1.4 0.43333333333333335 0.5242424242424243 0.6151515151515152 0.706060606060606 0.796969696969697 0.8878787878787879 0.9787878787878788 1.0696969696969698 1.1606060606060606 1.2515151515151515 1.3424242424242423 1.4333333333333333 0.4666666666666667 0.5575757575757576 0.6484848484848484 0.7393939393939394 0.8303030303030303 0.9212121212121211 1.0121212121212122 1.103030303030303 1.1939393939393939 1.284848484848485 1.3757575757575757 1.4666666666666668 0.5 0.5909090909090909 0.6818181818181819 0.7727272727272727 0.8636363636363636 0.9545454545454546 1.0454545454545454 1.1363636363636362 1.2272727272727273 1.3181818181818183 1.4090909090909092 1.5 0.0 0.09090909090909091 0.18181818181818182 0.2727272727272727 0.36363636363636365 0.45454545454545453 0.5454545454545454 0.6363636363636364 0.7272727272727273 0.8181818181818182 0.9090909090909091 1.0 0.03333333333333333 0.12424242424242424 0.21515151515151515 0.30606060606060603 0.396969696969697 0.48787878787878786 0.5787878787878787 0.6696969696969697 0.7606060606060606 0.8515151515151516 0.9424242424242424 1.0333333333333334 0.06666666666666667 0.1575757575757576 0.24848484848484848 0.33939393939393936 0.4303030303030303 0.5212121212121212 0.6121212121212121 0.703030303030303 0.793939393939394 0.8848484848484849 0.9757575757575757 1.0666666666666667 0.1 0.19090909090909092 0.28181818181818186 0.3727272727272727 0.4636363636363636 0.5545454545454546 0.6454545454545454 0.7363636363636363 0.8272727272727273 0.9181818181818182 1.009090909090909 1.1 0.13333333333333333 0.22424242424242424 0.3151515151515152 0.406060606060606 0.49696969696969695 0.5878787878787879 0.6787878787878787 0.7696969696969697 0.8606060606060606 0.9515151515151515 1.0424242424242425 1.1333333333333333 0.16666666666666666 0.25757575757575757 0.3484848484848485 0.43939393939393934 0.5303030303030303 0.6212121212121212 0.712121212121212 0.803030303030303 0.8939393939393939 0.9848484848484849 1.0757575757575757 1.1666666666666667 0.2 0.2909090909090909 0.38181818181818183 0.4727272727272727 0.5636363636363637 0.6545454545454545 0.7454545454545454 0.8363636363636364 0.9272727272727272 1.0181818181818183 1.1090909090909091 1.2 0.23333333333333334 0.3242424242424242 0.41515151515151516 0.5060606060606061 0.5969696969696969 0.6878787878787879 0.7787878787878788 0.8696969696969696 0.9606060606060607 1.0515151515151515 1.1424242424242423 1.2333333333333334 0.26666666666666666 0.35757575757575755 0.4484848484848485 0.5393939393939393 0.6303030303030304 0.7212121212121212 0.812121212121212 0.9030303030303031 0.9939393939393939 1.084848484848485 1.1757575757575758 1.2666666666666666 0.3 0.3909090909090909 0.4818181818181818 0.5727272727272728 0.6636363636363636 0.7545454545454545 0.8454545454545455 0.9363636363636363 1.0272727272727273 1.1181818181818182 1.209090909090909 1.3 0.3333333333333333 0.4242424242424242 0.5151515151515151 0.606060606060606 0.696969696969697 0.7878787878787878 0.8787878787878787 0.9696969696969697 1.0606060606060606 1.1515151515151516 1.2424242424242424 1.3333333333333333 0.36666666666666664 0.4575757575757575 0.5484848484848485 0.6393939393939394 0.7303030303030302 0.8212121212121212 0.9121212121212121 1.003030303030303 1.093939393939394 1.1848484848484848 1.2757575757575756 1.3666666666666667 0.4 0.49090909090909096 0.5818181818181818 0.6727272727272727 0.7636363636363637 0.8545454545454545 0.9454545454545454 1.0363636363636364 1.1272727272727274 1.2181818181818183 1.309090909090909 1.4 0.43333333333333335 0.5242424242424243 0.6151515151515152 0.706060606060606 0.796969696969697 0.8878787878787879 0.9787878787878788 1.0696969696969698 1.1606060606060606 1.2515151515151515 1.3424242424242423 1.4333333333333333 0.4666666666666667 0.5575757575757576 0.6484848484848484 0.7393939393939394 0.8303030303030303 0.9212121212121211 1.0121212121212122 1.103030303030303 1.1939393939393939 1.284848484848485 1.3757575757575757 1.4666666666666668 0.5 0.5909090909090909 0.6818181818181819 0.7727272727272727 0.8636363636363636 0.9545454545454546 1.0454545454545454 1.1363636363636362 1.2272727272727273 1.3181818181818183 1.4090909090909092 1.5 0.0 0.09090909090909091 0.18181818181818182 0.2727272727272727 0.36363636363636365 0.45454545454545453 0.5454545454545454 0.6363636363636364 0.7272727272727273 0.8181818181818182 0.9090909090909091 1.0 0.03333333333333333 0.12424242424242424 0.21515151515151515 0.30606060606060603 0.396969696969697 0.48787878787878786 0.5787878787878787 0.6696969696969697 0.7606060606060606 0.8515151515151516 0.9424242424242424 1.0333333333333334 0.06666666666666667 0.1575757575757576 0.24848484848484848 0.33939393939393936 0.4303030303030303 0.5212121212121212 0.6121212121212121 0.703030303030303 0.793939393939394 0.8848484848484849 0.9757575757575757 1.0666666666666667 0.1 0.19090909090909092 0.28181818181818186 0.3727272727272727 0.4636363636363636 0.5545454545454546 0.6454545454545454 0.7363636363636363 0.8272727272727273 0.9181818181818182 1.009090909090909 1.1 0.13333333333333333 0.22424242424242424 0.3151515151515152 0.406060606060606 0.49696969696969695 0.5878787878787879 0.6787878787878787 0.7696969696969697 0.8606060606060606 0.9515151515151515 1.0424242424242425 1.1333333333333333 0.16666666666666666 0.25757575757575757 0.3484848484848485 0.43939393939393934 0.5303030303030303 0.6212121212121212 0.712121212121212 0.803030303030303 0.8939393939393939 0.9848484848484849 1.0757575757575757 1.1666666666666667 0.2 0.2909090909090909 0.38181818181818183 0.4727272727272727 0.5636363636363637 0.6545454545454545 0.7454545454545454 0.8363636363636364 0.9272727272727272 1.0181818181818183 1.1090909090909091 1.2 0.23333333333333334 0.3242424242424242 0.41515151515151516 0.5060606060606061 0.5969696969696969 0.6878787878787879 0.7787878787878788 0.8696969696969696 0.9606060606060607 1.0515151515151515 1.1424242424242423 1.2333333333333334 0.26666666666666666 0.35757575757575755 0.4484848484848485 0.5393939393939393 0.6303030303030304 0.7212121212121212 0.812121212121212 0.9030303030303031 0.9939393939393939 1.084848484848485 1.1757575757575758 1.2666666666666666 0.3 0.3909090909090909 0.4818181818181818 0.5727272727272728 0.6636363636363636 0.7545454545454545 0.8454545454545455 0.9363636363636363 1.0272727272727273 1.1181818181818182 1.209090909090909 1.3 0.3333333333333333 0.4242424242424242 0.5151515151515151 0.606060606060606 0.696969696969697 0.7878787878787878 0.8787878787878787 0.9696969696969697 1.0606060606060606 1.1515151515151516 1.2424242424242424 1.3333333333333333 0.36666666666666664 0.4575757575757575 0.5484848484848485 0.6393939393939394 0.7303030303030302 0.8212121212121212 0.9121212121212121 1.003030303030303 1.093939393939394 1.1848484848484848 1.2757575757575756 1.3666666666666667 0.4 0.49090909090909096 0.5818181818181818 0.6727272727272727 0.7636363636363637 0.8545454545454545 0.9454545454545454 1.0363636363636364 1.1272727272727274 1.2181818181818183 1.309090909090909 1.4 0.43333333333333335 0.5242424242424243 0.6151515151515152 0.706060606060606 0.796969696969697 0.8878787878787879 0.9787878787878788 1.0696969696969698 1.1606060606060606 1.2515151515151515 1.3424242424242423 1.4333333333333333 0.4666666666666667 0.5575757575757576 0.6484848484848484 0.7393939393939394 0.8303030303030303 0.9212121212121211 1.0121212121212122 1.103030303030303 1.1939393939393939 1.284848484848485 1.3757575757575757 1.4666666666666668 0.5 0.5909090909090909 0.6818181818181819 0.7727272727272727 0.8636363636363636 0.9545454545454546 1.0454545454545454 1.1363636363636362 1.2272727272727273 1.3181818181818183 1.4090909090909092 1.5; + 0.0 0.018181818181818184 0.03636363636363637 0.05454545454545454 0.07272727272727274 0.09090909090909091 0.10909090909090909 0.1272727272727273 0.14545454545454548 0.16363636363636366 0.18181818181818182 0.2 0.06666666666666667 0.08484848484848485 0.10303030303030303 0.12121212121212122 0.1393939393939394 0.1575757575757576 0.17575757575757575 0.19393939393939397 0.21212121212121215 0.23030303030303034 0.24848484848484848 0.26666666666666666 0.13333333333333333 0.15151515151515152 0.1696969696969697 0.18787878787878787 0.20606060606060606 0.22424242424242424 0.24242424242424243 0.2606060606060606 0.2787878787878788 0.296969696969697 0.3151515151515152 0.33333333333333337 0.2 0.2181818181818182 0.2363636363636364 0.2545454545454546 0.27272727272727276 0.2909090909090909 0.3090909090909091 0.32727272727272727 0.34545454545454546 0.36363636363636365 0.38181818181818183 0.4 0.26666666666666666 0.28484848484848485 0.30303030303030304 0.3212121212121212 0.3393939393939394 0.35757575757575755 0.37575757575757573 0.3939393939393939 0.4121212121212121 0.4303030303030303 0.4484848484848485 0.4666666666666667 0.3333333333333333 0.3515151515151515 0.3696969696969697 0.3878787878787879 0.40606060606060607 0.4242424242424242 0.4424242424242424 0.4606060606060606 0.47878787878787876 0.49696969696969695 0.5151515151515151 0.5333333333333333 0.4 0.4181818181818182 0.4363636363636364 0.4545454545454546 0.4727272727272728 0.49090909090909096 0.5090909090909091 0.5272727272727273 0.5454545454545455 0.5636363636363637 0.5818181818181818 0.6000000000000001 0.4666666666666667 0.48484848484848486 0.503030303030303 0.5212121212121212 0.5393939393939394 0.5575757575757576 0.5757575757575758 0.593939393939394 0.6121212121212122 0.6303030303030304 0.6484848484848484 0.6666666666666667 0.5333333333333333 0.5515151515151515 0.5696969696969697 0.5878787878787879 0.6060606060606061 0.6242424242424243 0.6424242424242425 0.6606060606060606 0.6787878787878788 0.696969696969697 0.7151515151515151 0.7333333333333334 0.6 0.6181818181818182 0.6363636363636364 0.6545454545454545 0.6727272727272727 0.6909090909090909 0.7090909090909091 0.7272727272727273 0.7454545454545455 0.7636363636363637 0.7818181818181817 0.8 0.6666666666666666 0.6848484848484848 0.703030303030303 0.7212121212121212 0.7393939393939394 0.7575757575757576 0.7757575757575758 0.793939393939394 0.8121212121212121 0.8303030303030303 0.8484848484848484 0.8666666666666667 0.7333333333333333 0.7515151515151515 0.7696969696969697 0.7878787878787878 0.806060606060606 0.8242424242424242 0.8424242424242424 0.8606060606060606 0.8787878787878788 0.896969696969697 0.915151515151515 0.9333333333333333 0.8 0.8181818181818182 0.8363636363636364 0.8545454545454546 0.8727272727272728 0.890909090909091 0.9090909090909092 0.9272727272727274 0.9454545454545455 0.9636363636363637 0.9818181818181819 1.0 0.8666666666666667 0.8848484848484849 0.9030303030303031 0.9212121212121213 0.9393939393939394 0.9575757575757576 0.9757575757575758 0.993939393939394 1.0121212121212122 1.0303030303030303 1.0484848484848486 1.0666666666666667 0.9333333333333333 0.9515151515151515 0.9696969696969697 0.9878787878787879 1.006060606060606 1.0242424242424242 1.0424242424242425 1.0606060606060606 1.0787878787878789 1.096969696969697 1.1151515151515152 1.1333333333333333 1.0 1.018181818181818 1.0363636363636364 1.0545454545454545 1.0727272727272728 1.0909090909090908 1.1090909090909091 1.1272727272727272 1.1454545454545455 1.1636363636363636 1.1818181818181819 1.2 0.0 0.018181818181818184 0.03636363636363637 0.05454545454545454 0.07272727272727274 0.09090909090909091 0.10909090909090909 0.1272727272727273 0.14545454545454548 0.16363636363636366 0.18181818181818182 0.2 0.06666666666666667 0.08484848484848485 0.10303030303030303 0.12121212121212122 0.1393939393939394 0.1575757575757576 0.17575757575757575 0.19393939393939397 0.21212121212121215 0.23030303030303034 0.24848484848484848 0.26666666666666666 0.13333333333333333 0.15151515151515152 0.1696969696969697 0.18787878787878787 0.20606060606060606 0.22424242424242424 0.24242424242424243 0.2606060606060606 0.2787878787878788 0.296969696969697 0.3151515151515152 0.33333333333333337 0.2 0.2181818181818182 0.2363636363636364 0.2545454545454546 0.27272727272727276 0.2909090909090909 0.3090909090909091 0.32727272727272727 0.34545454545454546 0.36363636363636365 0.38181818181818183 0.4 0.26666666666666666 0.28484848484848485 0.30303030303030304 0.3212121212121212 0.3393939393939394 0.35757575757575755 0.37575757575757573 0.3939393939393939 0.4121212121212121 0.4303030303030303 0.4484848484848485 0.4666666666666667 0.3333333333333333 0.3515151515151515 0.3696969696969697 0.3878787878787879 0.40606060606060607 0.4242424242424242 0.4424242424242424 0.4606060606060606 0.47878787878787876 0.49696969696969695 0.5151515151515151 0.5333333333333333 0.4 0.4181818181818182 0.4363636363636364 0.4545454545454546 0.4727272727272728 0.49090909090909096 0.5090909090909091 0.5272727272727273 0.5454545454545455 0.5636363636363637 0.5818181818181818 0.6000000000000001 0.4666666666666667 0.48484848484848486 0.503030303030303 0.5212121212121212 0.5393939393939394 0.5575757575757576 0.5757575757575758 0.593939393939394 0.6121212121212122 0.6303030303030304 0.6484848484848484 0.6666666666666667 0.5333333333333333 0.5515151515151515 0.5696969696969697 0.5878787878787879 0.6060606060606061 0.6242424242424243 0.6424242424242425 0.6606060606060606 0.6787878787878788 0.696969696969697 0.7151515151515151 0.7333333333333334 0.6 0.6181818181818182 0.6363636363636364 0.6545454545454545 0.6727272727272727 0.6909090909090909 0.7090909090909091 0.7272727272727273 0.7454545454545455 0.7636363636363637 0.7818181818181817 0.8 0.6666666666666666 0.6848484848484848 0.703030303030303 0.7212121212121212 0.7393939393939394 0.7575757575757576 0.7757575757575758 0.793939393939394 0.8121212121212121 0.8303030303030303 0.8484848484848484 0.8666666666666667 0.7333333333333333 0.7515151515151515 0.7696969696969697 0.7878787878787878 0.806060606060606 0.8242424242424242 0.8424242424242424 0.8606060606060606 0.8787878787878788 0.896969696969697 0.915151515151515 0.9333333333333333 0.8 0.8181818181818182 0.8363636363636364 0.8545454545454546 0.8727272727272728 0.890909090909091 0.9090909090909092 0.9272727272727274 0.9454545454545455 0.9636363636363637 0.9818181818181819 1.0 0.8666666666666667 0.8848484848484849 0.9030303030303031 0.9212121212121213 0.9393939393939394 0.9575757575757576 0.9757575757575758 0.993939393939394 1.0121212121212122 1.0303030303030303 1.0484848484848486 1.0666666666666667 0.9333333333333333 0.9515151515151515 0.9696969696969697 0.9878787878787879 1.006060606060606 1.0242424242424242 1.0424242424242425 1.0606060606060606 1.0787878787878789 1.096969696969697 1.1151515151515152 1.1333333333333333 1.0 1.018181818181818 1.0363636363636364 1.0545454545454545 1.0727272727272728 1.0909090909090908 1.1090909090909091 1.1272727272727272 1.1454545454545455 1.1636363636363636 1.1818181818181819 1.2 0.0 0.018181818181818184 0.03636363636363637 0.05454545454545454 0.07272727272727274 0.09090909090909091 0.10909090909090909 0.1272727272727273 0.14545454545454548 0.16363636363636366 0.18181818181818182 0.2 0.06666666666666667 0.08484848484848485 0.10303030303030303 0.12121212121212122 0.1393939393939394 0.1575757575757576 0.17575757575757575 0.19393939393939397 0.21212121212121215 0.23030303030303034 0.24848484848484848 0.26666666666666666 0.13333333333333333 0.15151515151515152 0.1696969696969697 0.18787878787878787 0.20606060606060606 0.22424242424242424 0.24242424242424243 0.2606060606060606 0.2787878787878788 0.296969696969697 0.3151515151515152 0.33333333333333337 0.2 0.2181818181818182 0.2363636363636364 0.2545454545454546 0.27272727272727276 0.2909090909090909 0.3090909090909091 0.32727272727272727 0.34545454545454546 0.36363636363636365 0.38181818181818183 0.4 0.26666666666666666 0.28484848484848485 0.30303030303030304 0.3212121212121212 0.3393939393939394 0.35757575757575755 0.37575757575757573 0.3939393939393939 0.4121212121212121 0.4303030303030303 0.4484848484848485 0.4666666666666667 0.3333333333333333 0.3515151515151515 0.3696969696969697 0.3878787878787879 0.40606060606060607 0.4242424242424242 0.4424242424242424 0.4606060606060606 0.47878787878787876 0.49696969696969695 0.5151515151515151 0.5333333333333333 0.4 0.4181818181818182 0.4363636363636364 0.4545454545454546 0.4727272727272728 0.49090909090909096 0.5090909090909091 0.5272727272727273 0.5454545454545455 0.5636363636363637 0.5818181818181818 0.6000000000000001 0.4666666666666667 0.48484848484848486 0.503030303030303 0.5212121212121212 0.5393939393939394 0.5575757575757576 0.5757575757575758 0.593939393939394 0.6121212121212122 0.6303030303030304 0.6484848484848484 0.6666666666666667 0.5333333333333333 0.5515151515151515 0.5696969696969697 0.5878787878787879 0.6060606060606061 0.6242424242424243 0.6424242424242425 0.6606060606060606 0.6787878787878788 0.696969696969697 0.7151515151515151 0.7333333333333334 0.6 0.6181818181818182 0.6363636363636364 0.6545454545454545 0.6727272727272727 0.6909090909090909 0.7090909090909091 0.7272727272727273 0.7454545454545455 0.7636363636363637 0.7818181818181817 0.8 0.6666666666666666 0.6848484848484848 0.703030303030303 0.7212121212121212 0.7393939393939394 0.7575757575757576 0.7757575757575758 0.793939393939394 0.8121212121212121 0.8303030303030303 0.8484848484848484 0.8666666666666667 0.7333333333333333 0.7515151515151515 0.7696969696969697 0.7878787878787878 0.806060606060606 0.8242424242424242 0.8424242424242424 0.8606060606060606 0.8787878787878788 0.896969696969697 0.915151515151515 0.9333333333333333 0.8 0.8181818181818182 0.8363636363636364 0.8545454545454546 0.8727272727272728 0.890909090909091 0.9090909090909092 0.9272727272727274 0.9454545454545455 0.9636363636363637 0.9818181818181819 1.0 0.8666666666666667 0.8848484848484849 0.9030303030303031 0.9212121212121213 0.9393939393939394 0.9575757575757576 0.9757575757575758 0.993939393939394 1.0121212121212122 1.0303030303030303 1.0484848484848486 1.0666666666666667 0.9333333333333333 0.9515151515151515 0.9696969696969697 0.9878787878787879 1.006060606060606 1.0242424242424242 1.0424242424242425 1.0606060606060606 1.0787878787878789 1.096969696969697 1.1151515151515152 1.1333333333333333 1.0 1.018181818181818 1.0363636363636364 1.0545454545454545 1.0727272727272728 1.0909090909090908 1.1090909090909091 1.1272727272727272 1.1454545454545455 1.1636363636363636 1.1818181818181819 1.2 0.0 0.018181818181818184 0.03636363636363637 0.05454545454545454 0.07272727272727274 0.09090909090909091 0.10909090909090909 0.1272727272727273 0.14545454545454548 0.16363636363636366 0.18181818181818182 0.2 0.06666666666666667 0.08484848484848485 0.10303030303030303 0.12121212121212122 0.1393939393939394 0.1575757575757576 0.17575757575757575 0.19393939393939397 0.21212121212121215 0.23030303030303034 0.24848484848484848 0.26666666666666666 0.13333333333333333 0.15151515151515152 0.1696969696969697 0.18787878787878787 0.20606060606060606 0.22424242424242424 0.24242424242424243 0.2606060606060606 0.2787878787878788 0.296969696969697 0.3151515151515152 0.33333333333333337 0.2 0.2181818181818182 0.2363636363636364 0.2545454545454546 0.27272727272727276 0.2909090909090909 0.3090909090909091 0.32727272727272727 0.34545454545454546 0.36363636363636365 0.38181818181818183 0.4 0.26666666666666666 0.28484848484848485 0.30303030303030304 0.3212121212121212 0.3393939393939394 0.35757575757575755 0.37575757575757573 0.3939393939393939 0.4121212121212121 0.4303030303030303 0.4484848484848485 0.4666666666666667 0.3333333333333333 0.3515151515151515 0.3696969696969697 0.3878787878787879 0.40606060606060607 0.4242424242424242 0.4424242424242424 0.4606060606060606 0.47878787878787876 0.49696969696969695 0.5151515151515151 0.5333333333333333 0.4 0.4181818181818182 0.4363636363636364 0.4545454545454546 0.4727272727272728 0.49090909090909096 0.5090909090909091 0.5272727272727273 0.5454545454545455 0.5636363636363637 0.5818181818181818 0.6000000000000001 0.4666666666666667 0.48484848484848486 0.503030303030303 0.5212121212121212 0.5393939393939394 0.5575757575757576 0.5757575757575758 0.593939393939394 0.6121212121212122 0.6303030303030304 0.6484848484848484 0.6666666666666667 0.5333333333333333 0.5515151515151515 0.5696969696969697 0.5878787878787879 0.6060606060606061 0.6242424242424243 0.6424242424242425 0.6606060606060606 0.6787878787878788 0.696969696969697 0.7151515151515151 0.7333333333333334 0.6 0.6181818181818182 0.6363636363636364 0.6545454545454545 0.6727272727272727 0.6909090909090909 0.7090909090909091 0.7272727272727273 0.7454545454545455 0.7636363636363637 0.7818181818181817 0.8 0.6666666666666666 0.6848484848484848 0.703030303030303 0.7212121212121212 0.7393939393939394 0.7575757575757576 0.7757575757575758 0.793939393939394 0.8121212121212121 0.8303030303030303 0.8484848484848484 0.8666666666666667 0.7333333333333333 0.7515151515151515 0.7696969696969697 0.7878787878787878 0.806060606060606 0.8242424242424242 0.8424242424242424 0.8606060606060606 0.8787878787878788 0.896969696969697 0.915151515151515 0.9333333333333333 0.8 0.8181818181818182 0.8363636363636364 0.8545454545454546 0.8727272727272728 0.890909090909091 0.9090909090909092 0.9272727272727274 0.9454545454545455 0.9636363636363637 0.9818181818181819 1.0 0.8666666666666667 0.8848484848484849 0.9030303030303031 0.9212121212121213 0.9393939393939394 0.9575757575757576 0.9757575757575758 0.993939393939394 1.0121212121212122 1.0303030303030303 1.0484848484848486 1.0666666666666667 0.9333333333333333 0.9515151515151515 0.9696969696969697 0.9878787878787879 1.006060606060606 1.0242424242424242 1.0424242424242425 1.0606060606060606 1.0787878787878789 1.096969696969697 1.1151515151515152 1.1333333333333333 1.0 1.018181818181818 1.0363636363636364 1.0545454545454545 1.0727272727272728 1.0909090909090908 1.1090909090909091 1.1272727272727272 1.1454545454545455 1.1636363636363636 1.1818181818181819 1.2; + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.06666666666666667 0.06666666666666667 0.06666666666666667 0.06666666666666667 0.06666666666666667 0.06666666666666667 0.06666666666666667 0.06666666666666667 0.06666666666666667 0.06666666666666667 0.06666666666666667 0.06666666666666667 0.13333333333333333 0.13333333333333333 0.13333333333333333 0.13333333333333333 0.13333333333333333 0.13333333333333333 0.13333333333333333 0.13333333333333333 0.13333333333333333 0.13333333333333333 0.13333333333333333 0.13333333333333333 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.26666666666666666 0.26666666666666666 0.26666666666666666 0.26666666666666666 0.26666666666666666 0.26666666666666666 0.26666666666666666 0.26666666666666666 0.26666666666666666 0.26666666666666666 0.26666666666666666 0.26666666666666666 0.3333333333333333 0.3333333333333333 0.3333333333333333 0.3333333333333333 0.3333333333333333 0.3333333333333333 0.3333333333333333 0.3333333333333333 0.3333333333333333 0.3333333333333333 0.3333333333333333 0.3333333333333333 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4666666666666667 0.4666666666666667 0.4666666666666667 0.4666666666666667 0.4666666666666667 0.4666666666666667 0.4666666666666667 0.4666666666666667 0.4666666666666667 0.4666666666666667 0.4666666666666667 0.4666666666666667 0.5333333333333333 0.5333333333333333 0.5333333333333333 0.5333333333333333 0.5333333333333333 0.5333333333333333 0.5333333333333333 0.5333333333333333 0.5333333333333333 0.5333333333333333 0.5333333333333333 0.5333333333333333 0.6 0.6 0.6 0.6 0.6 0.6 0.6 0.6 0.6 0.6 0.6 0.6 0.6666666666666666 0.6666666666666666 0.6666666666666666 0.6666666666666666 0.6666666666666666 0.6666666666666666 0.6666666666666666 0.6666666666666666 0.6666666666666666 0.6666666666666666 0.6666666666666666 0.6666666666666666 0.7333333333333333 0.7333333333333333 0.7333333333333333 0.7333333333333333 0.7333333333333333 0.7333333333333333 0.7333333333333333 0.7333333333333333 0.7333333333333333 0.7333333333333333 0.7333333333333333 0.7333333333333333 0.8 0.8 0.8 0.8 0.8 0.8 0.8 0.8 0.8 0.8 0.8 0.8 0.8666666666666667 0.8666666666666667 0.8666666666666667 0.8666666666666667 0.8666666666666667 0.8666666666666667 0.8666666666666667 0.8666666666666667 0.8666666666666667 0.8666666666666667 0.8666666666666667 0.8666666666666667 0.9333333333333333 0.9333333333333333 0.9333333333333333 0.9333333333333333 0.9333333333333333 0.9333333333333333 0.9333333333333333 0.9333333333333333 0.9333333333333333 0.9333333333333333 0.9333333333333333 0.9333333333333333 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.16666666666666669 0.16666666666666669 0.16666666666666669 0.16666666666666669 0.16666666666666669 0.16666666666666669 0.16666666666666669 0.16666666666666669 0.16666666666666669 0.16666666666666669 0.16666666666666669 0.16666666666666669 0.23333333333333334 0.23333333333333334 0.23333333333333334 0.23333333333333334 0.23333333333333334 0.23333333333333334 0.23333333333333334 0.23333333333333334 0.23333333333333334 0.23333333333333334 0.23333333333333334 0.23333333333333334 0.30000000000000004 0.30000000000000004 0.30000000000000004 0.30000000000000004 0.30000000000000004 0.30000000000000004 0.30000000000000004 0.30000000000000004 0.30000000000000004 0.30000000000000004 0.30000000000000004 0.30000000000000004 0.3666666666666667 0.3666666666666667 0.3666666666666667 0.3666666666666667 0.3666666666666667 0.3666666666666667 0.3666666666666667 0.3666666666666667 0.3666666666666667 0.3666666666666667 0.3666666666666667 0.3666666666666667 0.43333333333333335 0.43333333333333335 0.43333333333333335 0.43333333333333335 0.43333333333333335 0.43333333333333335 0.43333333333333335 0.43333333333333335 0.43333333333333335 0.43333333333333335 0.43333333333333335 0.43333333333333335 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5666666666666667 0.5666666666666667 0.5666666666666667 0.5666666666666667 0.5666666666666667 0.5666666666666667 0.5666666666666667 0.5666666666666667 0.5666666666666667 0.5666666666666667 0.5666666666666667 0.5666666666666667 0.6333333333333333 0.6333333333333333 0.6333333333333333 0.6333333333333333 0.6333333333333333 0.6333333333333333 0.6333333333333333 0.6333333333333333 0.6333333333333333 0.6333333333333333 0.6333333333333333 0.6333333333333333 0.7 0.7 0.7 0.7 0.7 0.7 0.7 0.7 0.7 0.7 0.7 0.7 0.7666666666666666 0.7666666666666666 0.7666666666666666 0.7666666666666666 0.7666666666666666 0.7666666666666666 0.7666666666666666 0.7666666666666666 0.7666666666666666 0.7666666666666666 0.7666666666666666 0.7666666666666666 0.8333333333333333 0.8333333333333333 0.8333333333333333 0.8333333333333333 0.8333333333333333 0.8333333333333333 0.8333333333333333 0.8333333333333333 0.8333333333333333 0.8333333333333333 0.8333333333333333 0.8333333333333333 0.9 0.9 0.9 0.9 0.9 0.9 0.9 0.9 0.9 0.9 0.9 0.9 0.9666666666666667 0.9666666666666667 0.9666666666666667 0.9666666666666667 0.9666666666666667 0.9666666666666667 0.9666666666666667 0.9666666666666667 0.9666666666666667 0.9666666666666667 0.9666666666666667 0.9666666666666667 1.0333333333333334 1.0333333333333334 1.0333333333333334 1.0333333333333334 1.0333333333333334 1.0333333333333334 1.0333333333333334 1.0333333333333334 1.0333333333333334 1.0333333333333334 1.0333333333333334 1.0333333333333334 1.1 1.1 1.1 1.1 1.1 1.1 1.1 1.1 1.1 1.1 1.1 1.1 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.26666666666666666 0.26666666666666666 0.26666666666666666 0.26666666666666666 0.26666666666666666 0.26666666666666666 0.26666666666666666 0.26666666666666666 0.26666666666666666 0.26666666666666666 0.26666666666666666 0.26666666666666666 0.33333333333333337 0.33333333333333337 0.33333333333333337 0.33333333333333337 0.33333333333333337 0.33333333333333337 0.33333333333333337 0.33333333333333337 0.33333333333333337 0.33333333333333337 0.33333333333333337 0.33333333333333337 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4666666666666667 0.4666666666666667 0.4666666666666667 0.4666666666666667 0.4666666666666667 0.4666666666666667 0.4666666666666667 0.4666666666666667 0.4666666666666667 0.4666666666666667 0.4666666666666667 0.4666666666666667 0.5333333333333333 0.5333333333333333 0.5333333333333333 0.5333333333333333 0.5333333333333333 0.5333333333333333 0.5333333333333333 0.5333333333333333 0.5333333333333333 0.5333333333333333 0.5333333333333333 0.5333333333333333 0.6000000000000001 0.6000000000000001 0.6000000000000001 0.6000000000000001 0.6000000000000001 0.6000000000000001 0.6000000000000001 0.6000000000000001 0.6000000000000001 0.6000000000000001 0.6000000000000001 0.6000000000000001 0.6666666666666667 0.6666666666666667 0.6666666666666667 0.6666666666666667 0.6666666666666667 0.6666666666666667 0.6666666666666667 0.6666666666666667 0.6666666666666667 0.6666666666666667 0.6666666666666667 0.6666666666666667 0.7333333333333334 0.7333333333333334 0.7333333333333334 0.7333333333333334 0.7333333333333334 0.7333333333333334 0.7333333333333334 0.7333333333333334 0.7333333333333334 0.7333333333333334 0.7333333333333334 0.7333333333333334 0.8 0.8 0.8 0.8 0.8 0.8 0.8 0.8 0.8 0.8 0.8 0.8 0.8666666666666667 0.8666666666666667 0.8666666666666667 0.8666666666666667 0.8666666666666667 0.8666666666666667 0.8666666666666667 0.8666666666666667 0.8666666666666667 0.8666666666666667 0.8666666666666667 0.8666666666666667 0.9333333333333333 0.9333333333333333 0.9333333333333333 0.9333333333333333 0.9333333333333333 0.9333333333333333 0.9333333333333333 0.9333333333333333 0.9333333333333333 0.9333333333333333 0.9333333333333333 0.9333333333333333 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0666666666666667 1.0666666666666667 1.0666666666666667 1.0666666666666667 1.0666666666666667 1.0666666666666667 1.0666666666666667 1.0666666666666667 1.0666666666666667 1.0666666666666667 1.0666666666666667 1.0666666666666667 1.1333333333333333 1.1333333333333333 1.1333333333333333 1.1333333333333333 1.1333333333333333 1.1333333333333333 1.1333333333333333 1.1333333333333333 1.1333333333333333 1.1333333333333333 1.1333333333333333 1.1333333333333333 1.2 1.2 1.2 1.2 1.2 1.2 1.2 1.2 1.2 1.2 1.2 1.2 0.30000000000000004 0.30000000000000004 0.30000000000000004 0.30000000000000004 0.30000000000000004 0.30000000000000004 0.30000000000000004 0.30000000000000004 0.30000000000000004 0.30000000000000004 0.30000000000000004 0.30000000000000004 0.3666666666666667 0.3666666666666667 0.3666666666666667 0.3666666666666667 0.3666666666666667 0.3666666666666667 0.3666666666666667 0.3666666666666667 0.3666666666666667 0.3666666666666667 0.3666666666666667 0.3666666666666667 0.43333333333333335 0.43333333333333335 0.43333333333333335 0.43333333333333335 0.43333333333333335 0.43333333333333335 0.43333333333333335 0.43333333333333335 0.43333333333333335 0.43333333333333335 0.43333333333333335 0.43333333333333335 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5666666666666667 0.5666666666666667 0.5666666666666667 0.5666666666666667 0.5666666666666667 0.5666666666666667 0.5666666666666667 0.5666666666666667 0.5666666666666667 0.5666666666666667 0.5666666666666667 0.5666666666666667 0.6333333333333333 0.6333333333333333 0.6333333333333333 0.6333333333333333 0.6333333333333333 0.6333333333333333 0.6333333333333333 0.6333333333333333 0.6333333333333333 0.6333333333333333 0.6333333333333333 0.6333333333333333 0.7000000000000001 0.7000000000000001 0.7000000000000001 0.7000000000000001 0.7000000000000001 0.7000000000000001 0.7000000000000001 0.7000000000000001 0.7000000000000001 0.7000000000000001 0.7000000000000001 0.7000000000000001 0.7666666666666667 0.7666666666666667 0.7666666666666667 0.7666666666666667 0.7666666666666667 0.7666666666666667 0.7666666666666667 0.7666666666666667 0.7666666666666667 0.7666666666666667 0.7666666666666667 0.7666666666666667 0.8333333333333334 0.8333333333333334 0.8333333333333334 0.8333333333333334 0.8333333333333334 0.8333333333333334 0.8333333333333334 0.8333333333333334 0.8333333333333334 0.8333333333333334 0.8333333333333334 0.8333333333333334 0.9 0.9 0.9 0.9 0.9 0.9 0.9 0.9 0.9 0.9 0.9 0.9 0.9666666666666667 0.9666666666666667 0.9666666666666667 0.9666666666666667 0.9666666666666667 0.9666666666666667 0.9666666666666667 0.9666666666666667 0.9666666666666667 0.9666666666666667 0.9666666666666667 0.9666666666666667 1.0333333333333332 1.0333333333333332 1.0333333333333332 1.0333333333333332 1.0333333333333332 1.0333333333333332 1.0333333333333332 1.0333333333333332 1.0333333333333332 1.0333333333333332 1.0333333333333332 1.0333333333333332 1.1 1.1 1.1 1.1 1.1 1.1 1.1 1.1 1.1 1.1 1.1 1.1 1.1666666666666667 1.1666666666666667 1.1666666666666667 1.1666666666666667 1.1666666666666667 1.1666666666666667 1.1666666666666667 1.1666666666666667 1.1666666666666667 1.1666666666666667 1.1666666666666667 1.1666666666666667 1.2333333333333334 1.2333333333333334 1.2333333333333334 1.2333333333333334 1.2333333333333334 1.2333333333333334 1.2333333333333334 1.2333333333333334 1.2333333333333334 1.2333333333333334 1.2333333333333334 1.2333333333333334 1.3 1.3 1.3 1.3 1.3 1.3 1.3 1.3 1.3 1.3 1.3 1.3] + + shape = ExtrudeGeometry((p1, p2, p3); direction, particle_spacing=0.1, n_extrude=3, + density=1000.0) + + @test shape.coordinates == expected_coords + end +end diff --git a/test/setups/setups.jl b/test/setups/setups.jl index eaffd6761..0a72c9410 100644 --- a/test/setups/setups.jl +++ b/test/setups/setups.jl @@ -1,3 +1,4 @@ include("rectangular_shape.jl") include("sphere_shape.jl") include("rectangular_tank.jl") +include("extrude_geometry.jl") From 4fe0358c0a024e613c000ed05e2a5d5af6be2655 Mon Sep 17 00:00:00 2001 From: LasNikas Date: Wed, 7 Feb 2024 19:57:47 +0100 Subject: [PATCH 005/107] fix bug --- src/setups/extrude_geometry.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/setups/extrude_geometry.jl b/src/setups/extrude_geometry.jl index f2eb95518..4b3fa6065 100644 --- a/src/setups/extrude_geometry.jl +++ b/src/setups/extrude_geometry.jl @@ -74,7 +74,7 @@ function ExtrudeGeometry(geometry; particle_spacing, direction, n_extrude=0, coordinates = reshape(stack(coords), (NDIMS, size(face_coords, 2) * (n_extrude + 1))) return InitialCondition(; coordinates, velocity, density, mass, pressure, - particle_spacing) + particle_spacing_) end function sample_plane(geometry::AbstractMatrix, particle_spacing) From c8e08f4a4a544fc8403adb80be4d99a8d065ea1a Mon Sep 17 00:00:00 2001 From: LasNikas Date: Wed, 7 Feb 2024 20:28:55 +0100 Subject: [PATCH 006/107] create `OpenBoundarySPHSystem` --- src/schemes/boundary/open_boundary/system.jl | 124 ++++++++++++++++++ src/schemes/boundary/system.jl | 4 +- .../fluid/entropically_damped_sph/rhs.jl | 2 +- src/schemes/fluid/fluid.jl | 2 +- .../fluid/weakly_compressible_sph/rhs.jl | 2 +- .../solid/total_lagrangian_sph/system.jl | 4 +- 6 files changed, 131 insertions(+), 7 deletions(-) create mode 100644 src/schemes/boundary/open_boundary/system.jl diff --git a/src/schemes/boundary/open_boundary/system.jl b/src/schemes/boundary/open_boundary/system.jl new file mode 100644 index 000000000..51c529bb6 --- /dev/null +++ b/src/schemes/boundary/open_boundary/system.jl @@ -0,0 +1,124 @@ +struct OpenBoundarySPHSystem{BZ, NDIMS, ELTYPE <: Real, S, B, VF} <: FluidSystem{NDIMS} + initial_condition :: InitialCondition{ELTYPE} + mass :: Array{ELTYPE, 1} # [particle] + density :: Array{ELTYPE, 1} # [particle] + volume :: Array{ELTYPE, 1} # [particle] + pressure :: Array{ELTYPE, 1} # [particle] + characteristics :: Array{ELTYPE, 2} # [characteristics, particle] + previous_characteristics :: Array{ELTYPE, 2} # [characteristics, particle] + sound_speed :: ELTYPE + boundary_zone :: BZ + flow_direction :: SVector{NDIMS, ELTYPE} + zone_origin :: SVector{NDIMS, ELTYPE} + spanning_set :: S + velocity_function :: VF + + function OpenBoundarySPHSystem(plane_points, boundary_zone, sound_speed; + sample_geometry=plane_points, + particle_spacing, velocity=0.0, mass=nothing, + density=nothing, pressure=0.0, open_boundary_layers=0, + flow_direction=nothing, velocity_function=nothing) + if flow_direction === nothing + throw(ArgumentError("Please specify a flow direction.")) + end + + if !isa(open_boundary_layers, Int) + throw(ArgumentError("`open_boundary_layers` must be of type Int")) + elseif open_boundary_layers < sqrt(eps()) + throw(ArgumentError("`open_boundary_layers` must be positive and greater than zero")) + end + + # Unit vector pointing in downstream direction. + flow_direction_ = normalize(SVector(flow_direction...)) + + # Sample boundary zone with particles in corresponding direction. + (boundary_zone isa OutFlow) && (direction = flow_direction_) + (boundary_zone isa InFlow) && (direction = -flow_direction_) + + # Sample particles in boundary zone. + initial_condition = ExtrudeGeometry(sample_geometry; particle_spacing, direction, + n_extrude=open_boundary_layers, velocity, mass, + density, pressure) + + # Particles are sampled with `0.5particle_spacing` away from zone plane + zone_width = (open_boundary_layers + 1) * initial_condition.particle_spacing + initial_condition.coordinates .+= 0.5initial_condition.particle_spacing .* direction + + NDIMS = ndims(initial_condition) + ELTYPE = eltype(initial_condition) + + # Vectors spanning the boundary zone/box. + spanning_set = spanning_vectors(plane_points, zone_width) + + # First vector of `spanning_vectors` is normal to the in-/outflow plane. + # The normal vector must point in downstream direction for an outflow boundary and + # for an inflow boundary the normal vector must point in upstream direction. + # Thus, rotate the normal vector correspondingly. + if isapprox(dot(normalize(spanning_set[:, 1]), flow_direction_), 1.0, atol=1e-7) + # Normal vector points in downstream direction. + # Flip the inflow vector in upstream direction + (boundary_zone isa InFlow) && (spanning_set[:, 1] .*= -1) + elseif isapprox(dot(normalize(spanning_set[:, 1]), flow_direction_), -1.0, + atol=1e-7) + # Normal vector points in upstream direction. + # Flip the outflow vector in downstream direction + (boundary_zone isa OutFlow) && (spanning_set[:, 1] .*= -1) + else + throw(ArgumentError("Flow direction and normal vector of " * + "$(typeof(boundary_zone))-plane do not correspond.")) + end + + spanning_set_ = reinterpret(reshape, SVector{NDIMS, ELTYPE}, spanning_set) + + zone_origin = SVector(plane_points[1]...) + + characteristics = zeros(ELTYPE, 3, length(mass)) + previous_characteristics = zeros(ELTYPE, 4, length(mass)) + + mass = copy(initial_condition.mass) + pressure = copy(initial_condition.pressure) + density = copy(initial_condition.density) + volume = similar(initial_condition.density) + + return new{typeof(boundary_zone), NDIMS, ELTYPE, typeof(spanning_set_), + typeof(buffer), + typeof(velocity_function)}(initial_condition, mass, density, volume, + pressure, characteristics, + previous_characteristics, sound_speed, + boundary_zone, flow_direction_, zone_origin, + spanning_set_, buffer, velocity_function) + end +end + +@inline viscosity_model(system, neighbor_system::OpenBoundarySPHSystem) = system.viscosity + +function spanning_vectors(plane_points, zone_width) + + # Convert to tuple + return spanning_vectors(tuple(plane_points...), zone_width) +end + +spanning_vectors(plane_points::NTuple{1}, zone_width) = [-zone_width] + +function spanning_vectors(plane_points::NTuple{2}, zone_width) + plane_size = plane_points[2] - plane_points[1] + # Calculate normal vector of plane + b = Vector(normalize([-plane_size[2]; plane_size[1]]) * zone_width) + + return hcat(b, plane_size) +end + +function spanning_vectors(plane_points::NTuple{3}, zone_width) + # Vectors spanning the plane + edge1 = plane_points[2] - plane_points[1] + edge2 = plane_points[3] - plane_points[1] + + if !isapprox(dot(edge1, edge2), 0.0, atol=1e-7) + throw(ArgumentError("the provided points do not span a rectangular plane")) + end + + # Calculate normal vector of plane + c = Vector(normalize(cross(edge2, edge1)) * zone_width) + + return hcat(c, edge1, edge2) +end diff --git a/src/schemes/boundary/system.jl b/src/schemes/boundary/system.jl index ef5670558..504bd1944 100644 --- a/src/schemes/boundary/system.jl +++ b/src/schemes/boundary/system.jl @@ -261,6 +261,6 @@ function restart_with!(system::BoundarySPHSystem{<:BoundaryModelDummyParticles{C return system end -function viscosity_model(system::BoundarySPHSystem) - return system.boundary_model.viscosity +function viscosity_model(system, neighbor_system::BoundarySPHSystem) + return neighbor_system.boundary_model.viscosity end diff --git a/src/schemes/fluid/entropically_damped_sph/rhs.jl b/src/schemes/fluid/entropically_damped_sph/rhs.jl index aac412dc1..f0a74898d 100644 --- a/src/schemes/fluid/entropically_damped_sph/rhs.jl +++ b/src/schemes/fluid/entropically_damped_sph/rhs.jl @@ -4,7 +4,7 @@ function interact!(dv, v_particle_system, u_particle_system, particle_system::EntropicallyDampedSPHSystem, neighbor_system) (; sound_speed) = particle_system - viscosity = viscosity_model(neighbor_system) + viscosity = viscosity_model(particle_system, neighbor_system) system_coords = current_coordinates(u_particle_system, particle_system) neighbor_coords = current_coordinates(u_neighbor_system, neighbor_system) diff --git a/src/schemes/fluid/fluid.jl b/src/schemes/fluid/fluid.jl index 51eb4bebd..539af19af 100644 --- a/src/schemes/fluid/fluid.jl +++ b/src/schemes/fluid/fluid.jl @@ -13,7 +13,7 @@ function write_u0!(u0, system::FluidSystem) return u0 end -@inline viscosity_model(system::FluidSystem) = system.viscosity +@inline viscosity_model(system, neighbor_system::FluidSystem) = neighbor_system.viscosity include("pressure_acceleration.jl") include("viscosity.jl") diff --git a/src/schemes/fluid/weakly_compressible_sph/rhs.jl b/src/schemes/fluid/weakly_compressible_sph/rhs.jl index 29246d2c1..1785547db 100644 --- a/src/schemes/fluid/weakly_compressible_sph/rhs.jl +++ b/src/schemes/fluid/weakly_compressible_sph/rhs.jl @@ -9,7 +9,7 @@ function interact!(dv, v_particle_system, u_particle_system, (; density_calculator, state_equation, correction) = particle_system (; sound_speed) = state_equation - viscosity = viscosity_model(neighbor_system) + viscosity = viscosity_model(particle_system, neighbor_system) system_coords = current_coordinates(u_particle_system, particle_system) neighbor_system_coords = current_coordinates(u_neighbor_system, neighbor_system) diff --git a/src/schemes/solid/total_lagrangian_sph/system.jl b/src/schemes/solid/total_lagrangian_sph/system.jl index 43f87215f..eac6177e3 100644 --- a/src/schemes/solid/total_lagrangian_sph/system.jl +++ b/src/schemes/solid/total_lagrangian_sph/system.jl @@ -408,8 +408,8 @@ function restart_with!(system::TotalLagrangianSPHSystem, v, u) restart_with!(system, system.boundary_model, v, u) end -function viscosity_model(system::TotalLagrangianSPHSystem) - return system.boundary_model.viscosity +function viscosity_model(system, neighbor_system::TotalLagrangianSPHSystem) + return neighbor_system.boundary_model.viscosity end # An explanation of these equation can be found in From c9156636e47498fb638ef2cc142af00b759a485f Mon Sep 17 00:00:00 2001 From: LasNikas Date: Thu, 8 Feb 2024 11:27:42 +0100 Subject: [PATCH 007/107] export OpenBoundarySPHSystem --- src/TrixiParticles.jl | 2 +- src/schemes/boundary/boundary.jl | 1 + src/schemes/boundary/open_boundary/system.jl | 10 +++++++--- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/TrixiParticles.jl b/src/TrixiParticles.jl index 704a66ab3..296f78a48 100644 --- a/src/TrixiParticles.jl +++ b/src/TrixiParticles.jl @@ -37,7 +37,7 @@ include("visualization/write2vtk.jl") export Semidiscretization, semidiscretize, restart_with! export InitialCondition export WeaklyCompressibleSPHSystem, EntropicallyDampedSPHSystem, TotalLagrangianSPHSystem, - BoundarySPHSystem + BoundarySPHSystem, OpenBoundarySPHSystem, InFlow, OutFlow export InfoCallback, SolutionSavingCallback, DensityReinitializationCallback export ContinuityDensity, SummationDensity export PenaltyForceGanzenmueller diff --git a/src/schemes/boundary/boundary.jl b/src/schemes/boundary/boundary.jl index 25d9dfb93..6ce7b6677 100644 --- a/src/schemes/boundary/boundary.jl +++ b/src/schemes/boundary/boundary.jl @@ -1,4 +1,5 @@ include("dummy_particles/dummy_particles.jl") +include("open_boundary/system.jl") include("system.jl") # Monaghan-Kajtar repulsive boundary particles require the `BoundarySPHSystem` # and the `TotalLagrangianSPHSystem` and are therefore included later. diff --git a/src/schemes/boundary/open_boundary/system.jl b/src/schemes/boundary/open_boundary/system.jl index 51c529bb6..5bddf3451 100644 --- a/src/schemes/boundary/open_boundary/system.jl +++ b/src/schemes/boundary/open_boundary/system.jl @@ -1,3 +1,7 @@ +struct InFlow end + +struct OutFlow end + struct OpenBoundarySPHSystem{BZ, NDIMS, ELTYPE <: Real, S, B, VF} <: FluidSystem{NDIMS} initial_condition :: InitialCondition{ELTYPE} mass :: Array{ELTYPE, 1} # [particle] @@ -15,9 +19,9 @@ struct OpenBoundarySPHSystem{BZ, NDIMS, ELTYPE <: Real, S, B, VF} <: FluidSystem function OpenBoundarySPHSystem(plane_points, boundary_zone, sound_speed; sample_geometry=plane_points, - particle_spacing, velocity=0.0, mass=nothing, - density=nothing, pressure=0.0, open_boundary_layers=0, - flow_direction=nothing, velocity_function=nothing) + particle_spacing, flow_direction, open_boundary_layers=0, + velocity=0.0, mass=nothing, density=nothing, + pressure=0.0, velocity_function=nothing) if flow_direction === nothing throw(ArgumentError("Please specify a flow direction.")) end From a509489e2a9975cc1b11fb996f16198029cce482 Mon Sep 17 00:00:00 2001 From: LasNikas Date: Thu, 8 Feb 2024 11:29:26 +0100 Subject: [PATCH 008/107] fix bug --- src/setups/extrude_geometry.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/setups/extrude_geometry.jl b/src/setups/extrude_geometry.jl index 4b3fa6065..5a37584e8 100644 --- a/src/setups/extrude_geometry.jl +++ b/src/setups/extrude_geometry.jl @@ -74,7 +74,7 @@ function ExtrudeGeometry(geometry; particle_spacing, direction, n_extrude=0, coordinates = reshape(stack(coords), (NDIMS, size(face_coords, 2) * (n_extrude + 1))) return InitialCondition(; coordinates, velocity, density, mass, pressure, - particle_spacing_) + particle_spacing=particle_spacing_) end function sample_plane(geometry::AbstractMatrix, particle_spacing) From 1d5d99c58b8da08d97d753ccdd2c5170d2268972 Mon Sep 17 00:00:00 2001 From: LasNikas Date: Thu, 8 Feb 2024 16:37:19 +0100 Subject: [PATCH 009/107] add `tlsph=true` --- src/setups/extrude_geometry.jl | 56 ++++++++++++++++++++++++++++-- test/setups/extrude_geometry.jl | 60 ++++++++++++++++++++++++--------- 2 files changed, 98 insertions(+), 18 deletions(-) diff --git a/src/setups/extrude_geometry.jl b/src/setups/extrude_geometry.jl index 5a37584e8..2ea022615 100644 --- a/src/setups/extrude_geometry.jl +++ b/src/setups/extrude_geometry.jl @@ -59,9 +59,13 @@ shape = ExtrudeGeometry(shape; direction, particle_spacing=0.1, n_extrude=4, den `particle_spacing` between extrusion layers may differ from shapes `particle_spacing`. """ function ExtrudeGeometry(geometry; particle_spacing, direction, n_extrude=0, - velocity=zeros(length(direction)), + velocity=zeros(length(direction)), tlsph=true, mass=nothing, density=nothing, pressure=0.0) - NDIMS = length(direction) + direction_ = normalize(direction) + NDIMS = length(direction_) + + geometry = consider_particle_placement(geometry, direction_, particle_spacing, tlsph) + face_coords, particle_spacing_ = sample_plane(geometry, particle_spacing) if round(particle_spacing, digits=4) != round(particle_spacing_, digits=4) @@ -69,7 +73,7 @@ function ExtrudeGeometry(geometry; particle_spacing, direction, n_extrude=0, "\nNew particle spacing is set to $particle_spacing_." end - coords = (face_coords .+ i * particle_spacing * normalize(direction) for i in 0:n_extrude) + coords = (face_coords .+ i * particle_spacing_ * direction_ for i in 0:n_extrude) coordinates = reshape(stack(coords), (NDIMS, size(face_coords, 2) * (n_extrude + 1))) @@ -149,3 +153,49 @@ function sample_plane(plane_points::NTuple{3}, particle_spacing) return coords, particle_spacing_new end + +consider_particle_placement(geometry, direction, particle_spacing, tlsph) = geometry + +function consider_particle_placement(plane_points::NTuple{2}, direction, particle_spacing, + tlsph) + # With TLSPH, particles need to be AT the min coordinates and not half a particle + # spacing away from it. + (tlsph) && (return plane_points) + + plane_point1 = copy(plane_points[1]) + plane_point2 = copy(plane_points[2]) + + # Vectors shifting the points in the corresponding direction + dir1 = 0.5 * particle_spacing * direction + dir2 = 0.5 * particle_spacing * normalize(plane_point2 - plane_point1) + + plane_point1 .+= dir1 + dir2 + plane_point2 .+= dir1 - dir2 + + return (plane_point1, plane_point2) +end + +function consider_particle_placement(plane_points::NTuple{3}, direction, particle_spacing, + tlsph) + # With TLSPH, particles need to be AT the min coordinates and not half a particle + # spacing away from it. + (tlsph) && (return plane_points) + + plane_point1 = copy(plane_points[1]) + plane_point2 = copy(plane_points[2]) + plane_point3 = copy(plane_points[3]) + + edge1 = normalize(plane_point2 - plane_point1) + edge2 = normalize(plane_point3 - plane_point1) + + # Vectors shifting the points in the corresponding direction + dir1 = 0.5 * particle_spacing * direction + dir2 = 0.5 * particle_spacing * edge1 + dir3 = 0.5 * particle_spacing * edge2 + + plane_point1 .+= dir1 + dir2 + dir3 + plane_point2 .+= dir1 - dir2 + dir3 + plane_point3 .+= dir1 + dir2 - dir3 + + return (plane_point1, plane_point2, plane_point3) +end diff --git a/test/setups/extrude_geometry.jl b/test/setups/extrude_geometry.jl index b884d500e..2cb0cd53c 100644 --- a/test/setups/extrude_geometry.jl +++ b/test/setups/extrude_geometry.jl @@ -33,33 +33,46 @@ shape = ExtrudeGeometry(line; direction=directions[i], particle_spacing=0.15, n_extrude=4, density=1.0) - @test shape.coordinates == expected_coords[i] + @test shape.coordinates ≈ expected_coords[i] end end @testset verbose=true "Extrude Line-Points" begin expected_coords = [ - [0.0 0.07142857142857142 0.14285714285714285 0.21428571428571427 0.2857142857142857 0.35714285714285715 0.42857142857142855 0.5 -0.07142001120134328 8.560227228143757e-6 0.07143713165579957 0.142865703084371 0.21429427451294242 0.28572284594151387 0.35715141737008527 0.4285799887986567 -0.14284002240268656 -0.07141145097411514 1.7120454456287515e-5 0.07144569188302771 0.14287426331159914 0.2143028347401706 0.285731406168742 0.35715997759731344 -0.21426003360402984 -0.14283146217545842 -0.071402890746887 2.5680681684431272e-5 0.07145425211025586 0.1428828235388273 0.2143113949673987 0.28573996639597016 -0.2856800448053731 -0.2142514733768017 -0.14282290194823027 -0.07139433051965885 3.424090891257503e-5 0.07146281233748403 0.14289138376605542 0.21431995519462688; - 0.0 0.14285714285714285 0.2857142857142857 0.42857142857142855 0.5714285714285714 0.7142857142857143 0.8571428571428571 1.0 0.14284002240268656 0.2856971652598294 0.42855430811697226 0.571411450974115 0.714268593831258 0.8571257366884009 0.9999828795455437 1.1428400224026865 0.2856800448053731 0.428537187662516 0.5713943305196588 0.7142514733768017 0.8571086162339445 0.9999657590910874 1.14282290194823 1.2856800448053731 0.4285200672080597 0.5713772100652026 0.7142343529223454 0.8570914957794882 0.9999486386366311 1.142805781493774 1.2856629243509168 1.4285200672080598 0.5713600896107462 0.714217232467889 0.857074375325032 0.9999315181821748 1.1427886610393176 1.2856458038964607 1.4285029467536035 1.5713600896107462], - [0.0 0.07142857142857142 0.14285714285714285 0.21428571428571427 0.2857142857142857 0.35714285714285715 0.42857142857142855 0.5 0.07142001120134328 0.1428485826299147 0.21427715405848613 0.2857057254870575 0.357134296915629 0.42856286834420043 0.49999143977277183 0.5714200112013432 0.14284002240268656 0.214268593831258 0.2856971652598294 0.35712573668840086 0.42855430811697226 0.4999828795455437 0.571411450974115 0.6428400224026866 0.21426003360402984 0.2856886050326013 0.3571171764611727 0.4285457478897441 0.49997431931831554 0.571402890746887 0.6428314621754584 0.7142600336040299 0.2856800448053731 0.3571086162339445 0.428537187662516 0.4999657590910874 0.5713943305196588 0.6428229019482303 0.7142514733768017 0.7856800448053731; - 0.0 0.14285714285714285 0.2857142857142857 0.42857142857142855 0.5714285714285714 0.7142857142857143 0.8571428571428571 1.0 -0.14284002240268656 1.7120454456287515e-5 0.14287426331159914 0.285731406168742 0.42858854902588484 0.5714456918830277 0.7143028347401705 0.8571599775973134 -0.2856800448053731 -0.14282290194823027 3.424090891257503e-5 0.14289138376605542 0.2857485266231983 0.4286056694803412 0.571462812337484 0.7143199551946269 -0.4285200672080597 -0.28566292435091684 -0.142805781493774 5.1361363368862545e-5 0.1429085042205117 0.2857656470776546 0.4286227899347974 0.5714799327919403 -0.5713600896107462 -0.4285029467536034 -0.28564580389646055 -0.1427886610393177 6.848181782515006e-5 0.14292562467496805 0.28578276753211085 0.42863991038925375], - [0.0 0.07142857142857142 0.14285714285714285 0.21428571428571427 0.2857142857142857 0.35714285714285715 0.42857142857142855 0.5 -0.14284002240268656 -0.07141145097411514 1.7120454456287515e-5 0.07144569188302771 0.14287426331159914 0.2143028347401706 0.285731406168742 0.35715997759731344 -0.2856800448053731 -0.2142514733768017 -0.14282290194823027 -0.07139433051965885 3.424090891257503e-5 0.07146281233748403 0.14289138376605542 0.21431995519462688 -0.4285200672080597 -0.3570914957794883 -0.28566292435091684 -0.2142343529223454 -0.142805781493774 -0.07137721006520253 5.1361363368862545e-5 0.07147993279194031 -0.5713600896107462 -0.49993151818217485 -0.4285029467536034 -0.35707437532503195 -0.28564580389646055 -0.2142172324678891 -0.1427886610393177 -0.07136008961074625; - 0.0 0.14285714285714285 0.2857142857142857 0.42857142857142855 0.5714285714285714 0.7142857142857143 0.8571428571428571 1.0 0.07142001120134328 0.21427715405848613 0.357134296915629 0.49999143977277183 0.6428485826299146 0.7857057254870576 0.9285628683442004 1.0714200112013432 0.14284002240268656 0.2856971652598294 0.42855430811697226 0.571411450974115 0.714268593831258 0.8571257366884009 0.9999828795455437 1.1428400224026865 0.21426003360402984 0.3571171764611727 0.49997431931831554 0.6428314621754584 0.7856886050326013 0.9285457478897441 1.0714028907468869 1.21426003360403 0.2856800448053731 0.428537187662516 0.5713943305196588 0.7142514733768017 0.8571086162339445 0.9999657590910874 1.14282290194823 1.2856800448053731], - [0.0 0.07142857142857142 0.14285714285714285 0.21428571428571427 0.2857142857142857 0.35714285714285715 0.42857142857142855 0.5 0.14284002240268656 0.214268593831258 0.2856971652598294 0.35712573668840086 0.42855430811697226 0.4999828795455437 0.571411450974115 0.6428400224026866 0.2856800448053731 0.3571086162339445 0.428537187662516 0.4999657590910874 0.5713943305196588 0.6428229019482303 0.7142514733768017 0.7856800448053731 0.4285200672080597 0.4999486386366311 0.5713772100652026 0.642805781493774 0.7142343529223454 0.7856629243509168 0.8570914957794882 0.9285200672080597 0.5713600896107462 0.6427886610393176 0.714217232467889 0.7856458038964605 0.857074375325032 0.9285029467536035 0.9999315181821748 1.0713600896107462; - 0.0 0.14285714285714285 0.2857142857142857 0.42857142857142855 0.5714285714285714 0.7142857142857143 0.8571428571428571 1.0 -0.07142001120134328 0.07143713165579957 0.21429427451294242 0.35715141737008527 0.5000085602272282 0.642865703084371 0.7857228459415138 0.9285799887986568 -0.14284002240268656 1.7120454456287515e-5 0.14287426331159914 0.285731406168742 0.42858854902588484 0.5714456918830277 0.7143028347401705 0.8571599775973134 -0.21426003360402984 -0.071402890746887 0.07145425211025586 0.2143113949673987 0.35716853782454155 0.5000256806816845 0.6428828235388273 0.7857399663959701 -0.2856800448053731 -0.14282290194823027 3.424090891257503e-5 0.14289138376605542 0.2857485266231983 0.4286056694803412 0.571462812337484 0.7143199551946269], - [0.0 0.07142857142857142 0.14285714285714285 0.21428571428571427 0.2857142857142857 0.35714285714285715 0.42857142857142855 0.5 0.1597 0.23112857142857143 0.30255714285714286 0.37398571428571425 0.4454142857142857 0.5168428571428572 0.5882714285714286 0.6597 0.3194 0.3908285714285714 0.46225714285714287 0.5336857142857143 0.6051142857142857 0.6765428571428571 0.7479714285714285 0.8194 0.4791 0.5505285714285715 0.6219571428571429 0.6933857142857143 0.7648142857142857 0.8362428571428572 0.9076714285714286 0.9791000000000001 0.6388 0.7102285714285714 0.7816571428571428 0.8530857142857143 0.9245142857142857 0.9959428571428572 1.0673714285714286 1.1388; + [0.0 0.07142857142857142 0.14285714285714285 0.21428571428571427 0.2857142857142857 0.35714285714285715 0.42857142857142855 0.5 -0.07142857142857142 0.0 0.07142857142857142 0.14285714285714285 0.21428571428571427 0.2857142857142857 0.3571428571428571 0.4285714285714286 -0.14285714285714285 -0.07142857142857142 0.0 0.07142857142857142 0.14285714285714285 0.2142857142857143 0.2857142857142857 0.35714285714285715 -0.21428571428571425 -0.14285714285714282 -0.0714285714285714 2.7755575615628914e-17 0.07142857142857145 0.1428571428571429 0.2142857142857143 0.28571428571428575 -0.2857142857142857 -0.21428571428571427 -0.14285714285714285 -0.07142857142857142 0.0 0.07142857142857145 0.14285714285714285 0.2142857142857143; + 0.0 0.14285714285714285 0.2857142857142857 0.42857142857142855 0.5714285714285714 0.7142857142857143 0.8571428571428571 1.0 0.14285714285714285 0.2857142857142857 0.42857142857142855 0.5714285714285714 0.7142857142857142 0.8571428571428572 1.0 1.1428571428571428 0.2857142857142857 0.42857142857142855 0.5714285714285714 0.7142857142857142 0.8571428571428571 1.0 1.1428571428571428 1.2857142857142856 0.4285714285714285 0.5714285714285714 0.7142857142857142 0.857142857142857 0.9999999999999999 1.1428571428571428 1.2857142857142856 1.4285714285714284 0.5714285714285714 0.7142857142857142 0.8571428571428571 1.0 1.1428571428571428 1.2857142857142856 1.4285714285714284 1.5714285714285714], + [0.0 0.07142857142857142 0.14285714285714285 0.21428571428571427 0.2857142857142857 0.35714285714285715 0.42857142857142855 0.5 0.07142857142857142 0.14285714285714285 0.21428571428571427 0.2857142857142857 0.3571428571428571 0.4285714285714286 0.5 0.5714285714285714 0.14285714285714285 0.21428571428571427 0.2857142857142857 0.3571428571428571 0.42857142857142855 0.5 0.5714285714285714 0.6428571428571428 0.21428571428571425 0.2857142857142857 0.3571428571428571 0.4285714285714285 0.49999999999999994 0.5714285714285714 0.6428571428571428 0.7142857142857142 0.2857142857142857 0.3571428571428571 0.42857142857142855 0.5 0.5714285714285714 0.6428571428571428 0.7142857142857142 0.7857142857142857; + 0.0 0.14285714285714285 0.2857142857142857 0.42857142857142855 0.5714285714285714 0.7142857142857143 0.8571428571428571 1.0 -0.14285714285714285 0.0 0.14285714285714285 0.2857142857142857 0.42857142857142855 0.5714285714285714 0.7142857142857142 0.8571428571428572 -0.2857142857142857 -0.14285714285714285 0.0 0.14285714285714285 0.2857142857142857 0.4285714285714286 0.5714285714285714 0.7142857142857143 -0.4285714285714285 -0.28571428571428564 -0.1428571428571428 5.551115123125783e-17 0.1428571428571429 0.2857142857142858 0.4285714285714286 0.5714285714285715 -0.5714285714285714 -0.42857142857142855 -0.2857142857142857 -0.14285714285714285 0.0 0.1428571428571429 0.2857142857142857 0.4285714285714286], + [0.0 0.07142857142857142 0.14285714285714285 0.21428571428571427 0.2857142857142857 0.35714285714285715 0.42857142857142855 0.5 -0.14285714285714285 -0.07142857142857142 0.0 0.07142857142857142 0.14285714285714285 0.2142857142857143 0.2857142857142857 0.35714285714285715 -0.2857142857142857 -0.21428571428571427 -0.14285714285714285 -0.07142857142857142 0.0 0.07142857142857145 0.14285714285714285 0.2142857142857143 -0.4285714285714285 -0.3571428571428571 -0.28571428571428564 -0.21428571428571422 -0.1428571428571428 -0.07142857142857134 5.551115123125783e-17 0.07142857142857151 -0.5714285714285714 -0.5 -0.42857142857142855 -0.3571428571428571 -0.2857142857142857 -0.21428571428571425 -0.14285714285714285 -0.0714285714285714; + 0.0 0.14285714285714285 0.2857142857142857 0.42857142857142855 0.5714285714285714 0.7142857142857143 0.8571428571428571 1.0 0.07142857142857142 0.21428571428571427 0.3571428571428571 0.5 0.6428571428571428 0.7857142857142857 0.9285714285714285 1.0714285714285714 0.14285714285714285 0.2857142857142857 0.42857142857142855 0.5714285714285714 0.7142857142857142 0.8571428571428572 1.0 1.1428571428571428 0.21428571428571425 0.3571428571428571 0.49999999999999994 0.6428571428571428 0.7857142857142856 0.9285714285714286 1.0714285714285714 1.2142857142857142 0.2857142857142857 0.42857142857142855 0.5714285714285714 0.7142857142857142 0.8571428571428571 1.0 1.1428571428571428 1.2857142857142856], + [0.0 0.07142857142857142 0.14285714285714285 0.21428571428571427 0.2857142857142857 0.35714285714285715 0.42857142857142855 0.5 0.14285714285714285 0.21428571428571427 0.2857142857142857 0.3571428571428571 0.42857142857142855 0.5 0.5714285714285714 0.6428571428571428 0.2857142857142857 0.3571428571428571 0.42857142857142855 0.5 0.5714285714285714 0.6428571428571428 0.7142857142857142 0.7857142857142857 0.4285714285714285 0.4999999999999999 0.5714285714285714 0.6428571428571428 0.7142857142857142 0.7857142857142856 0.857142857142857 0.9285714285714285 0.5714285714285714 0.6428571428571428 0.7142857142857142 0.7857142857142857 0.8571428571428571 0.9285714285714286 1.0 1.0714285714285714; + 0.0 0.14285714285714285 0.2857142857142857 0.42857142857142855 0.5714285714285714 0.7142857142857143 0.8571428571428571 1.0 -0.07142857142857142 0.07142857142857142 0.21428571428571427 0.3571428571428571 0.5 0.6428571428571429 0.7857142857142857 0.9285714285714286 -0.14285714285714285 0.0 0.14285714285714285 0.2857142857142857 0.42857142857142855 0.5714285714285714 0.7142857142857142 0.8571428571428572 -0.21428571428571425 -0.0714285714285714 0.07142857142857145 0.2142857142857143 0.35714285714285715 0.5 0.6428571428571428 0.7857142857142858 -0.2857142857142857 -0.14285714285714285 0.0 0.14285714285714285 0.2857142857142857 0.4285714285714286 0.5714285714285714 0.7142857142857143], + [0.0 0.07142857142857142 0.14285714285714285 0.21428571428571427 0.2857142857142857 0.35714285714285715 0.42857142857142855 0.5 0.15971914124998496 0.23114771267855638 0.3025762841071278 0.37400485553569923 0.4454334269642707 0.5168619983928421 0.5882905698214135 0.659719141249985 0.3194382824999699 0.39086685392854137 0.46229542535711277 0.5337239967856842 0.6051525682142556 0.6765811396428271 0.7480097110713985 0.81943828249997 0.47915742374995485 0.5505859951785262 0.6220145666070978 0.6934431380356691 0.7648717094642405 0.8363002808928119 0.9077288523213833 0.9791574237499548 0.6388765649999398 0.7103051364285112 0.7817337078570827 0.8531622792856541 0.9245908507142255 0.9960194221427969 1.0674479935713683 1.13887656499994; 0.0 0.14285714285714285 0.2857142857142857 0.42857142857142855 0.5714285714285714 0.7142857142857143 0.8571428571428571 1.0 0.0 0.14285714285714285 0.2857142857142857 0.42857142857142855 0.5714285714285714 0.7142857142857143 0.8571428571428571 1.0 0.0 0.14285714285714285 0.2857142857142857 0.42857142857142855 0.5714285714285714 0.7142857142857143 0.8571428571428571 1.0 0.0 0.14285714285714285 0.2857142857142857 0.42857142857142855 0.5714285714285714 0.7142857142857143 0.8571428571428571 1.0 0.0 0.14285714285714285 0.2857142857142857 0.42857142857142855 0.5714285714285714 0.7142857142857143 0.8571428571428571 1.0], [0.0 0.07142857142857142 0.14285714285714285 0.21428571428571427 0.2857142857142857 0.35714285714285715 0.42857142857142855 0.5 0.0 0.07142857142857142 0.14285714285714285 0.21428571428571427 0.2857142857142857 0.35714285714285715 0.42857142857142855 0.5 0.0 0.07142857142857142 0.14285714285714285 0.21428571428571427 0.2857142857142857 0.35714285714285715 0.42857142857142855 0.5 0.0 0.07142857142857142 0.14285714285714285 0.21428571428571427 0.2857142857142857 0.35714285714285715 0.42857142857142855 0.5 0.0 0.07142857142857142 0.14285714285714285 0.21428571428571427 0.2857142857142857 0.35714285714285715 0.42857142857142855 0.5; - 0.0 0.14285714285714285 0.2857142857142857 0.42857142857142855 0.5714285714285714 0.7142857142857143 0.8571428571428571 1.0 0.1597 0.30255714285714286 0.4454142857142857 0.5882714285714286 0.7311285714285713 0.8739857142857144 1.0168428571428572 1.1597 0.3194 0.46225714285714287 0.6051142857142857 0.7479714285714285 0.8908285714285714 1.0336857142857143 1.1765428571428571 1.3194 0.4791 0.6219571428571429 0.7648142857142857 0.9076714285714286 1.0505285714285715 1.1933857142857143 1.336242857142857 1.4791 0.6388 0.7816571428571428 0.9245142857142857 1.0673714285714286 1.2102285714285714 1.3530857142857142 1.495942857142857 1.6388], + 0.0 0.14285714285714285 0.2857142857142857 0.42857142857142855 0.5714285714285714 0.7142857142857143 0.8571428571428571 1.0 0.15971914124998496 0.3025762841071278 0.4454334269642707 0.5882905698214135 0.7311477126785564 0.8740048555356993 1.016861998392842 1.159719141249985 0.3194382824999699 0.46229542535711277 0.6051525682142556 0.7480097110713985 0.8908668539285414 1.0337239967856842 1.176581139642827 1.31943828249997 0.47915742374995485 0.6220145666070978 0.7648717094642405 0.9077288523213833 1.0505859951785261 1.1934431380356691 1.336300280892812 1.479157423749955 0.6388765649999398 0.7817337078570827 0.9245908507142255 1.0674479935713683 1.2103051364285111 1.3531622792856541 1.496019422142797 1.63887656499994], ] @testset "Direction $i" for i in eachindex(directions) shape = ExtrudeGeometry((point1, point2); direction=directions[i], particle_spacing=0.1597, n_extrude=4, density=1.0) - @test shape.coordinates == expected_coords[i] + @test shape.coordinates ≈ expected_coords[i] end end + + @testset verbose=true "Shifted Particles" begin + point1 = [0.0, 0.0] + point2 = [0.0, 1.0] + + expected_coords = [-0.05 -0.05 -0.05 -0.05 -0.05 -0.05 -0.05 -0.05 -0.05 -0.1625 -0.1625 -0.1625 -0.1625 -0.1625 -0.1625 -0.1625 -0.1625 -0.1625 -0.275 -0.275 -0.275 -0.275 -0.275 -0.275 -0.275 -0.275 -0.275 -0.3875 -0.3875 -0.3875 -0.3875 -0.3875 -0.3875 -0.3875 -0.3875 -0.3875 -0.5 -0.5 -0.5 -0.5 -0.5 -0.5 -0.5 -0.5 -0.5; + 0.05 0.1625 0.275 0.38749999999999996 0.5 0.6125 0.7249999999999999 0.8374999999999999 0.95 0.05 0.1625 0.275 0.38749999999999996 0.5 0.6125 0.7249999999999999 0.8374999999999999 0.95 0.05 0.1625 0.275 0.38749999999999996 0.5 0.6125 0.7249999999999999 0.8374999999999999 0.95 0.05 0.1625 0.275 0.38749999999999996 0.5 0.6125 0.7249999999999999 0.8374999999999999 0.95 0.05 0.1625 0.275 0.38749999999999996 0.5 0.6125 0.7249999999999999 0.8374999999999999 0.95] + + shape = ExtrudeGeometry((point1, point2); direction=[-1.0, 0.0], tlsph=false, + particle_spacing=0.1, n_extrude=4, density=1.0) + + @test shape.coordinates ≈ expected_coords + end end # 3D @@ -84,7 +97,7 @@ end shape = ExtrudeGeometry(geometry; direction=directions[i], particle_spacing, n_extrude=4, density=1.0) - @test shape.coordinates == expected_coords[i] + @test shape.coordinates ≈ expected_coords[i] end end @@ -97,11 +110,28 @@ end expected_coords = [0.0 0.09090909090909091 0.18181818181818182 0.2727272727272727 0.36363636363636365 0.45454545454545453 0.5454545454545454 0.6363636363636364 0.7272727272727273 0.8181818181818182 0.9090909090909091 1.0 0.03333333333333333 0.12424242424242424 0.21515151515151515 0.30606060606060603 0.396969696969697 0.48787878787878786 0.5787878787878787 0.6696969696969697 0.7606060606060606 0.8515151515151516 0.9424242424242424 1.0333333333333334 0.06666666666666667 0.1575757575757576 0.24848484848484848 0.33939393939393936 0.4303030303030303 0.5212121212121212 0.6121212121212121 0.703030303030303 0.793939393939394 0.8848484848484849 0.9757575757575757 1.0666666666666667 0.1 0.19090909090909092 0.28181818181818186 0.3727272727272727 0.4636363636363636 0.5545454545454546 0.6454545454545454 0.7363636363636363 0.8272727272727273 0.9181818181818182 1.009090909090909 1.1 0.13333333333333333 0.22424242424242424 0.3151515151515152 0.406060606060606 0.49696969696969695 0.5878787878787879 0.6787878787878787 0.7696969696969697 0.8606060606060606 0.9515151515151515 1.0424242424242425 1.1333333333333333 0.16666666666666666 0.25757575757575757 0.3484848484848485 0.43939393939393934 0.5303030303030303 0.6212121212121212 0.712121212121212 0.803030303030303 0.8939393939393939 0.9848484848484849 1.0757575757575757 1.1666666666666667 0.2 0.2909090909090909 0.38181818181818183 0.4727272727272727 0.5636363636363637 0.6545454545454545 0.7454545454545454 0.8363636363636364 0.9272727272727272 1.0181818181818183 1.1090909090909091 1.2 0.23333333333333334 0.3242424242424242 0.41515151515151516 0.5060606060606061 0.5969696969696969 0.6878787878787879 0.7787878787878788 0.8696969696969696 0.9606060606060607 1.0515151515151515 1.1424242424242423 1.2333333333333334 0.26666666666666666 0.35757575757575755 0.4484848484848485 0.5393939393939393 0.6303030303030304 0.7212121212121212 0.812121212121212 0.9030303030303031 0.9939393939393939 1.084848484848485 1.1757575757575758 1.2666666666666666 0.3 0.3909090909090909 0.4818181818181818 0.5727272727272728 0.6636363636363636 0.7545454545454545 0.8454545454545455 0.9363636363636363 1.0272727272727273 1.1181818181818182 1.209090909090909 1.3 0.3333333333333333 0.4242424242424242 0.5151515151515151 0.606060606060606 0.696969696969697 0.7878787878787878 0.8787878787878787 0.9696969696969697 1.0606060606060606 1.1515151515151516 1.2424242424242424 1.3333333333333333 0.36666666666666664 0.4575757575757575 0.5484848484848485 0.6393939393939394 0.7303030303030302 0.8212121212121212 0.9121212121212121 1.003030303030303 1.093939393939394 1.1848484848484848 1.2757575757575756 1.3666666666666667 0.4 0.49090909090909096 0.5818181818181818 0.6727272727272727 0.7636363636363637 0.8545454545454545 0.9454545454545454 1.0363636363636364 1.1272727272727274 1.2181818181818183 1.309090909090909 1.4 0.43333333333333335 0.5242424242424243 0.6151515151515152 0.706060606060606 0.796969696969697 0.8878787878787879 0.9787878787878788 1.0696969696969698 1.1606060606060606 1.2515151515151515 1.3424242424242423 1.4333333333333333 0.4666666666666667 0.5575757575757576 0.6484848484848484 0.7393939393939394 0.8303030303030303 0.9212121212121211 1.0121212121212122 1.103030303030303 1.1939393939393939 1.284848484848485 1.3757575757575757 1.4666666666666668 0.5 0.5909090909090909 0.6818181818181819 0.7727272727272727 0.8636363636363636 0.9545454545454546 1.0454545454545454 1.1363636363636362 1.2272727272727273 1.3181818181818183 1.4090909090909092 1.5 0.0 0.09090909090909091 0.18181818181818182 0.2727272727272727 0.36363636363636365 0.45454545454545453 0.5454545454545454 0.6363636363636364 0.7272727272727273 0.8181818181818182 0.9090909090909091 1.0 0.03333333333333333 0.12424242424242424 0.21515151515151515 0.30606060606060603 0.396969696969697 0.48787878787878786 0.5787878787878787 0.6696969696969697 0.7606060606060606 0.8515151515151516 0.9424242424242424 1.0333333333333334 0.06666666666666667 0.1575757575757576 0.24848484848484848 0.33939393939393936 0.4303030303030303 0.5212121212121212 0.6121212121212121 0.703030303030303 0.793939393939394 0.8848484848484849 0.9757575757575757 1.0666666666666667 0.1 0.19090909090909092 0.28181818181818186 0.3727272727272727 0.4636363636363636 0.5545454545454546 0.6454545454545454 0.7363636363636363 0.8272727272727273 0.9181818181818182 1.009090909090909 1.1 0.13333333333333333 0.22424242424242424 0.3151515151515152 0.406060606060606 0.49696969696969695 0.5878787878787879 0.6787878787878787 0.7696969696969697 0.8606060606060606 0.9515151515151515 1.0424242424242425 1.1333333333333333 0.16666666666666666 0.25757575757575757 0.3484848484848485 0.43939393939393934 0.5303030303030303 0.6212121212121212 0.712121212121212 0.803030303030303 0.8939393939393939 0.9848484848484849 1.0757575757575757 1.1666666666666667 0.2 0.2909090909090909 0.38181818181818183 0.4727272727272727 0.5636363636363637 0.6545454545454545 0.7454545454545454 0.8363636363636364 0.9272727272727272 1.0181818181818183 1.1090909090909091 1.2 0.23333333333333334 0.3242424242424242 0.41515151515151516 0.5060606060606061 0.5969696969696969 0.6878787878787879 0.7787878787878788 0.8696969696969696 0.9606060606060607 1.0515151515151515 1.1424242424242423 1.2333333333333334 0.26666666666666666 0.35757575757575755 0.4484848484848485 0.5393939393939393 0.6303030303030304 0.7212121212121212 0.812121212121212 0.9030303030303031 0.9939393939393939 1.084848484848485 1.1757575757575758 1.2666666666666666 0.3 0.3909090909090909 0.4818181818181818 0.5727272727272728 0.6636363636363636 0.7545454545454545 0.8454545454545455 0.9363636363636363 1.0272727272727273 1.1181818181818182 1.209090909090909 1.3 0.3333333333333333 0.4242424242424242 0.5151515151515151 0.606060606060606 0.696969696969697 0.7878787878787878 0.8787878787878787 0.9696969696969697 1.0606060606060606 1.1515151515151516 1.2424242424242424 1.3333333333333333 0.36666666666666664 0.4575757575757575 0.5484848484848485 0.6393939393939394 0.7303030303030302 0.8212121212121212 0.9121212121212121 1.003030303030303 1.093939393939394 1.1848484848484848 1.2757575757575756 1.3666666666666667 0.4 0.49090909090909096 0.5818181818181818 0.6727272727272727 0.7636363636363637 0.8545454545454545 0.9454545454545454 1.0363636363636364 1.1272727272727274 1.2181818181818183 1.309090909090909 1.4 0.43333333333333335 0.5242424242424243 0.6151515151515152 0.706060606060606 0.796969696969697 0.8878787878787879 0.9787878787878788 1.0696969696969698 1.1606060606060606 1.2515151515151515 1.3424242424242423 1.4333333333333333 0.4666666666666667 0.5575757575757576 0.6484848484848484 0.7393939393939394 0.8303030303030303 0.9212121212121211 1.0121212121212122 1.103030303030303 1.1939393939393939 1.284848484848485 1.3757575757575757 1.4666666666666668 0.5 0.5909090909090909 0.6818181818181819 0.7727272727272727 0.8636363636363636 0.9545454545454546 1.0454545454545454 1.1363636363636362 1.2272727272727273 1.3181818181818183 1.4090909090909092 1.5 0.0 0.09090909090909091 0.18181818181818182 0.2727272727272727 0.36363636363636365 0.45454545454545453 0.5454545454545454 0.6363636363636364 0.7272727272727273 0.8181818181818182 0.9090909090909091 1.0 0.03333333333333333 0.12424242424242424 0.21515151515151515 0.30606060606060603 0.396969696969697 0.48787878787878786 0.5787878787878787 0.6696969696969697 0.7606060606060606 0.8515151515151516 0.9424242424242424 1.0333333333333334 0.06666666666666667 0.1575757575757576 0.24848484848484848 0.33939393939393936 0.4303030303030303 0.5212121212121212 0.6121212121212121 0.703030303030303 0.793939393939394 0.8848484848484849 0.9757575757575757 1.0666666666666667 0.1 0.19090909090909092 0.28181818181818186 0.3727272727272727 0.4636363636363636 0.5545454545454546 0.6454545454545454 0.7363636363636363 0.8272727272727273 0.9181818181818182 1.009090909090909 1.1 0.13333333333333333 0.22424242424242424 0.3151515151515152 0.406060606060606 0.49696969696969695 0.5878787878787879 0.6787878787878787 0.7696969696969697 0.8606060606060606 0.9515151515151515 1.0424242424242425 1.1333333333333333 0.16666666666666666 0.25757575757575757 0.3484848484848485 0.43939393939393934 0.5303030303030303 0.6212121212121212 0.712121212121212 0.803030303030303 0.8939393939393939 0.9848484848484849 1.0757575757575757 1.1666666666666667 0.2 0.2909090909090909 0.38181818181818183 0.4727272727272727 0.5636363636363637 0.6545454545454545 0.7454545454545454 0.8363636363636364 0.9272727272727272 1.0181818181818183 1.1090909090909091 1.2 0.23333333333333334 0.3242424242424242 0.41515151515151516 0.5060606060606061 0.5969696969696969 0.6878787878787879 0.7787878787878788 0.8696969696969696 0.9606060606060607 1.0515151515151515 1.1424242424242423 1.2333333333333334 0.26666666666666666 0.35757575757575755 0.4484848484848485 0.5393939393939393 0.6303030303030304 0.7212121212121212 0.812121212121212 0.9030303030303031 0.9939393939393939 1.084848484848485 1.1757575757575758 1.2666666666666666 0.3 0.3909090909090909 0.4818181818181818 0.5727272727272728 0.6636363636363636 0.7545454545454545 0.8454545454545455 0.9363636363636363 1.0272727272727273 1.1181818181818182 1.209090909090909 1.3 0.3333333333333333 0.4242424242424242 0.5151515151515151 0.606060606060606 0.696969696969697 0.7878787878787878 0.8787878787878787 0.9696969696969697 1.0606060606060606 1.1515151515151516 1.2424242424242424 1.3333333333333333 0.36666666666666664 0.4575757575757575 0.5484848484848485 0.6393939393939394 0.7303030303030302 0.8212121212121212 0.9121212121212121 1.003030303030303 1.093939393939394 1.1848484848484848 1.2757575757575756 1.3666666666666667 0.4 0.49090909090909096 0.5818181818181818 0.6727272727272727 0.7636363636363637 0.8545454545454545 0.9454545454545454 1.0363636363636364 1.1272727272727274 1.2181818181818183 1.309090909090909 1.4 0.43333333333333335 0.5242424242424243 0.6151515151515152 0.706060606060606 0.796969696969697 0.8878787878787879 0.9787878787878788 1.0696969696969698 1.1606060606060606 1.2515151515151515 1.3424242424242423 1.4333333333333333 0.4666666666666667 0.5575757575757576 0.6484848484848484 0.7393939393939394 0.8303030303030303 0.9212121212121211 1.0121212121212122 1.103030303030303 1.1939393939393939 1.284848484848485 1.3757575757575757 1.4666666666666668 0.5 0.5909090909090909 0.6818181818181819 0.7727272727272727 0.8636363636363636 0.9545454545454546 1.0454545454545454 1.1363636363636362 1.2272727272727273 1.3181818181818183 1.4090909090909092 1.5 0.0 0.09090909090909091 0.18181818181818182 0.2727272727272727 0.36363636363636365 0.45454545454545453 0.5454545454545454 0.6363636363636364 0.7272727272727273 0.8181818181818182 0.9090909090909091 1.0 0.03333333333333333 0.12424242424242424 0.21515151515151515 0.30606060606060603 0.396969696969697 0.48787878787878786 0.5787878787878787 0.6696969696969697 0.7606060606060606 0.8515151515151516 0.9424242424242424 1.0333333333333334 0.06666666666666667 0.1575757575757576 0.24848484848484848 0.33939393939393936 0.4303030303030303 0.5212121212121212 0.6121212121212121 0.703030303030303 0.793939393939394 0.8848484848484849 0.9757575757575757 1.0666666666666667 0.1 0.19090909090909092 0.28181818181818186 0.3727272727272727 0.4636363636363636 0.5545454545454546 0.6454545454545454 0.7363636363636363 0.8272727272727273 0.9181818181818182 1.009090909090909 1.1 0.13333333333333333 0.22424242424242424 0.3151515151515152 0.406060606060606 0.49696969696969695 0.5878787878787879 0.6787878787878787 0.7696969696969697 0.8606060606060606 0.9515151515151515 1.0424242424242425 1.1333333333333333 0.16666666666666666 0.25757575757575757 0.3484848484848485 0.43939393939393934 0.5303030303030303 0.6212121212121212 0.712121212121212 0.803030303030303 0.8939393939393939 0.9848484848484849 1.0757575757575757 1.1666666666666667 0.2 0.2909090909090909 0.38181818181818183 0.4727272727272727 0.5636363636363637 0.6545454545454545 0.7454545454545454 0.8363636363636364 0.9272727272727272 1.0181818181818183 1.1090909090909091 1.2 0.23333333333333334 0.3242424242424242 0.41515151515151516 0.5060606060606061 0.5969696969696969 0.6878787878787879 0.7787878787878788 0.8696969696969696 0.9606060606060607 1.0515151515151515 1.1424242424242423 1.2333333333333334 0.26666666666666666 0.35757575757575755 0.4484848484848485 0.5393939393939393 0.6303030303030304 0.7212121212121212 0.812121212121212 0.9030303030303031 0.9939393939393939 1.084848484848485 1.1757575757575758 1.2666666666666666 0.3 0.3909090909090909 0.4818181818181818 0.5727272727272728 0.6636363636363636 0.7545454545454545 0.8454545454545455 0.9363636363636363 1.0272727272727273 1.1181818181818182 1.209090909090909 1.3 0.3333333333333333 0.4242424242424242 0.5151515151515151 0.606060606060606 0.696969696969697 0.7878787878787878 0.8787878787878787 0.9696969696969697 1.0606060606060606 1.1515151515151516 1.2424242424242424 1.3333333333333333 0.36666666666666664 0.4575757575757575 0.5484848484848485 0.6393939393939394 0.7303030303030302 0.8212121212121212 0.9121212121212121 1.003030303030303 1.093939393939394 1.1848484848484848 1.2757575757575756 1.3666666666666667 0.4 0.49090909090909096 0.5818181818181818 0.6727272727272727 0.7636363636363637 0.8545454545454545 0.9454545454545454 1.0363636363636364 1.1272727272727274 1.2181818181818183 1.309090909090909 1.4 0.43333333333333335 0.5242424242424243 0.6151515151515152 0.706060606060606 0.796969696969697 0.8878787878787879 0.9787878787878788 1.0696969696969698 1.1606060606060606 1.2515151515151515 1.3424242424242423 1.4333333333333333 0.4666666666666667 0.5575757575757576 0.6484848484848484 0.7393939393939394 0.8303030303030303 0.9212121212121211 1.0121212121212122 1.103030303030303 1.1939393939393939 1.284848484848485 1.3757575757575757 1.4666666666666668 0.5 0.5909090909090909 0.6818181818181819 0.7727272727272727 0.8636363636363636 0.9545454545454546 1.0454545454545454 1.1363636363636362 1.2272727272727273 1.3181818181818183 1.4090909090909092 1.5; 0.0 0.018181818181818184 0.03636363636363637 0.05454545454545454 0.07272727272727274 0.09090909090909091 0.10909090909090909 0.1272727272727273 0.14545454545454548 0.16363636363636366 0.18181818181818182 0.2 0.06666666666666667 0.08484848484848485 0.10303030303030303 0.12121212121212122 0.1393939393939394 0.1575757575757576 0.17575757575757575 0.19393939393939397 0.21212121212121215 0.23030303030303034 0.24848484848484848 0.26666666666666666 0.13333333333333333 0.15151515151515152 0.1696969696969697 0.18787878787878787 0.20606060606060606 0.22424242424242424 0.24242424242424243 0.2606060606060606 0.2787878787878788 0.296969696969697 0.3151515151515152 0.33333333333333337 0.2 0.2181818181818182 0.2363636363636364 0.2545454545454546 0.27272727272727276 0.2909090909090909 0.3090909090909091 0.32727272727272727 0.34545454545454546 0.36363636363636365 0.38181818181818183 0.4 0.26666666666666666 0.28484848484848485 0.30303030303030304 0.3212121212121212 0.3393939393939394 0.35757575757575755 0.37575757575757573 0.3939393939393939 0.4121212121212121 0.4303030303030303 0.4484848484848485 0.4666666666666667 0.3333333333333333 0.3515151515151515 0.3696969696969697 0.3878787878787879 0.40606060606060607 0.4242424242424242 0.4424242424242424 0.4606060606060606 0.47878787878787876 0.49696969696969695 0.5151515151515151 0.5333333333333333 0.4 0.4181818181818182 0.4363636363636364 0.4545454545454546 0.4727272727272728 0.49090909090909096 0.5090909090909091 0.5272727272727273 0.5454545454545455 0.5636363636363637 0.5818181818181818 0.6000000000000001 0.4666666666666667 0.48484848484848486 0.503030303030303 0.5212121212121212 0.5393939393939394 0.5575757575757576 0.5757575757575758 0.593939393939394 0.6121212121212122 0.6303030303030304 0.6484848484848484 0.6666666666666667 0.5333333333333333 0.5515151515151515 0.5696969696969697 0.5878787878787879 0.6060606060606061 0.6242424242424243 0.6424242424242425 0.6606060606060606 0.6787878787878788 0.696969696969697 0.7151515151515151 0.7333333333333334 0.6 0.6181818181818182 0.6363636363636364 0.6545454545454545 0.6727272727272727 0.6909090909090909 0.7090909090909091 0.7272727272727273 0.7454545454545455 0.7636363636363637 0.7818181818181817 0.8 0.6666666666666666 0.6848484848484848 0.703030303030303 0.7212121212121212 0.7393939393939394 0.7575757575757576 0.7757575757575758 0.793939393939394 0.8121212121212121 0.8303030303030303 0.8484848484848484 0.8666666666666667 0.7333333333333333 0.7515151515151515 0.7696969696969697 0.7878787878787878 0.806060606060606 0.8242424242424242 0.8424242424242424 0.8606060606060606 0.8787878787878788 0.896969696969697 0.915151515151515 0.9333333333333333 0.8 0.8181818181818182 0.8363636363636364 0.8545454545454546 0.8727272727272728 0.890909090909091 0.9090909090909092 0.9272727272727274 0.9454545454545455 0.9636363636363637 0.9818181818181819 1.0 0.8666666666666667 0.8848484848484849 0.9030303030303031 0.9212121212121213 0.9393939393939394 0.9575757575757576 0.9757575757575758 0.993939393939394 1.0121212121212122 1.0303030303030303 1.0484848484848486 1.0666666666666667 0.9333333333333333 0.9515151515151515 0.9696969696969697 0.9878787878787879 1.006060606060606 1.0242424242424242 1.0424242424242425 1.0606060606060606 1.0787878787878789 1.096969696969697 1.1151515151515152 1.1333333333333333 1.0 1.018181818181818 1.0363636363636364 1.0545454545454545 1.0727272727272728 1.0909090909090908 1.1090909090909091 1.1272727272727272 1.1454545454545455 1.1636363636363636 1.1818181818181819 1.2 0.0 0.018181818181818184 0.03636363636363637 0.05454545454545454 0.07272727272727274 0.09090909090909091 0.10909090909090909 0.1272727272727273 0.14545454545454548 0.16363636363636366 0.18181818181818182 0.2 0.06666666666666667 0.08484848484848485 0.10303030303030303 0.12121212121212122 0.1393939393939394 0.1575757575757576 0.17575757575757575 0.19393939393939397 0.21212121212121215 0.23030303030303034 0.24848484848484848 0.26666666666666666 0.13333333333333333 0.15151515151515152 0.1696969696969697 0.18787878787878787 0.20606060606060606 0.22424242424242424 0.24242424242424243 0.2606060606060606 0.2787878787878788 0.296969696969697 0.3151515151515152 0.33333333333333337 0.2 0.2181818181818182 0.2363636363636364 0.2545454545454546 0.27272727272727276 0.2909090909090909 0.3090909090909091 0.32727272727272727 0.34545454545454546 0.36363636363636365 0.38181818181818183 0.4 0.26666666666666666 0.28484848484848485 0.30303030303030304 0.3212121212121212 0.3393939393939394 0.35757575757575755 0.37575757575757573 0.3939393939393939 0.4121212121212121 0.4303030303030303 0.4484848484848485 0.4666666666666667 0.3333333333333333 0.3515151515151515 0.3696969696969697 0.3878787878787879 0.40606060606060607 0.4242424242424242 0.4424242424242424 0.4606060606060606 0.47878787878787876 0.49696969696969695 0.5151515151515151 0.5333333333333333 0.4 0.4181818181818182 0.4363636363636364 0.4545454545454546 0.4727272727272728 0.49090909090909096 0.5090909090909091 0.5272727272727273 0.5454545454545455 0.5636363636363637 0.5818181818181818 0.6000000000000001 0.4666666666666667 0.48484848484848486 0.503030303030303 0.5212121212121212 0.5393939393939394 0.5575757575757576 0.5757575757575758 0.593939393939394 0.6121212121212122 0.6303030303030304 0.6484848484848484 0.6666666666666667 0.5333333333333333 0.5515151515151515 0.5696969696969697 0.5878787878787879 0.6060606060606061 0.6242424242424243 0.6424242424242425 0.6606060606060606 0.6787878787878788 0.696969696969697 0.7151515151515151 0.7333333333333334 0.6 0.6181818181818182 0.6363636363636364 0.6545454545454545 0.6727272727272727 0.6909090909090909 0.7090909090909091 0.7272727272727273 0.7454545454545455 0.7636363636363637 0.7818181818181817 0.8 0.6666666666666666 0.6848484848484848 0.703030303030303 0.7212121212121212 0.7393939393939394 0.7575757575757576 0.7757575757575758 0.793939393939394 0.8121212121212121 0.8303030303030303 0.8484848484848484 0.8666666666666667 0.7333333333333333 0.7515151515151515 0.7696969696969697 0.7878787878787878 0.806060606060606 0.8242424242424242 0.8424242424242424 0.8606060606060606 0.8787878787878788 0.896969696969697 0.915151515151515 0.9333333333333333 0.8 0.8181818181818182 0.8363636363636364 0.8545454545454546 0.8727272727272728 0.890909090909091 0.9090909090909092 0.9272727272727274 0.9454545454545455 0.9636363636363637 0.9818181818181819 1.0 0.8666666666666667 0.8848484848484849 0.9030303030303031 0.9212121212121213 0.9393939393939394 0.9575757575757576 0.9757575757575758 0.993939393939394 1.0121212121212122 1.0303030303030303 1.0484848484848486 1.0666666666666667 0.9333333333333333 0.9515151515151515 0.9696969696969697 0.9878787878787879 1.006060606060606 1.0242424242424242 1.0424242424242425 1.0606060606060606 1.0787878787878789 1.096969696969697 1.1151515151515152 1.1333333333333333 1.0 1.018181818181818 1.0363636363636364 1.0545454545454545 1.0727272727272728 1.0909090909090908 1.1090909090909091 1.1272727272727272 1.1454545454545455 1.1636363636363636 1.1818181818181819 1.2 0.0 0.018181818181818184 0.03636363636363637 0.05454545454545454 0.07272727272727274 0.09090909090909091 0.10909090909090909 0.1272727272727273 0.14545454545454548 0.16363636363636366 0.18181818181818182 0.2 0.06666666666666667 0.08484848484848485 0.10303030303030303 0.12121212121212122 0.1393939393939394 0.1575757575757576 0.17575757575757575 0.19393939393939397 0.21212121212121215 0.23030303030303034 0.24848484848484848 0.26666666666666666 0.13333333333333333 0.15151515151515152 0.1696969696969697 0.18787878787878787 0.20606060606060606 0.22424242424242424 0.24242424242424243 0.2606060606060606 0.2787878787878788 0.296969696969697 0.3151515151515152 0.33333333333333337 0.2 0.2181818181818182 0.2363636363636364 0.2545454545454546 0.27272727272727276 0.2909090909090909 0.3090909090909091 0.32727272727272727 0.34545454545454546 0.36363636363636365 0.38181818181818183 0.4 0.26666666666666666 0.28484848484848485 0.30303030303030304 0.3212121212121212 0.3393939393939394 0.35757575757575755 0.37575757575757573 0.3939393939393939 0.4121212121212121 0.4303030303030303 0.4484848484848485 0.4666666666666667 0.3333333333333333 0.3515151515151515 0.3696969696969697 0.3878787878787879 0.40606060606060607 0.4242424242424242 0.4424242424242424 0.4606060606060606 0.47878787878787876 0.49696969696969695 0.5151515151515151 0.5333333333333333 0.4 0.4181818181818182 0.4363636363636364 0.4545454545454546 0.4727272727272728 0.49090909090909096 0.5090909090909091 0.5272727272727273 0.5454545454545455 0.5636363636363637 0.5818181818181818 0.6000000000000001 0.4666666666666667 0.48484848484848486 0.503030303030303 0.5212121212121212 0.5393939393939394 0.5575757575757576 0.5757575757575758 0.593939393939394 0.6121212121212122 0.6303030303030304 0.6484848484848484 0.6666666666666667 0.5333333333333333 0.5515151515151515 0.5696969696969697 0.5878787878787879 0.6060606060606061 0.6242424242424243 0.6424242424242425 0.6606060606060606 0.6787878787878788 0.696969696969697 0.7151515151515151 0.7333333333333334 0.6 0.6181818181818182 0.6363636363636364 0.6545454545454545 0.6727272727272727 0.6909090909090909 0.7090909090909091 0.7272727272727273 0.7454545454545455 0.7636363636363637 0.7818181818181817 0.8 0.6666666666666666 0.6848484848484848 0.703030303030303 0.7212121212121212 0.7393939393939394 0.7575757575757576 0.7757575757575758 0.793939393939394 0.8121212121212121 0.8303030303030303 0.8484848484848484 0.8666666666666667 0.7333333333333333 0.7515151515151515 0.7696969696969697 0.7878787878787878 0.806060606060606 0.8242424242424242 0.8424242424242424 0.8606060606060606 0.8787878787878788 0.896969696969697 0.915151515151515 0.9333333333333333 0.8 0.8181818181818182 0.8363636363636364 0.8545454545454546 0.8727272727272728 0.890909090909091 0.9090909090909092 0.9272727272727274 0.9454545454545455 0.9636363636363637 0.9818181818181819 1.0 0.8666666666666667 0.8848484848484849 0.9030303030303031 0.9212121212121213 0.9393939393939394 0.9575757575757576 0.9757575757575758 0.993939393939394 1.0121212121212122 1.0303030303030303 1.0484848484848486 1.0666666666666667 0.9333333333333333 0.9515151515151515 0.9696969696969697 0.9878787878787879 1.006060606060606 1.0242424242424242 1.0424242424242425 1.0606060606060606 1.0787878787878789 1.096969696969697 1.1151515151515152 1.1333333333333333 1.0 1.018181818181818 1.0363636363636364 1.0545454545454545 1.0727272727272728 1.0909090909090908 1.1090909090909091 1.1272727272727272 1.1454545454545455 1.1636363636363636 1.1818181818181819 1.2 0.0 0.018181818181818184 0.03636363636363637 0.05454545454545454 0.07272727272727274 0.09090909090909091 0.10909090909090909 0.1272727272727273 0.14545454545454548 0.16363636363636366 0.18181818181818182 0.2 0.06666666666666667 0.08484848484848485 0.10303030303030303 0.12121212121212122 0.1393939393939394 0.1575757575757576 0.17575757575757575 0.19393939393939397 0.21212121212121215 0.23030303030303034 0.24848484848484848 0.26666666666666666 0.13333333333333333 0.15151515151515152 0.1696969696969697 0.18787878787878787 0.20606060606060606 0.22424242424242424 0.24242424242424243 0.2606060606060606 0.2787878787878788 0.296969696969697 0.3151515151515152 0.33333333333333337 0.2 0.2181818181818182 0.2363636363636364 0.2545454545454546 0.27272727272727276 0.2909090909090909 0.3090909090909091 0.32727272727272727 0.34545454545454546 0.36363636363636365 0.38181818181818183 0.4 0.26666666666666666 0.28484848484848485 0.30303030303030304 0.3212121212121212 0.3393939393939394 0.35757575757575755 0.37575757575757573 0.3939393939393939 0.4121212121212121 0.4303030303030303 0.4484848484848485 0.4666666666666667 0.3333333333333333 0.3515151515151515 0.3696969696969697 0.3878787878787879 0.40606060606060607 0.4242424242424242 0.4424242424242424 0.4606060606060606 0.47878787878787876 0.49696969696969695 0.5151515151515151 0.5333333333333333 0.4 0.4181818181818182 0.4363636363636364 0.4545454545454546 0.4727272727272728 0.49090909090909096 0.5090909090909091 0.5272727272727273 0.5454545454545455 0.5636363636363637 0.5818181818181818 0.6000000000000001 0.4666666666666667 0.48484848484848486 0.503030303030303 0.5212121212121212 0.5393939393939394 0.5575757575757576 0.5757575757575758 0.593939393939394 0.6121212121212122 0.6303030303030304 0.6484848484848484 0.6666666666666667 0.5333333333333333 0.5515151515151515 0.5696969696969697 0.5878787878787879 0.6060606060606061 0.6242424242424243 0.6424242424242425 0.6606060606060606 0.6787878787878788 0.696969696969697 0.7151515151515151 0.7333333333333334 0.6 0.6181818181818182 0.6363636363636364 0.6545454545454545 0.6727272727272727 0.6909090909090909 0.7090909090909091 0.7272727272727273 0.7454545454545455 0.7636363636363637 0.7818181818181817 0.8 0.6666666666666666 0.6848484848484848 0.703030303030303 0.7212121212121212 0.7393939393939394 0.7575757575757576 0.7757575757575758 0.793939393939394 0.8121212121212121 0.8303030303030303 0.8484848484848484 0.8666666666666667 0.7333333333333333 0.7515151515151515 0.7696969696969697 0.7878787878787878 0.806060606060606 0.8242424242424242 0.8424242424242424 0.8606060606060606 0.8787878787878788 0.896969696969697 0.915151515151515 0.9333333333333333 0.8 0.8181818181818182 0.8363636363636364 0.8545454545454546 0.8727272727272728 0.890909090909091 0.9090909090909092 0.9272727272727274 0.9454545454545455 0.9636363636363637 0.9818181818181819 1.0 0.8666666666666667 0.8848484848484849 0.9030303030303031 0.9212121212121213 0.9393939393939394 0.9575757575757576 0.9757575757575758 0.993939393939394 1.0121212121212122 1.0303030303030303 1.0484848484848486 1.0666666666666667 0.9333333333333333 0.9515151515151515 0.9696969696969697 0.9878787878787879 1.006060606060606 1.0242424242424242 1.0424242424242425 1.0606060606060606 1.0787878787878789 1.096969696969697 1.1151515151515152 1.1333333333333333 1.0 1.018181818181818 1.0363636363636364 1.0545454545454545 1.0727272727272728 1.0909090909090908 1.1090909090909091 1.1272727272727272 1.1454545454545455 1.1636363636363636 1.1818181818181819 1.2; - 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.06666666666666667 0.06666666666666667 0.06666666666666667 0.06666666666666667 0.06666666666666667 0.06666666666666667 0.06666666666666667 0.06666666666666667 0.06666666666666667 0.06666666666666667 0.06666666666666667 0.06666666666666667 0.13333333333333333 0.13333333333333333 0.13333333333333333 0.13333333333333333 0.13333333333333333 0.13333333333333333 0.13333333333333333 0.13333333333333333 0.13333333333333333 0.13333333333333333 0.13333333333333333 0.13333333333333333 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.26666666666666666 0.26666666666666666 0.26666666666666666 0.26666666666666666 0.26666666666666666 0.26666666666666666 0.26666666666666666 0.26666666666666666 0.26666666666666666 0.26666666666666666 0.26666666666666666 0.26666666666666666 0.3333333333333333 0.3333333333333333 0.3333333333333333 0.3333333333333333 0.3333333333333333 0.3333333333333333 0.3333333333333333 0.3333333333333333 0.3333333333333333 0.3333333333333333 0.3333333333333333 0.3333333333333333 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4666666666666667 0.4666666666666667 0.4666666666666667 0.4666666666666667 0.4666666666666667 0.4666666666666667 0.4666666666666667 0.4666666666666667 0.4666666666666667 0.4666666666666667 0.4666666666666667 0.4666666666666667 0.5333333333333333 0.5333333333333333 0.5333333333333333 0.5333333333333333 0.5333333333333333 0.5333333333333333 0.5333333333333333 0.5333333333333333 0.5333333333333333 0.5333333333333333 0.5333333333333333 0.5333333333333333 0.6 0.6 0.6 0.6 0.6 0.6 0.6 0.6 0.6 0.6 0.6 0.6 0.6666666666666666 0.6666666666666666 0.6666666666666666 0.6666666666666666 0.6666666666666666 0.6666666666666666 0.6666666666666666 0.6666666666666666 0.6666666666666666 0.6666666666666666 0.6666666666666666 0.6666666666666666 0.7333333333333333 0.7333333333333333 0.7333333333333333 0.7333333333333333 0.7333333333333333 0.7333333333333333 0.7333333333333333 0.7333333333333333 0.7333333333333333 0.7333333333333333 0.7333333333333333 0.7333333333333333 0.8 0.8 0.8 0.8 0.8 0.8 0.8 0.8 0.8 0.8 0.8 0.8 0.8666666666666667 0.8666666666666667 0.8666666666666667 0.8666666666666667 0.8666666666666667 0.8666666666666667 0.8666666666666667 0.8666666666666667 0.8666666666666667 0.8666666666666667 0.8666666666666667 0.8666666666666667 0.9333333333333333 0.9333333333333333 0.9333333333333333 0.9333333333333333 0.9333333333333333 0.9333333333333333 0.9333333333333333 0.9333333333333333 0.9333333333333333 0.9333333333333333 0.9333333333333333 0.9333333333333333 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.16666666666666669 0.16666666666666669 0.16666666666666669 0.16666666666666669 0.16666666666666669 0.16666666666666669 0.16666666666666669 0.16666666666666669 0.16666666666666669 0.16666666666666669 0.16666666666666669 0.16666666666666669 0.23333333333333334 0.23333333333333334 0.23333333333333334 0.23333333333333334 0.23333333333333334 0.23333333333333334 0.23333333333333334 0.23333333333333334 0.23333333333333334 0.23333333333333334 0.23333333333333334 0.23333333333333334 0.30000000000000004 0.30000000000000004 0.30000000000000004 0.30000000000000004 0.30000000000000004 0.30000000000000004 0.30000000000000004 0.30000000000000004 0.30000000000000004 0.30000000000000004 0.30000000000000004 0.30000000000000004 0.3666666666666667 0.3666666666666667 0.3666666666666667 0.3666666666666667 0.3666666666666667 0.3666666666666667 0.3666666666666667 0.3666666666666667 0.3666666666666667 0.3666666666666667 0.3666666666666667 0.3666666666666667 0.43333333333333335 0.43333333333333335 0.43333333333333335 0.43333333333333335 0.43333333333333335 0.43333333333333335 0.43333333333333335 0.43333333333333335 0.43333333333333335 0.43333333333333335 0.43333333333333335 0.43333333333333335 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5666666666666667 0.5666666666666667 0.5666666666666667 0.5666666666666667 0.5666666666666667 0.5666666666666667 0.5666666666666667 0.5666666666666667 0.5666666666666667 0.5666666666666667 0.5666666666666667 0.5666666666666667 0.6333333333333333 0.6333333333333333 0.6333333333333333 0.6333333333333333 0.6333333333333333 0.6333333333333333 0.6333333333333333 0.6333333333333333 0.6333333333333333 0.6333333333333333 0.6333333333333333 0.6333333333333333 0.7 0.7 0.7 0.7 0.7 0.7 0.7 0.7 0.7 0.7 0.7 0.7 0.7666666666666666 0.7666666666666666 0.7666666666666666 0.7666666666666666 0.7666666666666666 0.7666666666666666 0.7666666666666666 0.7666666666666666 0.7666666666666666 0.7666666666666666 0.7666666666666666 0.7666666666666666 0.8333333333333333 0.8333333333333333 0.8333333333333333 0.8333333333333333 0.8333333333333333 0.8333333333333333 0.8333333333333333 0.8333333333333333 0.8333333333333333 0.8333333333333333 0.8333333333333333 0.8333333333333333 0.9 0.9 0.9 0.9 0.9 0.9 0.9 0.9 0.9 0.9 0.9 0.9 0.9666666666666667 0.9666666666666667 0.9666666666666667 0.9666666666666667 0.9666666666666667 0.9666666666666667 0.9666666666666667 0.9666666666666667 0.9666666666666667 0.9666666666666667 0.9666666666666667 0.9666666666666667 1.0333333333333334 1.0333333333333334 1.0333333333333334 1.0333333333333334 1.0333333333333334 1.0333333333333334 1.0333333333333334 1.0333333333333334 1.0333333333333334 1.0333333333333334 1.0333333333333334 1.0333333333333334 1.1 1.1 1.1 1.1 1.1 1.1 1.1 1.1 1.1 1.1 1.1 1.1 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.26666666666666666 0.26666666666666666 0.26666666666666666 0.26666666666666666 0.26666666666666666 0.26666666666666666 0.26666666666666666 0.26666666666666666 0.26666666666666666 0.26666666666666666 0.26666666666666666 0.26666666666666666 0.33333333333333337 0.33333333333333337 0.33333333333333337 0.33333333333333337 0.33333333333333337 0.33333333333333337 0.33333333333333337 0.33333333333333337 0.33333333333333337 0.33333333333333337 0.33333333333333337 0.33333333333333337 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4666666666666667 0.4666666666666667 0.4666666666666667 0.4666666666666667 0.4666666666666667 0.4666666666666667 0.4666666666666667 0.4666666666666667 0.4666666666666667 0.4666666666666667 0.4666666666666667 0.4666666666666667 0.5333333333333333 0.5333333333333333 0.5333333333333333 0.5333333333333333 0.5333333333333333 0.5333333333333333 0.5333333333333333 0.5333333333333333 0.5333333333333333 0.5333333333333333 0.5333333333333333 0.5333333333333333 0.6000000000000001 0.6000000000000001 0.6000000000000001 0.6000000000000001 0.6000000000000001 0.6000000000000001 0.6000000000000001 0.6000000000000001 0.6000000000000001 0.6000000000000001 0.6000000000000001 0.6000000000000001 0.6666666666666667 0.6666666666666667 0.6666666666666667 0.6666666666666667 0.6666666666666667 0.6666666666666667 0.6666666666666667 0.6666666666666667 0.6666666666666667 0.6666666666666667 0.6666666666666667 0.6666666666666667 0.7333333333333334 0.7333333333333334 0.7333333333333334 0.7333333333333334 0.7333333333333334 0.7333333333333334 0.7333333333333334 0.7333333333333334 0.7333333333333334 0.7333333333333334 0.7333333333333334 0.7333333333333334 0.8 0.8 0.8 0.8 0.8 0.8 0.8 0.8 0.8 0.8 0.8 0.8 0.8666666666666667 0.8666666666666667 0.8666666666666667 0.8666666666666667 0.8666666666666667 0.8666666666666667 0.8666666666666667 0.8666666666666667 0.8666666666666667 0.8666666666666667 0.8666666666666667 0.8666666666666667 0.9333333333333333 0.9333333333333333 0.9333333333333333 0.9333333333333333 0.9333333333333333 0.9333333333333333 0.9333333333333333 0.9333333333333333 0.9333333333333333 0.9333333333333333 0.9333333333333333 0.9333333333333333 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0666666666666667 1.0666666666666667 1.0666666666666667 1.0666666666666667 1.0666666666666667 1.0666666666666667 1.0666666666666667 1.0666666666666667 1.0666666666666667 1.0666666666666667 1.0666666666666667 1.0666666666666667 1.1333333333333333 1.1333333333333333 1.1333333333333333 1.1333333333333333 1.1333333333333333 1.1333333333333333 1.1333333333333333 1.1333333333333333 1.1333333333333333 1.1333333333333333 1.1333333333333333 1.1333333333333333 1.2 1.2 1.2 1.2 1.2 1.2 1.2 1.2 1.2 1.2 1.2 1.2 0.30000000000000004 0.30000000000000004 0.30000000000000004 0.30000000000000004 0.30000000000000004 0.30000000000000004 0.30000000000000004 0.30000000000000004 0.30000000000000004 0.30000000000000004 0.30000000000000004 0.30000000000000004 0.3666666666666667 0.3666666666666667 0.3666666666666667 0.3666666666666667 0.3666666666666667 0.3666666666666667 0.3666666666666667 0.3666666666666667 0.3666666666666667 0.3666666666666667 0.3666666666666667 0.3666666666666667 0.43333333333333335 0.43333333333333335 0.43333333333333335 0.43333333333333335 0.43333333333333335 0.43333333333333335 0.43333333333333335 0.43333333333333335 0.43333333333333335 0.43333333333333335 0.43333333333333335 0.43333333333333335 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5666666666666667 0.5666666666666667 0.5666666666666667 0.5666666666666667 0.5666666666666667 0.5666666666666667 0.5666666666666667 0.5666666666666667 0.5666666666666667 0.5666666666666667 0.5666666666666667 0.5666666666666667 0.6333333333333333 0.6333333333333333 0.6333333333333333 0.6333333333333333 0.6333333333333333 0.6333333333333333 0.6333333333333333 0.6333333333333333 0.6333333333333333 0.6333333333333333 0.6333333333333333 0.6333333333333333 0.7000000000000001 0.7000000000000001 0.7000000000000001 0.7000000000000001 0.7000000000000001 0.7000000000000001 0.7000000000000001 0.7000000000000001 0.7000000000000001 0.7000000000000001 0.7000000000000001 0.7000000000000001 0.7666666666666667 0.7666666666666667 0.7666666666666667 0.7666666666666667 0.7666666666666667 0.7666666666666667 0.7666666666666667 0.7666666666666667 0.7666666666666667 0.7666666666666667 0.7666666666666667 0.7666666666666667 0.8333333333333334 0.8333333333333334 0.8333333333333334 0.8333333333333334 0.8333333333333334 0.8333333333333334 0.8333333333333334 0.8333333333333334 0.8333333333333334 0.8333333333333334 0.8333333333333334 0.8333333333333334 0.9 0.9 0.9 0.9 0.9 0.9 0.9 0.9 0.9 0.9 0.9 0.9 0.9666666666666667 0.9666666666666667 0.9666666666666667 0.9666666666666667 0.9666666666666667 0.9666666666666667 0.9666666666666667 0.9666666666666667 0.9666666666666667 0.9666666666666667 0.9666666666666667 0.9666666666666667 1.0333333333333332 1.0333333333333332 1.0333333333333332 1.0333333333333332 1.0333333333333332 1.0333333333333332 1.0333333333333332 1.0333333333333332 1.0333333333333332 1.0333333333333332 1.0333333333333332 1.0333333333333332 1.1 1.1 1.1 1.1 1.1 1.1 1.1 1.1 1.1 1.1 1.1 1.1 1.1666666666666667 1.1666666666666667 1.1666666666666667 1.1666666666666667 1.1666666666666667 1.1666666666666667 1.1666666666666667 1.1666666666666667 1.1666666666666667 1.1666666666666667 1.1666666666666667 1.1666666666666667 1.2333333333333334 1.2333333333333334 1.2333333333333334 1.2333333333333334 1.2333333333333334 1.2333333333333334 1.2333333333333334 1.2333333333333334 1.2333333333333334 1.2333333333333334 1.2333333333333334 1.2333333333333334 1.3 1.3 1.3 1.3 1.3 1.3 1.3 1.3 1.3 1.3 1.3 1.3] + 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.06666666666666667 0.06666666666666667 0.06666666666666667 0.06666666666666667 0.06666666666666667 0.06666666666666667 0.06666666666666667 0.06666666666666667 0.06666666666666667 0.06666666666666667 0.06666666666666667 0.06666666666666667 0.13333333333333333 0.13333333333333333 0.13333333333333333 0.13333333333333333 0.13333333333333333 0.13333333333333333 0.13333333333333333 0.13333333333333333 0.13333333333333333 0.13333333333333333 0.13333333333333333 0.13333333333333333 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.26666666666666666 0.26666666666666666 0.26666666666666666 0.26666666666666666 0.26666666666666666 0.26666666666666666 0.26666666666666666 0.26666666666666666 0.26666666666666666 0.26666666666666666 0.26666666666666666 0.26666666666666666 0.3333333333333333 0.3333333333333333 0.3333333333333333 0.3333333333333333 0.3333333333333333 0.3333333333333333 0.3333333333333333 0.3333333333333333 0.3333333333333333 0.3333333333333333 0.3333333333333333 0.3333333333333333 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4666666666666667 0.4666666666666667 0.4666666666666667 0.4666666666666667 0.4666666666666667 0.4666666666666667 0.4666666666666667 0.4666666666666667 0.4666666666666667 0.4666666666666667 0.4666666666666667 0.4666666666666667 0.5333333333333333 0.5333333333333333 0.5333333333333333 0.5333333333333333 0.5333333333333333 0.5333333333333333 0.5333333333333333 0.5333333333333333 0.5333333333333333 0.5333333333333333 0.5333333333333333 0.5333333333333333 0.6 0.6 0.6 0.6 0.6 0.6 0.6 0.6 0.6 0.6 0.6 0.6 0.6666666666666666 0.6666666666666666 0.6666666666666666 0.6666666666666666 0.6666666666666666 0.6666666666666666 0.6666666666666666 0.6666666666666666 0.6666666666666666 0.6666666666666666 0.6666666666666666 0.6666666666666666 0.7333333333333333 0.7333333333333333 0.7333333333333333 0.7333333333333333 0.7333333333333333 0.7333333333333333 0.7333333333333333 0.7333333333333333 0.7333333333333333 0.7333333333333333 0.7333333333333333 0.7333333333333333 0.8 0.8 0.8 0.8 0.8 0.8 0.8 0.8 0.8 0.8 0.8 0.8 0.8666666666666667 0.8666666666666667 0.8666666666666667 0.8666666666666667 0.8666666666666667 0.8666666666666667 0.8666666666666667 0.8666666666666667 0.8666666666666667 0.8666666666666667 0.8666666666666667 0.8666666666666667 0.9333333333333333 0.9333333333333333 0.9333333333333333 0.9333333333333333 0.9333333333333333 0.9333333333333333 0.9333333333333333 0.9333333333333333 0.9333333333333333 0.9333333333333333 0.9333333333333333 0.9333333333333333 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 0.092709445701687 0.092709445701687 0.092709445701687 0.092709445701687 0.092709445701687 0.092709445701687 0.092709445701687 0.092709445701687 0.092709445701687 0.092709445701687 0.092709445701687 0.092709445701687 0.15937611236835367 0.15937611236835367 0.15937611236835367 0.15937611236835367 0.15937611236835367 0.15937611236835367 0.15937611236835367 0.15937611236835367 0.15937611236835367 0.15937611236835367 0.15937611236835367 0.15937611236835367 0.22604277903502035 0.22604277903502035 0.22604277903502035 0.22604277903502035 0.22604277903502035 0.22604277903502035 0.22604277903502035 0.22604277903502035 0.22604277903502035 0.22604277903502035 0.22604277903502035 0.22604277903502035 0.292709445701687 0.292709445701687 0.292709445701687 0.292709445701687 0.292709445701687 0.292709445701687 0.292709445701687 0.292709445701687 0.292709445701687 0.292709445701687 0.292709445701687 0.292709445701687 0.35937611236835365 0.35937611236835365 0.35937611236835365 0.35937611236835365 0.35937611236835365 0.35937611236835365 0.35937611236835365 0.35937611236835365 0.35937611236835365 0.35937611236835365 0.35937611236835365 0.35937611236835365 0.4260427790350203 0.4260427790350203 0.4260427790350203 0.4260427790350203 0.4260427790350203 0.4260427790350203 0.4260427790350203 0.4260427790350203 0.4260427790350203 0.4260427790350203 0.4260427790350203 0.4260427790350203 0.492709445701687 0.492709445701687 0.492709445701687 0.492709445701687 0.492709445701687 0.492709445701687 0.492709445701687 0.492709445701687 0.492709445701687 0.492709445701687 0.492709445701687 0.492709445701687 0.5593761123683537 0.5593761123683537 0.5593761123683537 0.5593761123683537 0.5593761123683537 0.5593761123683537 0.5593761123683537 0.5593761123683537 0.5593761123683537 0.5593761123683537 0.5593761123683537 0.5593761123683537 0.6260427790350204 0.6260427790350204 0.6260427790350204 0.6260427790350204 0.6260427790350204 0.6260427790350204 0.6260427790350204 0.6260427790350204 0.6260427790350204 0.6260427790350204 0.6260427790350204 0.6260427790350204 0.692709445701687 0.692709445701687 0.692709445701687 0.692709445701687 0.692709445701687 0.692709445701687 0.692709445701687 0.692709445701687 0.692709445701687 0.692709445701687 0.692709445701687 0.692709445701687 0.7593761123683537 0.7593761123683537 0.7593761123683537 0.7593761123683537 0.7593761123683537 0.7593761123683537 0.7593761123683537 0.7593761123683537 0.7593761123683537 0.7593761123683537 0.7593761123683537 0.7593761123683537 0.8260427790350203 0.8260427790350203 0.8260427790350203 0.8260427790350203 0.8260427790350203 0.8260427790350203 0.8260427790350203 0.8260427790350203 0.8260427790350203 0.8260427790350203 0.8260427790350203 0.8260427790350203 0.8927094457016871 0.8927094457016871 0.8927094457016871 0.8927094457016871 0.8927094457016871 0.8927094457016871 0.8927094457016871 0.8927094457016871 0.8927094457016871 0.8927094457016871 0.8927094457016871 0.8927094457016871 0.9593761123683537 0.9593761123683537 0.9593761123683537 0.9593761123683537 0.9593761123683537 0.9593761123683537 0.9593761123683537 0.9593761123683537 0.9593761123683537 0.9593761123683537 0.9593761123683537 0.9593761123683537 1.0260427790350204 1.0260427790350204 1.0260427790350204 1.0260427790350204 1.0260427790350204 1.0260427790350204 1.0260427790350204 1.0260427790350204 1.0260427790350204 1.0260427790350204 1.0260427790350204 1.0260427790350204 1.092709445701687 1.092709445701687 1.092709445701687 1.092709445701687 1.092709445701687 1.092709445701687 1.092709445701687 1.092709445701687 1.092709445701687 1.092709445701687 1.092709445701687 1.092709445701687 0.185418891403374 0.185418891403374 0.185418891403374 0.185418891403374 0.185418891403374 0.185418891403374 0.185418891403374 0.185418891403374 0.185418891403374 0.185418891403374 0.185418891403374 0.185418891403374 0.2520855580700407 0.2520855580700407 0.2520855580700407 0.2520855580700407 0.2520855580700407 0.2520855580700407 0.2520855580700407 0.2520855580700407 0.2520855580700407 0.2520855580700407 0.2520855580700407 0.2520855580700407 0.31875222473670733 0.31875222473670733 0.31875222473670733 0.31875222473670733 0.31875222473670733 0.31875222473670733 0.31875222473670733 0.31875222473670733 0.31875222473670733 0.31875222473670733 0.31875222473670733 0.31875222473670733 0.38541889140337404 0.38541889140337404 0.38541889140337404 0.38541889140337404 0.38541889140337404 0.38541889140337404 0.38541889140337404 0.38541889140337404 0.38541889140337404 0.38541889140337404 0.38541889140337404 0.38541889140337404 0.4520855580700407 0.4520855580700407 0.4520855580700407 0.4520855580700407 0.4520855580700407 0.4520855580700407 0.4520855580700407 0.4520855580700407 0.4520855580700407 0.4520855580700407 0.4520855580700407 0.4520855580700407 0.5187522247367073 0.5187522247367073 0.5187522247367073 0.5187522247367073 0.5187522247367073 0.5187522247367073 0.5187522247367073 0.5187522247367073 0.5187522247367073 0.5187522247367073 0.5187522247367073 0.5187522247367073 0.585418891403374 0.585418891403374 0.585418891403374 0.585418891403374 0.585418891403374 0.585418891403374 0.585418891403374 0.585418891403374 0.585418891403374 0.585418891403374 0.585418891403374 0.585418891403374 0.6520855580700406 0.6520855580700406 0.6520855580700406 0.6520855580700406 0.6520855580700406 0.6520855580700406 0.6520855580700406 0.6520855580700406 0.6520855580700406 0.6520855580700406 0.6520855580700406 0.6520855580700406 0.7187522247367073 0.7187522247367073 0.7187522247367073 0.7187522247367073 0.7187522247367073 0.7187522247367073 0.7187522247367073 0.7187522247367073 0.7187522247367073 0.7187522247367073 0.7187522247367073 0.7187522247367073 0.785418891403374 0.785418891403374 0.785418891403374 0.785418891403374 0.785418891403374 0.785418891403374 0.785418891403374 0.785418891403374 0.785418891403374 0.785418891403374 0.785418891403374 0.785418891403374 0.8520855580700406 0.8520855580700406 0.8520855580700406 0.8520855580700406 0.8520855580700406 0.8520855580700406 0.8520855580700406 0.8520855580700406 0.8520855580700406 0.8520855580700406 0.8520855580700406 0.8520855580700406 0.9187522247367073 0.9187522247367073 0.9187522247367073 0.9187522247367073 0.9187522247367073 0.9187522247367073 0.9187522247367073 0.9187522247367073 0.9187522247367073 0.9187522247367073 0.9187522247367073 0.9187522247367073 0.985418891403374 0.985418891403374 0.985418891403374 0.985418891403374 0.985418891403374 0.985418891403374 0.985418891403374 0.985418891403374 0.985418891403374 0.985418891403374 0.985418891403374 0.985418891403374 1.0520855580700408 1.0520855580700408 1.0520855580700408 1.0520855580700408 1.0520855580700408 1.0520855580700408 1.0520855580700408 1.0520855580700408 1.0520855580700408 1.0520855580700408 1.0520855580700408 1.0520855580700408 1.1187522247367074 1.1187522247367074 1.1187522247367074 1.1187522247367074 1.1187522247367074 1.1187522247367074 1.1187522247367074 1.1187522247367074 1.1187522247367074 1.1187522247367074 1.1187522247367074 1.1187522247367074 1.185418891403374 1.185418891403374 1.185418891403374 1.185418891403374 1.185418891403374 1.185418891403374 1.185418891403374 1.185418891403374 1.185418891403374 1.185418891403374 1.185418891403374 1.185418891403374 0.278128337105061 0.278128337105061 0.278128337105061 0.278128337105061 0.278128337105061 0.278128337105061 0.278128337105061 0.278128337105061 0.278128337105061 0.278128337105061 0.278128337105061 0.278128337105061 0.34479500377172767 0.34479500377172767 0.34479500377172767 0.34479500377172767 0.34479500377172767 0.34479500377172767 0.34479500377172767 0.34479500377172767 0.34479500377172767 0.34479500377172767 0.34479500377172767 0.34479500377172767 0.4114616704383943 0.4114616704383943 0.4114616704383943 0.4114616704383943 0.4114616704383943 0.4114616704383943 0.4114616704383943 0.4114616704383943 0.4114616704383943 0.4114616704383943 0.4114616704383943 0.4114616704383943 0.47812833710506103 0.47812833710506103 0.47812833710506103 0.47812833710506103 0.47812833710506103 0.47812833710506103 0.47812833710506103 0.47812833710506103 0.47812833710506103 0.47812833710506103 0.47812833710506103 0.47812833710506103 0.5447950037717277 0.5447950037717277 0.5447950037717277 0.5447950037717277 0.5447950037717277 0.5447950037717277 0.5447950037717277 0.5447950037717277 0.5447950037717277 0.5447950037717277 0.5447950037717277 0.5447950037717277 0.6114616704383944 0.6114616704383944 0.6114616704383944 0.6114616704383944 0.6114616704383944 0.6114616704383944 0.6114616704383944 0.6114616704383944 0.6114616704383944 0.6114616704383944 0.6114616704383944 0.6114616704383944 0.678128337105061 0.678128337105061 0.678128337105061 0.678128337105061 0.678128337105061 0.678128337105061 0.678128337105061 0.678128337105061 0.678128337105061 0.678128337105061 0.678128337105061 0.678128337105061 0.7447950037717277 0.7447950037717277 0.7447950037717277 0.7447950037717277 0.7447950037717277 0.7447950037717277 0.7447950037717277 0.7447950037717277 0.7447950037717277 0.7447950037717277 0.7447950037717277 0.7447950037717277 0.8114616704383943 0.8114616704383943 0.8114616704383943 0.8114616704383943 0.8114616704383943 0.8114616704383943 0.8114616704383943 0.8114616704383943 0.8114616704383943 0.8114616704383943 0.8114616704383943 0.8114616704383943 0.878128337105061 0.878128337105061 0.878128337105061 0.878128337105061 0.878128337105061 0.878128337105061 0.878128337105061 0.878128337105061 0.878128337105061 0.878128337105061 0.878128337105061 0.878128337105061 0.9447950037717276 0.9447950037717276 0.9447950037717276 0.9447950037717276 0.9447950037717276 0.9447950037717276 0.9447950037717276 0.9447950037717276 0.9447950037717276 0.9447950037717276 0.9447950037717276 0.9447950037717276 1.0114616704383943 1.0114616704383943 1.0114616704383943 1.0114616704383943 1.0114616704383943 1.0114616704383943 1.0114616704383943 1.0114616704383943 1.0114616704383943 1.0114616704383943 1.0114616704383943 1.0114616704383943 1.0781283371050612 1.0781283371050612 1.0781283371050612 1.0781283371050612 1.0781283371050612 1.0781283371050612 1.0781283371050612 1.0781283371050612 1.0781283371050612 1.0781283371050612 1.0781283371050612 1.0781283371050612 1.1447950037717276 1.1447950037717276 1.1447950037717276 1.1447950037717276 1.1447950037717276 1.1447950037717276 1.1447950037717276 1.1447950037717276 1.1447950037717276 1.1447950037717276 1.1447950037717276 1.1447950037717276 1.2114616704383945 1.2114616704383945 1.2114616704383945 1.2114616704383945 1.2114616704383945 1.2114616704383945 1.2114616704383945 1.2114616704383945 1.2114616704383945 1.2114616704383945 1.2114616704383945 1.2114616704383945 1.278128337105061 1.278128337105061 1.278128337105061 1.278128337105061 1.278128337105061 1.278128337105061 1.278128337105061 1.278128337105061 1.278128337105061 1.278128337105061 1.278128337105061 1.278128337105061] shape = ExtrudeGeometry((p1, p2, p3); direction, particle_spacing=0.1, n_extrude=3, density=1000.0) - @test shape.coordinates == expected_coords + @test shape.coordinates ≈ expected_coords + end + + @testset verbose=true "Shifted Particles" begin + p1 = [0.0, 0.0, 0.0] + p2 = [0.5, 1.0, 0.0] + p3 = [1.0, 0.2, 0.0] + + direction = [0.0, 0.0, 1.0] + + expected_coords = [0.0713897135595439 0.1615839068026347 0.25177810004572554 0.3419722932888163 0.43216648653190715 0.5223606797749979 0.6125548730180886 0.7027490662611794 0.7929432595042704 0.8831374527473611 0.9733316459904519 0.11277868087318066 0.20297287411627146 0.29316706735936227 0.383361260602453 0.47355545384554387 0.5637496470886346 0.6539438403317254 0.7441380335748161 0.8343322268179071 0.9245264200609978 1.0147206133040885 0.15416764818681739 0.2443618414299082 0.334556034672999 0.42475022791608974 0.5149444211591806 0.6051386144022713 0.6953328076453621 0.7855270008884528 0.8757211941315438 0.9659153873746346 1.0561095806177252 0.19555661550045414 0.28575080874354497 0.3759450019866357 0.46613919522972647 0.5563333884728173 0.6465275817159081 0.7367217749589988 0.8269159682020896 0.9171101614451805 1.0073043546882714 1.0974985479313621 0.2369455828140909 0.3271397760571817 0.4173339693002725 0.5075281625433632 0.5977223557864542 0.6879165490295449 0.7781107422726357 0.8683049355157264 0.9584991287588174 1.0486933220019081 1.1388875152449989 0.2783345501277276 0.3685287433708184 0.4587229366139092 0.5489171298569999 0.6391113231000909 0.7293055163431816 0.8194997095862724 0.9096939028293631 0.9998880960724541 1.0900822893155449 1.1802764825586356 0.3197235174413644 0.4099177106844552 0.500111903927546 0.5903060971706368 0.6805002904137276 0.7706944836568184 0.8608886768999091 0.9510828701429999 1.0412770633860908 1.1314712566291816 1.2216654498722723 0.36111248475500113 0.45130667799809193 0.5415008712411827 0.6316950644842735 0.7218892577273643 0.8120834509704551 0.9022776442135458 0.9924718374566366 1.0826660306997276 1.1728602239428183 1.263054417185909 0.40250145206863785 0.49269564531172866 0.5828898385548195 0.6730840317979102 0.7632782250410011 0.8534724182840918 0.9436666115271826 1.0338608047702733 1.1240549980133643 1.214249191256455 1.3044433844995458 0.4438904193822747 0.5340846126253656 0.6242788058684563 0.714472999111547 0.8046671923546379 0.8948613855977287 0.9850555788408194 1.07524977208391 1.1654439653270012 1.255638158570092 1.3458323518131827 0.4852793866959113 0.5754735799390021 0.6656677731820929 0.7558619664251837 0.8460561596682745 0.9362503529113653 1.026444546154456 1.1166387393975468 1.2068329326406377 1.2970271258837285 1.3872213191268192 0.5266683540095481 0.616862547252639 0.7070567404957298 0.7972509337388205 0.8874451269819114 0.9776393202250021 1.0678335134680927 1.1580277067111835 1.2482218999542747 1.3384160931973654 1.4286102864404562 0.0713897135595439 0.1615839068026347 0.25177810004572554 0.3419722932888163 0.43216648653190715 0.5223606797749979 0.6125548730180886 0.7027490662611794 0.7929432595042704 0.8831374527473611 0.9733316459904519 0.11277868087318066 0.20297287411627146 0.29316706735936227 0.383361260602453 0.47355545384554387 0.5637496470886346 0.6539438403317254 0.7441380335748161 0.8343322268179071 0.9245264200609978 1.0147206133040885 0.15416764818681739 0.2443618414299082 0.334556034672999 0.42475022791608974 0.5149444211591806 0.6051386144022713 0.6953328076453621 0.7855270008884528 0.8757211941315438 0.9659153873746346 1.0561095806177252 0.19555661550045414 0.28575080874354497 0.3759450019866357 0.46613919522972647 0.5563333884728173 0.6465275817159081 0.7367217749589988 0.8269159682020896 0.9171101614451805 1.0073043546882714 1.0974985479313621 0.2369455828140909 0.3271397760571817 0.4173339693002725 0.5075281625433632 0.5977223557864542 0.6879165490295449 0.7781107422726357 0.8683049355157264 0.9584991287588174 1.0486933220019081 1.1388875152449989 0.2783345501277276 0.3685287433708184 0.4587229366139092 0.5489171298569999 0.6391113231000909 0.7293055163431816 0.8194997095862724 0.9096939028293631 0.9998880960724541 1.0900822893155449 1.1802764825586356 0.3197235174413644 0.4099177106844552 0.500111903927546 0.5903060971706368 0.6805002904137276 0.7706944836568184 0.8608886768999091 0.9510828701429999 1.0412770633860908 1.1314712566291816 1.2216654498722723 0.36111248475500113 0.45130667799809193 0.5415008712411827 0.6316950644842735 0.7218892577273643 0.8120834509704551 0.9022776442135458 0.9924718374566366 1.0826660306997276 1.1728602239428183 1.263054417185909 0.40250145206863785 0.49269564531172866 0.5828898385548195 0.6730840317979102 0.7632782250410011 0.8534724182840918 0.9436666115271826 1.0338608047702733 1.1240549980133643 1.214249191256455 1.3044433844995458 0.4438904193822747 0.5340846126253656 0.6242788058684563 0.714472999111547 0.8046671923546379 0.8948613855977287 0.9850555788408194 1.07524977208391 1.1654439653270012 1.255638158570092 1.3458323518131827 0.4852793866959113 0.5754735799390021 0.6656677731820929 0.7558619664251837 0.8460561596682745 0.9362503529113653 1.026444546154456 1.1166387393975468 1.2068329326406377 1.2970271258837285 1.3872213191268192 0.5266683540095481 0.616862547252639 0.7070567404957298 0.7972509337388205 0.8874451269819114 0.9776393202250021 1.0678335134680927 1.1580277067111835 1.2482218999542747 1.3384160931973654 1.4286102864404562 0.0713897135595439 0.1615839068026347 0.25177810004572554 0.3419722932888163 0.43216648653190715 0.5223606797749979 0.6125548730180886 0.7027490662611794 0.7929432595042704 0.8831374527473611 0.9733316459904519 0.11277868087318066 0.20297287411627146 0.29316706735936227 0.383361260602453 0.47355545384554387 0.5637496470886346 0.6539438403317254 0.7441380335748161 0.8343322268179071 0.9245264200609978 1.0147206133040885 0.15416764818681739 0.2443618414299082 0.334556034672999 0.42475022791608974 0.5149444211591806 0.6051386144022713 0.6953328076453621 0.7855270008884528 0.8757211941315438 0.9659153873746346 1.0561095806177252 0.19555661550045414 0.28575080874354497 0.3759450019866357 0.46613919522972647 0.5563333884728173 0.6465275817159081 0.7367217749589988 0.8269159682020896 0.9171101614451805 1.0073043546882714 1.0974985479313621 0.2369455828140909 0.3271397760571817 0.4173339693002725 0.5075281625433632 0.5977223557864542 0.6879165490295449 0.7781107422726357 0.8683049355157264 0.9584991287588174 1.0486933220019081 1.1388875152449989 0.2783345501277276 0.3685287433708184 0.4587229366139092 0.5489171298569999 0.6391113231000909 0.7293055163431816 0.8194997095862724 0.9096939028293631 0.9998880960724541 1.0900822893155449 1.1802764825586356 0.3197235174413644 0.4099177106844552 0.500111903927546 0.5903060971706368 0.6805002904137276 0.7706944836568184 0.8608886768999091 0.9510828701429999 1.0412770633860908 1.1314712566291816 1.2216654498722723 0.36111248475500113 0.45130667799809193 0.5415008712411827 0.6316950644842735 0.7218892577273643 0.8120834509704551 0.9022776442135458 0.9924718374566366 1.0826660306997276 1.1728602239428183 1.263054417185909 0.40250145206863785 0.49269564531172866 0.5828898385548195 0.6730840317979102 0.7632782250410011 0.8534724182840918 0.9436666115271826 1.0338608047702733 1.1240549980133643 1.214249191256455 1.3044433844995458 0.4438904193822747 0.5340846126253656 0.6242788058684563 0.714472999111547 0.8046671923546379 0.8948613855977287 0.9850555788408194 1.07524977208391 1.1654439653270012 1.255638158570092 1.3458323518131827 0.4852793866959113 0.5754735799390021 0.6656677731820929 0.7558619664251837 0.8460561596682745 0.9362503529113653 1.026444546154456 1.1166387393975468 1.2068329326406377 1.2970271258837285 1.3872213191268192 0.5266683540095481 0.616862547252639 0.7070567404957298 0.7972509337388205 0.8874451269819114 0.9776393202250021 1.0678335134680927 1.1580277067111835 1.2482218999542747 1.3384160931973654 1.4286102864404562 0.0713897135595439 0.1615839068026347 0.25177810004572554 0.3419722932888163 0.43216648653190715 0.5223606797749979 0.6125548730180886 0.7027490662611794 0.7929432595042704 0.8831374527473611 0.9733316459904519 0.11277868087318066 0.20297287411627146 0.29316706735936227 0.383361260602453 0.47355545384554387 0.5637496470886346 0.6539438403317254 0.7441380335748161 0.8343322268179071 0.9245264200609978 1.0147206133040885 0.15416764818681739 0.2443618414299082 0.334556034672999 0.42475022791608974 0.5149444211591806 0.6051386144022713 0.6953328076453621 0.7855270008884528 0.8757211941315438 0.9659153873746346 1.0561095806177252 0.19555661550045414 0.28575080874354497 0.3759450019866357 0.46613919522972647 0.5563333884728173 0.6465275817159081 0.7367217749589988 0.8269159682020896 0.9171101614451805 1.0073043546882714 1.0974985479313621 0.2369455828140909 0.3271397760571817 0.4173339693002725 0.5075281625433632 0.5977223557864542 0.6879165490295449 0.7781107422726357 0.8683049355157264 0.9584991287588174 1.0486933220019081 1.1388875152449989 0.2783345501277276 0.3685287433708184 0.4587229366139092 0.5489171298569999 0.6391113231000909 0.7293055163431816 0.8194997095862724 0.9096939028293631 0.9998880960724541 1.0900822893155449 1.1802764825586356 0.3197235174413644 0.4099177106844552 0.500111903927546 0.5903060971706368 0.6805002904137276 0.7706944836568184 0.8608886768999091 0.9510828701429999 1.0412770633860908 1.1314712566291816 1.2216654498722723 0.36111248475500113 0.45130667799809193 0.5415008712411827 0.6316950644842735 0.7218892577273643 0.8120834509704551 0.9022776442135458 0.9924718374566366 1.0826660306997276 1.1728602239428183 1.263054417185909 0.40250145206863785 0.49269564531172866 0.5828898385548195 0.6730840317979102 0.7632782250410011 0.8534724182840918 0.9436666115271826 1.0338608047702733 1.1240549980133643 1.214249191256455 1.3044433844995458 0.4438904193822747 0.5340846126253656 0.6242788058684563 0.714472999111547 0.8046671923546379 0.8948613855977287 0.9850555788408194 1.07524977208391 1.1654439653270012 1.255638158570092 1.3458323518131827 0.4852793866959113 0.5754735799390021 0.6656677731820929 0.7558619664251837 0.8460561596682745 0.9362503529113653 1.026444546154456 1.1166387393975468 1.2068329326406377 1.2970271258837285 1.3872213191268192 0.5266683540095481 0.616862547252639 0.7070567404957298 0.7972509337388205 0.8874451269819114 0.9776393202250021 1.0678335134680927 1.1580277067111835 1.2482218999542747 1.3384160931973654 1.4286102864404562; + 0.054527166306904996 0.07256600495552315 0.09060484360414131 0.10864368225275947 0.12668252090137763 0.1447213595499958 0.16276019819861395 0.18079903684723211 0.19883787549585027 0.21687671414446844 0.2349155527930866 0.1373051009341785 0.15534393958279666 0.17338277823141482 0.19142161688003298 0.20946045552865114 0.2274992941772693 0.24553813282588746 0.26357697147450565 0.28161581012312376 0.29965464877174197 0.3176934874203601 0.22008303556145198 0.23812187421007014 0.2561607128586883 0.27419955150730646 0.2922383901559246 0.3102772288045428 0.32831606745316094 0.3463549061017791 0.36439374475039726 0.3824325833990154 0.4004714220476336 0.3028609701887255 0.32089980883734365 0.3389386474859618 0.35697748613457997 0.37501632478319813 0.3930551634318163 0.41109400208043445 0.4291328407290526 0.44717167937767077 0.46521051802628893 0.4832493566749071 0.385638904815999 0.40367774346461716 0.4217165821132353 0.4397554207618535 0.45779425941047164 0.4758330980590898 0.49387193670770796 0.5119107753563261 0.5299496140049442 0.5479884526535624 0.5660272913021807 0.46841683944327245 0.4864556780918906 0.5044945167405088 0.5225333553891269 0.540572194037745 0.5586110326863633 0.5766498713349815 0.5946887099835996 0.6127275486322177 0.6307663872808359 0.6488052259294541 0.551194774070546 0.5692336127191642 0.5872724513677823 0.6053112900164004 0.6233501286650186 0.6413889673136368 0.6594278059622549 0.677466644610873 0.6955054832594912 0.7135443219081095 0.7315831605567276 0.6339727086978194 0.6520115473464376 0.6700503859950557 0.6880892246436738 0.706128063292292 0.7241669019409103 0.7422057405895284 0.7602445792381465 0.7782834178867647 0.7963222565353829 0.814361095184001 0.716750643325093 0.7347894819737111 0.7528283206223293 0.7708671592709475 0.7889059979195656 0.8069448365681837 0.8249836752168019 0.8430225138654202 0.8610613525140383 0.8791001911626564 0.8971390298112746 0.7995285779523665 0.8175674166009848 0.8356062552496029 0.853645093898221 0.8716839325468392 0.8897227711954574 0.9077616098440755 0.9258004484926936 0.9438392871413118 0.96187812578993 0.9799169644385481 0.8823065125796399 0.900345351228258 0.9183841898768762 0.9364230285254944 0.9544618671741125 0.9725007058227306 0.9905395444713488 1.008578383119967 1.0266172217685852 1.0446560604172033 1.0626948990658214 0.9650844472069134 0.9831232858555317 1.0011621245041498 1.0192009631527679 1.0372398018013862 1.0552786404500043 1.0733174790986224 1.0913563177472405 1.1093951563958586 1.127433995044477 1.145472833693095 0.054527166306904996 0.07256600495552315 0.09060484360414131 0.10864368225275947 0.12668252090137763 0.1447213595499958 0.16276019819861395 0.18079903684723211 0.19883787549585027 0.21687671414446844 0.2349155527930866 0.1373051009341785 0.15534393958279666 0.17338277823141482 0.19142161688003298 0.20946045552865114 0.2274992941772693 0.24553813282588746 0.26357697147450565 0.28161581012312376 0.29965464877174197 0.3176934874203601 0.22008303556145198 0.23812187421007014 0.2561607128586883 0.27419955150730646 0.2922383901559246 0.3102772288045428 0.32831606745316094 0.3463549061017791 0.36439374475039726 0.3824325833990154 0.4004714220476336 0.3028609701887255 0.32089980883734365 0.3389386474859618 0.35697748613457997 0.37501632478319813 0.3930551634318163 0.41109400208043445 0.4291328407290526 0.44717167937767077 0.46521051802628893 0.4832493566749071 0.385638904815999 0.40367774346461716 0.4217165821132353 0.4397554207618535 0.45779425941047164 0.4758330980590898 0.49387193670770796 0.5119107753563261 0.5299496140049442 0.5479884526535624 0.5660272913021807 0.46841683944327245 0.4864556780918906 0.5044945167405088 0.5225333553891269 0.540572194037745 0.5586110326863633 0.5766498713349815 0.5946887099835996 0.6127275486322177 0.6307663872808359 0.6488052259294541 0.551194774070546 0.5692336127191642 0.5872724513677823 0.6053112900164004 0.6233501286650186 0.6413889673136368 0.6594278059622549 0.677466644610873 0.6955054832594912 0.7135443219081095 0.7315831605567276 0.6339727086978194 0.6520115473464376 0.6700503859950557 0.6880892246436738 0.706128063292292 0.7241669019409103 0.7422057405895284 0.7602445792381465 0.7782834178867647 0.7963222565353829 0.814361095184001 0.716750643325093 0.7347894819737111 0.7528283206223293 0.7708671592709475 0.7889059979195656 0.8069448365681837 0.8249836752168019 0.8430225138654202 0.8610613525140383 0.8791001911626564 0.8971390298112746 0.7995285779523665 0.8175674166009848 0.8356062552496029 0.853645093898221 0.8716839325468392 0.8897227711954574 0.9077616098440755 0.9258004484926936 0.9438392871413118 0.96187812578993 0.9799169644385481 0.8823065125796399 0.900345351228258 0.9183841898768762 0.9364230285254944 0.9544618671741125 0.9725007058227306 0.9905395444713488 1.008578383119967 1.0266172217685852 1.0446560604172033 1.0626948990658214 0.9650844472069134 0.9831232858555317 1.0011621245041498 1.0192009631527679 1.0372398018013862 1.0552786404500043 1.0733174790986224 1.0913563177472405 1.1093951563958586 1.127433995044477 1.145472833693095 0.054527166306904996 0.07256600495552315 0.09060484360414131 0.10864368225275947 0.12668252090137763 0.1447213595499958 0.16276019819861395 0.18079903684723211 0.19883787549585027 0.21687671414446844 0.2349155527930866 0.1373051009341785 0.15534393958279666 0.17338277823141482 0.19142161688003298 0.20946045552865114 0.2274992941772693 0.24553813282588746 0.26357697147450565 0.28161581012312376 0.29965464877174197 0.3176934874203601 0.22008303556145198 0.23812187421007014 0.2561607128586883 0.27419955150730646 0.2922383901559246 0.3102772288045428 0.32831606745316094 0.3463549061017791 0.36439374475039726 0.3824325833990154 0.4004714220476336 0.3028609701887255 0.32089980883734365 0.3389386474859618 0.35697748613457997 0.37501632478319813 0.3930551634318163 0.41109400208043445 0.4291328407290526 0.44717167937767077 0.46521051802628893 0.4832493566749071 0.385638904815999 0.40367774346461716 0.4217165821132353 0.4397554207618535 0.45779425941047164 0.4758330980590898 0.49387193670770796 0.5119107753563261 0.5299496140049442 0.5479884526535624 0.5660272913021807 0.46841683944327245 0.4864556780918906 0.5044945167405088 0.5225333553891269 0.540572194037745 0.5586110326863633 0.5766498713349815 0.5946887099835996 0.6127275486322177 0.6307663872808359 0.6488052259294541 0.551194774070546 0.5692336127191642 0.5872724513677823 0.6053112900164004 0.6233501286650186 0.6413889673136368 0.6594278059622549 0.677466644610873 0.6955054832594912 0.7135443219081095 0.7315831605567276 0.6339727086978194 0.6520115473464376 0.6700503859950557 0.6880892246436738 0.706128063292292 0.7241669019409103 0.7422057405895284 0.7602445792381465 0.7782834178867647 0.7963222565353829 0.814361095184001 0.716750643325093 0.7347894819737111 0.7528283206223293 0.7708671592709475 0.7889059979195656 0.8069448365681837 0.8249836752168019 0.8430225138654202 0.8610613525140383 0.8791001911626564 0.8971390298112746 0.7995285779523665 0.8175674166009848 0.8356062552496029 0.853645093898221 0.8716839325468392 0.8897227711954574 0.9077616098440755 0.9258004484926936 0.9438392871413118 0.96187812578993 0.9799169644385481 0.8823065125796399 0.900345351228258 0.9183841898768762 0.9364230285254944 0.9544618671741125 0.9725007058227306 0.9905395444713488 1.008578383119967 1.0266172217685852 1.0446560604172033 1.0626948990658214 0.9650844472069134 0.9831232858555317 1.0011621245041498 1.0192009631527679 1.0372398018013862 1.0552786404500043 1.0733174790986224 1.0913563177472405 1.1093951563958586 1.127433995044477 1.145472833693095 0.054527166306904996 0.07256600495552315 0.09060484360414131 0.10864368225275947 0.12668252090137763 0.1447213595499958 0.16276019819861395 0.18079903684723211 0.19883787549585027 0.21687671414446844 0.2349155527930866 0.1373051009341785 0.15534393958279666 0.17338277823141482 0.19142161688003298 0.20946045552865114 0.2274992941772693 0.24553813282588746 0.26357697147450565 0.28161581012312376 0.29965464877174197 0.3176934874203601 0.22008303556145198 0.23812187421007014 0.2561607128586883 0.27419955150730646 0.2922383901559246 0.3102772288045428 0.32831606745316094 0.3463549061017791 0.36439374475039726 0.3824325833990154 0.4004714220476336 0.3028609701887255 0.32089980883734365 0.3389386474859618 0.35697748613457997 0.37501632478319813 0.3930551634318163 0.41109400208043445 0.4291328407290526 0.44717167937767077 0.46521051802628893 0.4832493566749071 0.385638904815999 0.40367774346461716 0.4217165821132353 0.4397554207618535 0.45779425941047164 0.4758330980590898 0.49387193670770796 0.5119107753563261 0.5299496140049442 0.5479884526535624 0.5660272913021807 0.46841683944327245 0.4864556780918906 0.5044945167405088 0.5225333553891269 0.540572194037745 0.5586110326863633 0.5766498713349815 0.5946887099835996 0.6127275486322177 0.6307663872808359 0.6488052259294541 0.551194774070546 0.5692336127191642 0.5872724513677823 0.6053112900164004 0.6233501286650186 0.6413889673136368 0.6594278059622549 0.677466644610873 0.6955054832594912 0.7135443219081095 0.7315831605567276 0.6339727086978194 0.6520115473464376 0.6700503859950557 0.6880892246436738 0.706128063292292 0.7241669019409103 0.7422057405895284 0.7602445792381465 0.7782834178867647 0.7963222565353829 0.814361095184001 0.716750643325093 0.7347894819737111 0.7528283206223293 0.7708671592709475 0.7889059979195656 0.8069448365681837 0.8249836752168019 0.8430225138654202 0.8610613525140383 0.8791001911626564 0.8971390298112746 0.7995285779523665 0.8175674166009848 0.8356062552496029 0.853645093898221 0.8716839325468392 0.8897227711954574 0.9077616098440755 0.9258004484926936 0.9438392871413118 0.96187812578993 0.9799169644385481 0.8823065125796399 0.900345351228258 0.9183841898768762 0.9364230285254944 0.9544618671741125 0.9725007058227306 0.9905395444713488 1.008578383119967 1.0266172217685852 1.0446560604172033 1.0626948990658214 0.9650844472069134 0.9831232858555317 1.0011621245041498 1.0192009631527679 1.0372398018013862 1.0552786404500043 1.0733174790986224 1.0913563177472405 1.1093951563958586 1.127433995044477 1.145472833693095; + 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671] + + shape = ExtrudeGeometry((p1, p2, p3); direction, particle_spacing=0.1, n_extrude=3, + density=1000.0, tlsph=false) + + @test shape.coordinates ≈ expected_coords end end From 2b472c9c025e647a449472638c946da648448eb1 Mon Sep 17 00:00:00 2001 From: LasNikas Date: Thu, 8 Feb 2024 17:02:41 +0100 Subject: [PATCH 010/107] fix tuple bug --- src/setups/extrude_geometry.jl | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/setups/extrude_geometry.jl b/src/setups/extrude_geometry.jl index 2ea022615..c83e9fd93 100644 --- a/src/setups/extrude_geometry.jl +++ b/src/setups/extrude_geometry.jl @@ -154,7 +154,14 @@ function sample_plane(plane_points::NTuple{3}, particle_spacing) return coords, particle_spacing_new end -consider_particle_placement(geometry, direction, particle_spacing, tlsph) = geometry +function consider_particle_placement(geometry::Union{AbstractMatrix, InitialCondition}, + direction, particle_spacing, tlsph) + return geometry +end + +function consider_particle_placement(plane_points, direction, particle_spacing, tlsph) + consider_particle_placement(tuple(plabe_points...), direction, particle_spacing, tlsph) +end function consider_particle_placement(plane_points::NTuple{2}, direction, particle_spacing, tlsph) From 8d3c6225aa5303ab5f476d3ef56905eccee89f5d Mon Sep 17 00:00:00 2001 From: LasNikas Date: Thu, 8 Feb 2024 17:04:29 +0100 Subject: [PATCH 011/107] fix typo --- src/setups/extrude_geometry.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/setups/extrude_geometry.jl b/src/setups/extrude_geometry.jl index c83e9fd93..ddb14503a 100644 --- a/src/setups/extrude_geometry.jl +++ b/src/setups/extrude_geometry.jl @@ -160,7 +160,7 @@ function consider_particle_placement(geometry::Union{AbstractMatrix, InitialCond end function consider_particle_placement(plane_points, direction, particle_spacing, tlsph) - consider_particle_placement(tuple(plabe_points...), direction, particle_spacing, tlsph) + consider_particle_placement(tuple(plane_points...), direction, particle_spacing, tlsph) end function consider_particle_placement(plane_points::NTuple{2}, direction, particle_spacing, From a5e2f1c9a8f759800caf54579bfdefda5456d625 Mon Sep 17 00:00:00 2001 From: LasNikas Date: Thu, 8 Feb 2024 17:39:31 +0100 Subject: [PATCH 012/107] fix again --- src/setups/extrude_geometry.jl | 2 +- test/setups/extrude_geometry.jl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/setups/extrude_geometry.jl b/src/setups/extrude_geometry.jl index ddb14503a..ff30d29f7 100644 --- a/src/setups/extrude_geometry.jl +++ b/src/setups/extrude_geometry.jl @@ -110,7 +110,7 @@ function sample_plane(plane_points::NTuple{2}, particle_spacing) throw(ArgumentError("all points must be 2D coordinates")) end - n_points = ceil(Int, norm(plane_points[2] - plane_points[1]) / particle_spacing) + n_points = floor(Int, norm(plane_points[2] - plane_points[1]) / particle_spacing)+1 coords = stack(range(plane_points[1], plane_points[2], length=n_points)) particle_spacing_new = norm(coords[:, 1] - coords[:, 2]) diff --git a/test/setups/extrude_geometry.jl b/test/setups/extrude_geometry.jl index 2cb0cd53c..a4a587484 100644 --- a/test/setups/extrude_geometry.jl +++ b/test/setups/extrude_geometry.jl @@ -55,7 +55,7 @@ @testset "Direction $i" for i in eachindex(directions) shape = ExtrudeGeometry((point1, point2); direction=directions[i], - particle_spacing=0.1597, n_extrude=4, density=1.0) + particle_spacing=0.15, n_extrude=4, density=1.0) @test shape.coordinates ≈ expected_coords[i] end From 2aa969665fa20bac58b36de143efdb285575484c Mon Sep 17 00:00:00 2001 From: LasNikas Date: Thu, 8 Feb 2024 17:55:14 +0100 Subject: [PATCH 013/107] fix for tests --- src/schemes/boundary/open_boundary/system.jl | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/schemes/boundary/open_boundary/system.jl b/src/schemes/boundary/open_boundary/system.jl index 4e6e78f46..e50293bf8 100644 --- a/src/schemes/boundary/open_boundary/system.jl +++ b/src/schemes/boundary/open_boundary/system.jl @@ -37,12 +37,10 @@ struct OpenBoundarySPHSystem{BZ, NDIMS, ELTYPE <: Real, S, VF} <: FluidSystem{ND # Sample particles in boundary zone. initial_condition = ExtrudeGeometry(sample_geometry; particle_spacing, direction, - n_extrude=(open_boundary_layers - 1), velocity, - mass, density, pressure) + n_extrude=open_boundary_layers, velocity, mass, + density, pressure) - # Particles are sampled with `0.5particle_spacing` away from zone plane - zone_width = (open_boundary_layers + 1) * initial_condition.particle_spacing - initial_condition.coordinates .+= 0.5initial_condition.particle_spacing .* direction + zone_width = open_boundary_layers * initial_condition.particle_spacing NDIMS = ndims(initial_condition) ELTYPE = eltype(initial_condition) From bde240d84e22db7bd0718fca8ce79afda43b3c60 Mon Sep 17 00:00:00 2001 From: LasNikas Date: Thu, 8 Feb 2024 18:04:55 +0100 Subject: [PATCH 014/107] fix layers --- src/setups/extrude_geometry.jl | 15 +++++++++------ test/setups/extrude_geometry.jl | 20 ++++++++++---------- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/src/setups/extrude_geometry.jl b/src/setups/extrude_geometry.jl index ff30d29f7..f9dc854ec 100644 --- a/src/setups/extrude_geometry.jl +++ b/src/setups/extrude_geometry.jl @@ -11,7 +11,7 @@ Extrude either a line, a plane or a shape along a specific direction. # Keywords - `particle_spacing`: Spacing between the particles. - `direction`: Vector defining the extrusion direction. -- `n_extrude=0` Number of `geometry` layers in extrude direction. +- `n_extrude=1` Number of `geometry` layers in extrude direction. - `velocity`: Either a function mapping each particle's coordinates to its velocity, or, for a constant fluid velocity, a vector holding this velocity. Velocity is constant zero by default. @@ -26,6 +26,9 @@ Extrude either a line, a plane or a shape along a specific direction. This is only used by the [`EntropicallyDampedSPHSystem`](@ref) and will be overwritten when using an initial pressure function in the system. Cannot be used together with hydrostatic pressure gradient. +- `tlsph`: With the [`TotalLagrangianSPHSystem`](@ref), particles need to be placed + on the boundary of the shape and not one particle radius away, as for fluids. + When `tlsph=true`, particles will be placed on the boundary of the shape. # Examples ```julia @@ -58,8 +61,8 @@ shape = ExtrudeGeometry(shape; direction, particle_spacing=0.1, n_extrude=4, den !!! warning `particle_spacing` between extrusion layers may differ from shapes `particle_spacing`. """ -function ExtrudeGeometry(geometry; particle_spacing, direction, n_extrude=0, - velocity=zeros(length(direction)), tlsph=true, +function ExtrudeGeometry(geometry; particle_spacing, direction, n_extrude=1, + velocity=zeros(length(direction)), tlsph=false, mass=nothing, density=nothing, pressure=0.0) direction_ = normalize(direction) NDIMS = length(direction_) @@ -73,9 +76,9 @@ function ExtrudeGeometry(geometry; particle_spacing, direction, n_extrude=0, "\nNew particle spacing is set to $particle_spacing_." end - coords = (face_coords .+ i * particle_spacing_ * direction_ for i in 0:n_extrude) + coords = (face_coords .+ i * particle_spacing_ * direction_ for i in 0:(n_extrude - 1)) - coordinates = reshape(stack(coords), (NDIMS, size(face_coords, 2) * (n_extrude + 1))) + coordinates = reshape(stack(coords), (NDIMS, size(face_coords, 2) * n_extrude)) return InitialCondition(; coordinates, velocity, density, mass, pressure, particle_spacing=particle_spacing_) @@ -110,7 +113,7 @@ function sample_plane(plane_points::NTuple{2}, particle_spacing) throw(ArgumentError("all points must be 2D coordinates")) end - n_points = floor(Int, norm(plane_points[2] - plane_points[1]) / particle_spacing)+1 + n_points = floor(Int, norm(plane_points[2] - plane_points[1]) / particle_spacing) + 1 coords = stack(range(plane_points[1], plane_points[2], length=n_points)) particle_spacing_new = norm(coords[:, 1] - coords[:, 2]) diff --git a/test/setups/extrude_geometry.jl b/test/setups/extrude_geometry.jl index a4a587484..4dfaac9c1 100644 --- a/test/setups/extrude_geometry.jl +++ b/test/setups/extrude_geometry.jl @@ -31,7 +31,7 @@ @testset "Direction $i" for i in eachindex(directions) shape = ExtrudeGeometry(line; direction=directions[i], particle_spacing=0.15, - n_extrude=4, density=1.0) + n_extrude=5, density=1.0, tlsph=true) @test shape.coordinates ≈ expected_coords[i] end @@ -54,8 +54,8 @@ ] @testset "Direction $i" for i in eachindex(directions) - shape = ExtrudeGeometry((point1, point2); direction=directions[i], - particle_spacing=0.15, n_extrude=4, density=1.0) + shape = ExtrudeGeometry((point1, point2); direction=directions[i], tlsph=true, + particle_spacing=0.15, n_extrude=5, density=1.0) @test shape.coordinates ≈ expected_coords[i] end @@ -68,8 +68,8 @@ expected_coords = [-0.05 -0.05 -0.05 -0.05 -0.05 -0.05 -0.05 -0.05 -0.05 -0.1625 -0.1625 -0.1625 -0.1625 -0.1625 -0.1625 -0.1625 -0.1625 -0.1625 -0.275 -0.275 -0.275 -0.275 -0.275 -0.275 -0.275 -0.275 -0.275 -0.3875 -0.3875 -0.3875 -0.3875 -0.3875 -0.3875 -0.3875 -0.3875 -0.3875 -0.5 -0.5 -0.5 -0.5 -0.5 -0.5 -0.5 -0.5 -0.5; 0.05 0.1625 0.275 0.38749999999999996 0.5 0.6125 0.7249999999999999 0.8374999999999999 0.95 0.05 0.1625 0.275 0.38749999999999996 0.5 0.6125 0.7249999999999999 0.8374999999999999 0.95 0.05 0.1625 0.275 0.38749999999999996 0.5 0.6125 0.7249999999999999 0.8374999999999999 0.95 0.05 0.1625 0.275 0.38749999999999996 0.5 0.6125 0.7249999999999999 0.8374999999999999 0.95 0.05 0.1625 0.275 0.38749999999999996 0.5 0.6125 0.7249999999999999 0.8374999999999999 0.95] - shape = ExtrudeGeometry((point1, point2); direction=[-1.0, 0.0], tlsph=false, - particle_spacing=0.1, n_extrude=4, density=1.0) + shape = ExtrudeGeometry((point1, point2); direction=[-1.0, 0.0], + particle_spacing=0.1, n_extrude=5, density=1.0) @test shape.coordinates ≈ expected_coords end @@ -95,7 +95,7 @@ end @testset "Direction $i" for i in eachindex(directions) shape = ExtrudeGeometry(geometry; direction=directions[i], particle_spacing, - n_extrude=4, density=1.0) + n_extrude=5, tlsph=true, density=1.0) @test shape.coordinates ≈ expected_coords[i] end @@ -112,8 +112,8 @@ end 0.0 0.018181818181818184 0.03636363636363637 0.05454545454545454 0.07272727272727274 0.09090909090909091 0.10909090909090909 0.1272727272727273 0.14545454545454548 0.16363636363636366 0.18181818181818182 0.2 0.06666666666666667 0.08484848484848485 0.10303030303030303 0.12121212121212122 0.1393939393939394 0.1575757575757576 0.17575757575757575 0.19393939393939397 0.21212121212121215 0.23030303030303034 0.24848484848484848 0.26666666666666666 0.13333333333333333 0.15151515151515152 0.1696969696969697 0.18787878787878787 0.20606060606060606 0.22424242424242424 0.24242424242424243 0.2606060606060606 0.2787878787878788 0.296969696969697 0.3151515151515152 0.33333333333333337 0.2 0.2181818181818182 0.2363636363636364 0.2545454545454546 0.27272727272727276 0.2909090909090909 0.3090909090909091 0.32727272727272727 0.34545454545454546 0.36363636363636365 0.38181818181818183 0.4 0.26666666666666666 0.28484848484848485 0.30303030303030304 0.3212121212121212 0.3393939393939394 0.35757575757575755 0.37575757575757573 0.3939393939393939 0.4121212121212121 0.4303030303030303 0.4484848484848485 0.4666666666666667 0.3333333333333333 0.3515151515151515 0.3696969696969697 0.3878787878787879 0.40606060606060607 0.4242424242424242 0.4424242424242424 0.4606060606060606 0.47878787878787876 0.49696969696969695 0.5151515151515151 0.5333333333333333 0.4 0.4181818181818182 0.4363636363636364 0.4545454545454546 0.4727272727272728 0.49090909090909096 0.5090909090909091 0.5272727272727273 0.5454545454545455 0.5636363636363637 0.5818181818181818 0.6000000000000001 0.4666666666666667 0.48484848484848486 0.503030303030303 0.5212121212121212 0.5393939393939394 0.5575757575757576 0.5757575757575758 0.593939393939394 0.6121212121212122 0.6303030303030304 0.6484848484848484 0.6666666666666667 0.5333333333333333 0.5515151515151515 0.5696969696969697 0.5878787878787879 0.6060606060606061 0.6242424242424243 0.6424242424242425 0.6606060606060606 0.6787878787878788 0.696969696969697 0.7151515151515151 0.7333333333333334 0.6 0.6181818181818182 0.6363636363636364 0.6545454545454545 0.6727272727272727 0.6909090909090909 0.7090909090909091 0.7272727272727273 0.7454545454545455 0.7636363636363637 0.7818181818181817 0.8 0.6666666666666666 0.6848484848484848 0.703030303030303 0.7212121212121212 0.7393939393939394 0.7575757575757576 0.7757575757575758 0.793939393939394 0.8121212121212121 0.8303030303030303 0.8484848484848484 0.8666666666666667 0.7333333333333333 0.7515151515151515 0.7696969696969697 0.7878787878787878 0.806060606060606 0.8242424242424242 0.8424242424242424 0.8606060606060606 0.8787878787878788 0.896969696969697 0.915151515151515 0.9333333333333333 0.8 0.8181818181818182 0.8363636363636364 0.8545454545454546 0.8727272727272728 0.890909090909091 0.9090909090909092 0.9272727272727274 0.9454545454545455 0.9636363636363637 0.9818181818181819 1.0 0.8666666666666667 0.8848484848484849 0.9030303030303031 0.9212121212121213 0.9393939393939394 0.9575757575757576 0.9757575757575758 0.993939393939394 1.0121212121212122 1.0303030303030303 1.0484848484848486 1.0666666666666667 0.9333333333333333 0.9515151515151515 0.9696969696969697 0.9878787878787879 1.006060606060606 1.0242424242424242 1.0424242424242425 1.0606060606060606 1.0787878787878789 1.096969696969697 1.1151515151515152 1.1333333333333333 1.0 1.018181818181818 1.0363636363636364 1.0545454545454545 1.0727272727272728 1.0909090909090908 1.1090909090909091 1.1272727272727272 1.1454545454545455 1.1636363636363636 1.1818181818181819 1.2 0.0 0.018181818181818184 0.03636363636363637 0.05454545454545454 0.07272727272727274 0.09090909090909091 0.10909090909090909 0.1272727272727273 0.14545454545454548 0.16363636363636366 0.18181818181818182 0.2 0.06666666666666667 0.08484848484848485 0.10303030303030303 0.12121212121212122 0.1393939393939394 0.1575757575757576 0.17575757575757575 0.19393939393939397 0.21212121212121215 0.23030303030303034 0.24848484848484848 0.26666666666666666 0.13333333333333333 0.15151515151515152 0.1696969696969697 0.18787878787878787 0.20606060606060606 0.22424242424242424 0.24242424242424243 0.2606060606060606 0.2787878787878788 0.296969696969697 0.3151515151515152 0.33333333333333337 0.2 0.2181818181818182 0.2363636363636364 0.2545454545454546 0.27272727272727276 0.2909090909090909 0.3090909090909091 0.32727272727272727 0.34545454545454546 0.36363636363636365 0.38181818181818183 0.4 0.26666666666666666 0.28484848484848485 0.30303030303030304 0.3212121212121212 0.3393939393939394 0.35757575757575755 0.37575757575757573 0.3939393939393939 0.4121212121212121 0.4303030303030303 0.4484848484848485 0.4666666666666667 0.3333333333333333 0.3515151515151515 0.3696969696969697 0.3878787878787879 0.40606060606060607 0.4242424242424242 0.4424242424242424 0.4606060606060606 0.47878787878787876 0.49696969696969695 0.5151515151515151 0.5333333333333333 0.4 0.4181818181818182 0.4363636363636364 0.4545454545454546 0.4727272727272728 0.49090909090909096 0.5090909090909091 0.5272727272727273 0.5454545454545455 0.5636363636363637 0.5818181818181818 0.6000000000000001 0.4666666666666667 0.48484848484848486 0.503030303030303 0.5212121212121212 0.5393939393939394 0.5575757575757576 0.5757575757575758 0.593939393939394 0.6121212121212122 0.6303030303030304 0.6484848484848484 0.6666666666666667 0.5333333333333333 0.5515151515151515 0.5696969696969697 0.5878787878787879 0.6060606060606061 0.6242424242424243 0.6424242424242425 0.6606060606060606 0.6787878787878788 0.696969696969697 0.7151515151515151 0.7333333333333334 0.6 0.6181818181818182 0.6363636363636364 0.6545454545454545 0.6727272727272727 0.6909090909090909 0.7090909090909091 0.7272727272727273 0.7454545454545455 0.7636363636363637 0.7818181818181817 0.8 0.6666666666666666 0.6848484848484848 0.703030303030303 0.7212121212121212 0.7393939393939394 0.7575757575757576 0.7757575757575758 0.793939393939394 0.8121212121212121 0.8303030303030303 0.8484848484848484 0.8666666666666667 0.7333333333333333 0.7515151515151515 0.7696969696969697 0.7878787878787878 0.806060606060606 0.8242424242424242 0.8424242424242424 0.8606060606060606 0.8787878787878788 0.896969696969697 0.915151515151515 0.9333333333333333 0.8 0.8181818181818182 0.8363636363636364 0.8545454545454546 0.8727272727272728 0.890909090909091 0.9090909090909092 0.9272727272727274 0.9454545454545455 0.9636363636363637 0.9818181818181819 1.0 0.8666666666666667 0.8848484848484849 0.9030303030303031 0.9212121212121213 0.9393939393939394 0.9575757575757576 0.9757575757575758 0.993939393939394 1.0121212121212122 1.0303030303030303 1.0484848484848486 1.0666666666666667 0.9333333333333333 0.9515151515151515 0.9696969696969697 0.9878787878787879 1.006060606060606 1.0242424242424242 1.0424242424242425 1.0606060606060606 1.0787878787878789 1.096969696969697 1.1151515151515152 1.1333333333333333 1.0 1.018181818181818 1.0363636363636364 1.0545454545454545 1.0727272727272728 1.0909090909090908 1.1090909090909091 1.1272727272727272 1.1454545454545455 1.1636363636363636 1.1818181818181819 1.2 0.0 0.018181818181818184 0.03636363636363637 0.05454545454545454 0.07272727272727274 0.09090909090909091 0.10909090909090909 0.1272727272727273 0.14545454545454548 0.16363636363636366 0.18181818181818182 0.2 0.06666666666666667 0.08484848484848485 0.10303030303030303 0.12121212121212122 0.1393939393939394 0.1575757575757576 0.17575757575757575 0.19393939393939397 0.21212121212121215 0.23030303030303034 0.24848484848484848 0.26666666666666666 0.13333333333333333 0.15151515151515152 0.1696969696969697 0.18787878787878787 0.20606060606060606 0.22424242424242424 0.24242424242424243 0.2606060606060606 0.2787878787878788 0.296969696969697 0.3151515151515152 0.33333333333333337 0.2 0.2181818181818182 0.2363636363636364 0.2545454545454546 0.27272727272727276 0.2909090909090909 0.3090909090909091 0.32727272727272727 0.34545454545454546 0.36363636363636365 0.38181818181818183 0.4 0.26666666666666666 0.28484848484848485 0.30303030303030304 0.3212121212121212 0.3393939393939394 0.35757575757575755 0.37575757575757573 0.3939393939393939 0.4121212121212121 0.4303030303030303 0.4484848484848485 0.4666666666666667 0.3333333333333333 0.3515151515151515 0.3696969696969697 0.3878787878787879 0.40606060606060607 0.4242424242424242 0.4424242424242424 0.4606060606060606 0.47878787878787876 0.49696969696969695 0.5151515151515151 0.5333333333333333 0.4 0.4181818181818182 0.4363636363636364 0.4545454545454546 0.4727272727272728 0.49090909090909096 0.5090909090909091 0.5272727272727273 0.5454545454545455 0.5636363636363637 0.5818181818181818 0.6000000000000001 0.4666666666666667 0.48484848484848486 0.503030303030303 0.5212121212121212 0.5393939393939394 0.5575757575757576 0.5757575757575758 0.593939393939394 0.6121212121212122 0.6303030303030304 0.6484848484848484 0.6666666666666667 0.5333333333333333 0.5515151515151515 0.5696969696969697 0.5878787878787879 0.6060606060606061 0.6242424242424243 0.6424242424242425 0.6606060606060606 0.6787878787878788 0.696969696969697 0.7151515151515151 0.7333333333333334 0.6 0.6181818181818182 0.6363636363636364 0.6545454545454545 0.6727272727272727 0.6909090909090909 0.7090909090909091 0.7272727272727273 0.7454545454545455 0.7636363636363637 0.7818181818181817 0.8 0.6666666666666666 0.6848484848484848 0.703030303030303 0.7212121212121212 0.7393939393939394 0.7575757575757576 0.7757575757575758 0.793939393939394 0.8121212121212121 0.8303030303030303 0.8484848484848484 0.8666666666666667 0.7333333333333333 0.7515151515151515 0.7696969696969697 0.7878787878787878 0.806060606060606 0.8242424242424242 0.8424242424242424 0.8606060606060606 0.8787878787878788 0.896969696969697 0.915151515151515 0.9333333333333333 0.8 0.8181818181818182 0.8363636363636364 0.8545454545454546 0.8727272727272728 0.890909090909091 0.9090909090909092 0.9272727272727274 0.9454545454545455 0.9636363636363637 0.9818181818181819 1.0 0.8666666666666667 0.8848484848484849 0.9030303030303031 0.9212121212121213 0.9393939393939394 0.9575757575757576 0.9757575757575758 0.993939393939394 1.0121212121212122 1.0303030303030303 1.0484848484848486 1.0666666666666667 0.9333333333333333 0.9515151515151515 0.9696969696969697 0.9878787878787879 1.006060606060606 1.0242424242424242 1.0424242424242425 1.0606060606060606 1.0787878787878789 1.096969696969697 1.1151515151515152 1.1333333333333333 1.0 1.018181818181818 1.0363636363636364 1.0545454545454545 1.0727272727272728 1.0909090909090908 1.1090909090909091 1.1272727272727272 1.1454545454545455 1.1636363636363636 1.1818181818181819 1.2 0.0 0.018181818181818184 0.03636363636363637 0.05454545454545454 0.07272727272727274 0.09090909090909091 0.10909090909090909 0.1272727272727273 0.14545454545454548 0.16363636363636366 0.18181818181818182 0.2 0.06666666666666667 0.08484848484848485 0.10303030303030303 0.12121212121212122 0.1393939393939394 0.1575757575757576 0.17575757575757575 0.19393939393939397 0.21212121212121215 0.23030303030303034 0.24848484848484848 0.26666666666666666 0.13333333333333333 0.15151515151515152 0.1696969696969697 0.18787878787878787 0.20606060606060606 0.22424242424242424 0.24242424242424243 0.2606060606060606 0.2787878787878788 0.296969696969697 0.3151515151515152 0.33333333333333337 0.2 0.2181818181818182 0.2363636363636364 0.2545454545454546 0.27272727272727276 0.2909090909090909 0.3090909090909091 0.32727272727272727 0.34545454545454546 0.36363636363636365 0.38181818181818183 0.4 0.26666666666666666 0.28484848484848485 0.30303030303030304 0.3212121212121212 0.3393939393939394 0.35757575757575755 0.37575757575757573 0.3939393939393939 0.4121212121212121 0.4303030303030303 0.4484848484848485 0.4666666666666667 0.3333333333333333 0.3515151515151515 0.3696969696969697 0.3878787878787879 0.40606060606060607 0.4242424242424242 0.4424242424242424 0.4606060606060606 0.47878787878787876 0.49696969696969695 0.5151515151515151 0.5333333333333333 0.4 0.4181818181818182 0.4363636363636364 0.4545454545454546 0.4727272727272728 0.49090909090909096 0.5090909090909091 0.5272727272727273 0.5454545454545455 0.5636363636363637 0.5818181818181818 0.6000000000000001 0.4666666666666667 0.48484848484848486 0.503030303030303 0.5212121212121212 0.5393939393939394 0.5575757575757576 0.5757575757575758 0.593939393939394 0.6121212121212122 0.6303030303030304 0.6484848484848484 0.6666666666666667 0.5333333333333333 0.5515151515151515 0.5696969696969697 0.5878787878787879 0.6060606060606061 0.6242424242424243 0.6424242424242425 0.6606060606060606 0.6787878787878788 0.696969696969697 0.7151515151515151 0.7333333333333334 0.6 0.6181818181818182 0.6363636363636364 0.6545454545454545 0.6727272727272727 0.6909090909090909 0.7090909090909091 0.7272727272727273 0.7454545454545455 0.7636363636363637 0.7818181818181817 0.8 0.6666666666666666 0.6848484848484848 0.703030303030303 0.7212121212121212 0.7393939393939394 0.7575757575757576 0.7757575757575758 0.793939393939394 0.8121212121212121 0.8303030303030303 0.8484848484848484 0.8666666666666667 0.7333333333333333 0.7515151515151515 0.7696969696969697 0.7878787878787878 0.806060606060606 0.8242424242424242 0.8424242424242424 0.8606060606060606 0.8787878787878788 0.896969696969697 0.915151515151515 0.9333333333333333 0.8 0.8181818181818182 0.8363636363636364 0.8545454545454546 0.8727272727272728 0.890909090909091 0.9090909090909092 0.9272727272727274 0.9454545454545455 0.9636363636363637 0.9818181818181819 1.0 0.8666666666666667 0.8848484848484849 0.9030303030303031 0.9212121212121213 0.9393939393939394 0.9575757575757576 0.9757575757575758 0.993939393939394 1.0121212121212122 1.0303030303030303 1.0484848484848486 1.0666666666666667 0.9333333333333333 0.9515151515151515 0.9696969696969697 0.9878787878787879 1.006060606060606 1.0242424242424242 1.0424242424242425 1.0606060606060606 1.0787878787878789 1.096969696969697 1.1151515151515152 1.1333333333333333 1.0 1.018181818181818 1.0363636363636364 1.0545454545454545 1.0727272727272728 1.0909090909090908 1.1090909090909091 1.1272727272727272 1.1454545454545455 1.1636363636363636 1.1818181818181819 1.2; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.06666666666666667 0.06666666666666667 0.06666666666666667 0.06666666666666667 0.06666666666666667 0.06666666666666667 0.06666666666666667 0.06666666666666667 0.06666666666666667 0.06666666666666667 0.06666666666666667 0.06666666666666667 0.13333333333333333 0.13333333333333333 0.13333333333333333 0.13333333333333333 0.13333333333333333 0.13333333333333333 0.13333333333333333 0.13333333333333333 0.13333333333333333 0.13333333333333333 0.13333333333333333 0.13333333333333333 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.26666666666666666 0.26666666666666666 0.26666666666666666 0.26666666666666666 0.26666666666666666 0.26666666666666666 0.26666666666666666 0.26666666666666666 0.26666666666666666 0.26666666666666666 0.26666666666666666 0.26666666666666666 0.3333333333333333 0.3333333333333333 0.3333333333333333 0.3333333333333333 0.3333333333333333 0.3333333333333333 0.3333333333333333 0.3333333333333333 0.3333333333333333 0.3333333333333333 0.3333333333333333 0.3333333333333333 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4666666666666667 0.4666666666666667 0.4666666666666667 0.4666666666666667 0.4666666666666667 0.4666666666666667 0.4666666666666667 0.4666666666666667 0.4666666666666667 0.4666666666666667 0.4666666666666667 0.4666666666666667 0.5333333333333333 0.5333333333333333 0.5333333333333333 0.5333333333333333 0.5333333333333333 0.5333333333333333 0.5333333333333333 0.5333333333333333 0.5333333333333333 0.5333333333333333 0.5333333333333333 0.5333333333333333 0.6 0.6 0.6 0.6 0.6 0.6 0.6 0.6 0.6 0.6 0.6 0.6 0.6666666666666666 0.6666666666666666 0.6666666666666666 0.6666666666666666 0.6666666666666666 0.6666666666666666 0.6666666666666666 0.6666666666666666 0.6666666666666666 0.6666666666666666 0.6666666666666666 0.6666666666666666 0.7333333333333333 0.7333333333333333 0.7333333333333333 0.7333333333333333 0.7333333333333333 0.7333333333333333 0.7333333333333333 0.7333333333333333 0.7333333333333333 0.7333333333333333 0.7333333333333333 0.7333333333333333 0.8 0.8 0.8 0.8 0.8 0.8 0.8 0.8 0.8 0.8 0.8 0.8 0.8666666666666667 0.8666666666666667 0.8666666666666667 0.8666666666666667 0.8666666666666667 0.8666666666666667 0.8666666666666667 0.8666666666666667 0.8666666666666667 0.8666666666666667 0.8666666666666667 0.8666666666666667 0.9333333333333333 0.9333333333333333 0.9333333333333333 0.9333333333333333 0.9333333333333333 0.9333333333333333 0.9333333333333333 0.9333333333333333 0.9333333333333333 0.9333333333333333 0.9333333333333333 0.9333333333333333 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 0.092709445701687 0.092709445701687 0.092709445701687 0.092709445701687 0.092709445701687 0.092709445701687 0.092709445701687 0.092709445701687 0.092709445701687 0.092709445701687 0.092709445701687 0.092709445701687 0.15937611236835367 0.15937611236835367 0.15937611236835367 0.15937611236835367 0.15937611236835367 0.15937611236835367 0.15937611236835367 0.15937611236835367 0.15937611236835367 0.15937611236835367 0.15937611236835367 0.15937611236835367 0.22604277903502035 0.22604277903502035 0.22604277903502035 0.22604277903502035 0.22604277903502035 0.22604277903502035 0.22604277903502035 0.22604277903502035 0.22604277903502035 0.22604277903502035 0.22604277903502035 0.22604277903502035 0.292709445701687 0.292709445701687 0.292709445701687 0.292709445701687 0.292709445701687 0.292709445701687 0.292709445701687 0.292709445701687 0.292709445701687 0.292709445701687 0.292709445701687 0.292709445701687 0.35937611236835365 0.35937611236835365 0.35937611236835365 0.35937611236835365 0.35937611236835365 0.35937611236835365 0.35937611236835365 0.35937611236835365 0.35937611236835365 0.35937611236835365 0.35937611236835365 0.35937611236835365 0.4260427790350203 0.4260427790350203 0.4260427790350203 0.4260427790350203 0.4260427790350203 0.4260427790350203 0.4260427790350203 0.4260427790350203 0.4260427790350203 0.4260427790350203 0.4260427790350203 0.4260427790350203 0.492709445701687 0.492709445701687 0.492709445701687 0.492709445701687 0.492709445701687 0.492709445701687 0.492709445701687 0.492709445701687 0.492709445701687 0.492709445701687 0.492709445701687 0.492709445701687 0.5593761123683537 0.5593761123683537 0.5593761123683537 0.5593761123683537 0.5593761123683537 0.5593761123683537 0.5593761123683537 0.5593761123683537 0.5593761123683537 0.5593761123683537 0.5593761123683537 0.5593761123683537 0.6260427790350204 0.6260427790350204 0.6260427790350204 0.6260427790350204 0.6260427790350204 0.6260427790350204 0.6260427790350204 0.6260427790350204 0.6260427790350204 0.6260427790350204 0.6260427790350204 0.6260427790350204 0.692709445701687 0.692709445701687 0.692709445701687 0.692709445701687 0.692709445701687 0.692709445701687 0.692709445701687 0.692709445701687 0.692709445701687 0.692709445701687 0.692709445701687 0.692709445701687 0.7593761123683537 0.7593761123683537 0.7593761123683537 0.7593761123683537 0.7593761123683537 0.7593761123683537 0.7593761123683537 0.7593761123683537 0.7593761123683537 0.7593761123683537 0.7593761123683537 0.7593761123683537 0.8260427790350203 0.8260427790350203 0.8260427790350203 0.8260427790350203 0.8260427790350203 0.8260427790350203 0.8260427790350203 0.8260427790350203 0.8260427790350203 0.8260427790350203 0.8260427790350203 0.8260427790350203 0.8927094457016871 0.8927094457016871 0.8927094457016871 0.8927094457016871 0.8927094457016871 0.8927094457016871 0.8927094457016871 0.8927094457016871 0.8927094457016871 0.8927094457016871 0.8927094457016871 0.8927094457016871 0.9593761123683537 0.9593761123683537 0.9593761123683537 0.9593761123683537 0.9593761123683537 0.9593761123683537 0.9593761123683537 0.9593761123683537 0.9593761123683537 0.9593761123683537 0.9593761123683537 0.9593761123683537 1.0260427790350204 1.0260427790350204 1.0260427790350204 1.0260427790350204 1.0260427790350204 1.0260427790350204 1.0260427790350204 1.0260427790350204 1.0260427790350204 1.0260427790350204 1.0260427790350204 1.0260427790350204 1.092709445701687 1.092709445701687 1.092709445701687 1.092709445701687 1.092709445701687 1.092709445701687 1.092709445701687 1.092709445701687 1.092709445701687 1.092709445701687 1.092709445701687 1.092709445701687 0.185418891403374 0.185418891403374 0.185418891403374 0.185418891403374 0.185418891403374 0.185418891403374 0.185418891403374 0.185418891403374 0.185418891403374 0.185418891403374 0.185418891403374 0.185418891403374 0.2520855580700407 0.2520855580700407 0.2520855580700407 0.2520855580700407 0.2520855580700407 0.2520855580700407 0.2520855580700407 0.2520855580700407 0.2520855580700407 0.2520855580700407 0.2520855580700407 0.2520855580700407 0.31875222473670733 0.31875222473670733 0.31875222473670733 0.31875222473670733 0.31875222473670733 0.31875222473670733 0.31875222473670733 0.31875222473670733 0.31875222473670733 0.31875222473670733 0.31875222473670733 0.31875222473670733 0.38541889140337404 0.38541889140337404 0.38541889140337404 0.38541889140337404 0.38541889140337404 0.38541889140337404 0.38541889140337404 0.38541889140337404 0.38541889140337404 0.38541889140337404 0.38541889140337404 0.38541889140337404 0.4520855580700407 0.4520855580700407 0.4520855580700407 0.4520855580700407 0.4520855580700407 0.4520855580700407 0.4520855580700407 0.4520855580700407 0.4520855580700407 0.4520855580700407 0.4520855580700407 0.4520855580700407 0.5187522247367073 0.5187522247367073 0.5187522247367073 0.5187522247367073 0.5187522247367073 0.5187522247367073 0.5187522247367073 0.5187522247367073 0.5187522247367073 0.5187522247367073 0.5187522247367073 0.5187522247367073 0.585418891403374 0.585418891403374 0.585418891403374 0.585418891403374 0.585418891403374 0.585418891403374 0.585418891403374 0.585418891403374 0.585418891403374 0.585418891403374 0.585418891403374 0.585418891403374 0.6520855580700406 0.6520855580700406 0.6520855580700406 0.6520855580700406 0.6520855580700406 0.6520855580700406 0.6520855580700406 0.6520855580700406 0.6520855580700406 0.6520855580700406 0.6520855580700406 0.6520855580700406 0.7187522247367073 0.7187522247367073 0.7187522247367073 0.7187522247367073 0.7187522247367073 0.7187522247367073 0.7187522247367073 0.7187522247367073 0.7187522247367073 0.7187522247367073 0.7187522247367073 0.7187522247367073 0.785418891403374 0.785418891403374 0.785418891403374 0.785418891403374 0.785418891403374 0.785418891403374 0.785418891403374 0.785418891403374 0.785418891403374 0.785418891403374 0.785418891403374 0.785418891403374 0.8520855580700406 0.8520855580700406 0.8520855580700406 0.8520855580700406 0.8520855580700406 0.8520855580700406 0.8520855580700406 0.8520855580700406 0.8520855580700406 0.8520855580700406 0.8520855580700406 0.8520855580700406 0.9187522247367073 0.9187522247367073 0.9187522247367073 0.9187522247367073 0.9187522247367073 0.9187522247367073 0.9187522247367073 0.9187522247367073 0.9187522247367073 0.9187522247367073 0.9187522247367073 0.9187522247367073 0.985418891403374 0.985418891403374 0.985418891403374 0.985418891403374 0.985418891403374 0.985418891403374 0.985418891403374 0.985418891403374 0.985418891403374 0.985418891403374 0.985418891403374 0.985418891403374 1.0520855580700408 1.0520855580700408 1.0520855580700408 1.0520855580700408 1.0520855580700408 1.0520855580700408 1.0520855580700408 1.0520855580700408 1.0520855580700408 1.0520855580700408 1.0520855580700408 1.0520855580700408 1.1187522247367074 1.1187522247367074 1.1187522247367074 1.1187522247367074 1.1187522247367074 1.1187522247367074 1.1187522247367074 1.1187522247367074 1.1187522247367074 1.1187522247367074 1.1187522247367074 1.1187522247367074 1.185418891403374 1.185418891403374 1.185418891403374 1.185418891403374 1.185418891403374 1.185418891403374 1.185418891403374 1.185418891403374 1.185418891403374 1.185418891403374 1.185418891403374 1.185418891403374 0.278128337105061 0.278128337105061 0.278128337105061 0.278128337105061 0.278128337105061 0.278128337105061 0.278128337105061 0.278128337105061 0.278128337105061 0.278128337105061 0.278128337105061 0.278128337105061 0.34479500377172767 0.34479500377172767 0.34479500377172767 0.34479500377172767 0.34479500377172767 0.34479500377172767 0.34479500377172767 0.34479500377172767 0.34479500377172767 0.34479500377172767 0.34479500377172767 0.34479500377172767 0.4114616704383943 0.4114616704383943 0.4114616704383943 0.4114616704383943 0.4114616704383943 0.4114616704383943 0.4114616704383943 0.4114616704383943 0.4114616704383943 0.4114616704383943 0.4114616704383943 0.4114616704383943 0.47812833710506103 0.47812833710506103 0.47812833710506103 0.47812833710506103 0.47812833710506103 0.47812833710506103 0.47812833710506103 0.47812833710506103 0.47812833710506103 0.47812833710506103 0.47812833710506103 0.47812833710506103 0.5447950037717277 0.5447950037717277 0.5447950037717277 0.5447950037717277 0.5447950037717277 0.5447950037717277 0.5447950037717277 0.5447950037717277 0.5447950037717277 0.5447950037717277 0.5447950037717277 0.5447950037717277 0.6114616704383944 0.6114616704383944 0.6114616704383944 0.6114616704383944 0.6114616704383944 0.6114616704383944 0.6114616704383944 0.6114616704383944 0.6114616704383944 0.6114616704383944 0.6114616704383944 0.6114616704383944 0.678128337105061 0.678128337105061 0.678128337105061 0.678128337105061 0.678128337105061 0.678128337105061 0.678128337105061 0.678128337105061 0.678128337105061 0.678128337105061 0.678128337105061 0.678128337105061 0.7447950037717277 0.7447950037717277 0.7447950037717277 0.7447950037717277 0.7447950037717277 0.7447950037717277 0.7447950037717277 0.7447950037717277 0.7447950037717277 0.7447950037717277 0.7447950037717277 0.7447950037717277 0.8114616704383943 0.8114616704383943 0.8114616704383943 0.8114616704383943 0.8114616704383943 0.8114616704383943 0.8114616704383943 0.8114616704383943 0.8114616704383943 0.8114616704383943 0.8114616704383943 0.8114616704383943 0.878128337105061 0.878128337105061 0.878128337105061 0.878128337105061 0.878128337105061 0.878128337105061 0.878128337105061 0.878128337105061 0.878128337105061 0.878128337105061 0.878128337105061 0.878128337105061 0.9447950037717276 0.9447950037717276 0.9447950037717276 0.9447950037717276 0.9447950037717276 0.9447950037717276 0.9447950037717276 0.9447950037717276 0.9447950037717276 0.9447950037717276 0.9447950037717276 0.9447950037717276 1.0114616704383943 1.0114616704383943 1.0114616704383943 1.0114616704383943 1.0114616704383943 1.0114616704383943 1.0114616704383943 1.0114616704383943 1.0114616704383943 1.0114616704383943 1.0114616704383943 1.0114616704383943 1.0781283371050612 1.0781283371050612 1.0781283371050612 1.0781283371050612 1.0781283371050612 1.0781283371050612 1.0781283371050612 1.0781283371050612 1.0781283371050612 1.0781283371050612 1.0781283371050612 1.0781283371050612 1.1447950037717276 1.1447950037717276 1.1447950037717276 1.1447950037717276 1.1447950037717276 1.1447950037717276 1.1447950037717276 1.1447950037717276 1.1447950037717276 1.1447950037717276 1.1447950037717276 1.1447950037717276 1.2114616704383945 1.2114616704383945 1.2114616704383945 1.2114616704383945 1.2114616704383945 1.2114616704383945 1.2114616704383945 1.2114616704383945 1.2114616704383945 1.2114616704383945 1.2114616704383945 1.2114616704383945 1.278128337105061 1.278128337105061 1.278128337105061 1.278128337105061 1.278128337105061 1.278128337105061 1.278128337105061 1.278128337105061 1.278128337105061 1.278128337105061 1.278128337105061 1.278128337105061] - shape = ExtrudeGeometry((p1, p2, p3); direction, particle_spacing=0.1, n_extrude=3, - density=1000.0) + shape = ExtrudeGeometry((p1, p2, p3); direction, particle_spacing=0.1, n_extrude=4, + density=1000.0, tlsph=true) @test shape.coordinates ≈ expected_coords end @@ -129,8 +129,8 @@ end 0.054527166306904996 0.07256600495552315 0.09060484360414131 0.10864368225275947 0.12668252090137763 0.1447213595499958 0.16276019819861395 0.18079903684723211 0.19883787549585027 0.21687671414446844 0.2349155527930866 0.1373051009341785 0.15534393958279666 0.17338277823141482 0.19142161688003298 0.20946045552865114 0.2274992941772693 0.24553813282588746 0.26357697147450565 0.28161581012312376 0.29965464877174197 0.3176934874203601 0.22008303556145198 0.23812187421007014 0.2561607128586883 0.27419955150730646 0.2922383901559246 0.3102772288045428 0.32831606745316094 0.3463549061017791 0.36439374475039726 0.3824325833990154 0.4004714220476336 0.3028609701887255 0.32089980883734365 0.3389386474859618 0.35697748613457997 0.37501632478319813 0.3930551634318163 0.41109400208043445 0.4291328407290526 0.44717167937767077 0.46521051802628893 0.4832493566749071 0.385638904815999 0.40367774346461716 0.4217165821132353 0.4397554207618535 0.45779425941047164 0.4758330980590898 0.49387193670770796 0.5119107753563261 0.5299496140049442 0.5479884526535624 0.5660272913021807 0.46841683944327245 0.4864556780918906 0.5044945167405088 0.5225333553891269 0.540572194037745 0.5586110326863633 0.5766498713349815 0.5946887099835996 0.6127275486322177 0.6307663872808359 0.6488052259294541 0.551194774070546 0.5692336127191642 0.5872724513677823 0.6053112900164004 0.6233501286650186 0.6413889673136368 0.6594278059622549 0.677466644610873 0.6955054832594912 0.7135443219081095 0.7315831605567276 0.6339727086978194 0.6520115473464376 0.6700503859950557 0.6880892246436738 0.706128063292292 0.7241669019409103 0.7422057405895284 0.7602445792381465 0.7782834178867647 0.7963222565353829 0.814361095184001 0.716750643325093 0.7347894819737111 0.7528283206223293 0.7708671592709475 0.7889059979195656 0.8069448365681837 0.8249836752168019 0.8430225138654202 0.8610613525140383 0.8791001911626564 0.8971390298112746 0.7995285779523665 0.8175674166009848 0.8356062552496029 0.853645093898221 0.8716839325468392 0.8897227711954574 0.9077616098440755 0.9258004484926936 0.9438392871413118 0.96187812578993 0.9799169644385481 0.8823065125796399 0.900345351228258 0.9183841898768762 0.9364230285254944 0.9544618671741125 0.9725007058227306 0.9905395444713488 1.008578383119967 1.0266172217685852 1.0446560604172033 1.0626948990658214 0.9650844472069134 0.9831232858555317 1.0011621245041498 1.0192009631527679 1.0372398018013862 1.0552786404500043 1.0733174790986224 1.0913563177472405 1.1093951563958586 1.127433995044477 1.145472833693095 0.054527166306904996 0.07256600495552315 0.09060484360414131 0.10864368225275947 0.12668252090137763 0.1447213595499958 0.16276019819861395 0.18079903684723211 0.19883787549585027 0.21687671414446844 0.2349155527930866 0.1373051009341785 0.15534393958279666 0.17338277823141482 0.19142161688003298 0.20946045552865114 0.2274992941772693 0.24553813282588746 0.26357697147450565 0.28161581012312376 0.29965464877174197 0.3176934874203601 0.22008303556145198 0.23812187421007014 0.2561607128586883 0.27419955150730646 0.2922383901559246 0.3102772288045428 0.32831606745316094 0.3463549061017791 0.36439374475039726 0.3824325833990154 0.4004714220476336 0.3028609701887255 0.32089980883734365 0.3389386474859618 0.35697748613457997 0.37501632478319813 0.3930551634318163 0.41109400208043445 0.4291328407290526 0.44717167937767077 0.46521051802628893 0.4832493566749071 0.385638904815999 0.40367774346461716 0.4217165821132353 0.4397554207618535 0.45779425941047164 0.4758330980590898 0.49387193670770796 0.5119107753563261 0.5299496140049442 0.5479884526535624 0.5660272913021807 0.46841683944327245 0.4864556780918906 0.5044945167405088 0.5225333553891269 0.540572194037745 0.5586110326863633 0.5766498713349815 0.5946887099835996 0.6127275486322177 0.6307663872808359 0.6488052259294541 0.551194774070546 0.5692336127191642 0.5872724513677823 0.6053112900164004 0.6233501286650186 0.6413889673136368 0.6594278059622549 0.677466644610873 0.6955054832594912 0.7135443219081095 0.7315831605567276 0.6339727086978194 0.6520115473464376 0.6700503859950557 0.6880892246436738 0.706128063292292 0.7241669019409103 0.7422057405895284 0.7602445792381465 0.7782834178867647 0.7963222565353829 0.814361095184001 0.716750643325093 0.7347894819737111 0.7528283206223293 0.7708671592709475 0.7889059979195656 0.8069448365681837 0.8249836752168019 0.8430225138654202 0.8610613525140383 0.8791001911626564 0.8971390298112746 0.7995285779523665 0.8175674166009848 0.8356062552496029 0.853645093898221 0.8716839325468392 0.8897227711954574 0.9077616098440755 0.9258004484926936 0.9438392871413118 0.96187812578993 0.9799169644385481 0.8823065125796399 0.900345351228258 0.9183841898768762 0.9364230285254944 0.9544618671741125 0.9725007058227306 0.9905395444713488 1.008578383119967 1.0266172217685852 1.0446560604172033 1.0626948990658214 0.9650844472069134 0.9831232858555317 1.0011621245041498 1.0192009631527679 1.0372398018013862 1.0552786404500043 1.0733174790986224 1.0913563177472405 1.1093951563958586 1.127433995044477 1.145472833693095 0.054527166306904996 0.07256600495552315 0.09060484360414131 0.10864368225275947 0.12668252090137763 0.1447213595499958 0.16276019819861395 0.18079903684723211 0.19883787549585027 0.21687671414446844 0.2349155527930866 0.1373051009341785 0.15534393958279666 0.17338277823141482 0.19142161688003298 0.20946045552865114 0.2274992941772693 0.24553813282588746 0.26357697147450565 0.28161581012312376 0.29965464877174197 0.3176934874203601 0.22008303556145198 0.23812187421007014 0.2561607128586883 0.27419955150730646 0.2922383901559246 0.3102772288045428 0.32831606745316094 0.3463549061017791 0.36439374475039726 0.3824325833990154 0.4004714220476336 0.3028609701887255 0.32089980883734365 0.3389386474859618 0.35697748613457997 0.37501632478319813 0.3930551634318163 0.41109400208043445 0.4291328407290526 0.44717167937767077 0.46521051802628893 0.4832493566749071 0.385638904815999 0.40367774346461716 0.4217165821132353 0.4397554207618535 0.45779425941047164 0.4758330980590898 0.49387193670770796 0.5119107753563261 0.5299496140049442 0.5479884526535624 0.5660272913021807 0.46841683944327245 0.4864556780918906 0.5044945167405088 0.5225333553891269 0.540572194037745 0.5586110326863633 0.5766498713349815 0.5946887099835996 0.6127275486322177 0.6307663872808359 0.6488052259294541 0.551194774070546 0.5692336127191642 0.5872724513677823 0.6053112900164004 0.6233501286650186 0.6413889673136368 0.6594278059622549 0.677466644610873 0.6955054832594912 0.7135443219081095 0.7315831605567276 0.6339727086978194 0.6520115473464376 0.6700503859950557 0.6880892246436738 0.706128063292292 0.7241669019409103 0.7422057405895284 0.7602445792381465 0.7782834178867647 0.7963222565353829 0.814361095184001 0.716750643325093 0.7347894819737111 0.7528283206223293 0.7708671592709475 0.7889059979195656 0.8069448365681837 0.8249836752168019 0.8430225138654202 0.8610613525140383 0.8791001911626564 0.8971390298112746 0.7995285779523665 0.8175674166009848 0.8356062552496029 0.853645093898221 0.8716839325468392 0.8897227711954574 0.9077616098440755 0.9258004484926936 0.9438392871413118 0.96187812578993 0.9799169644385481 0.8823065125796399 0.900345351228258 0.9183841898768762 0.9364230285254944 0.9544618671741125 0.9725007058227306 0.9905395444713488 1.008578383119967 1.0266172217685852 1.0446560604172033 1.0626948990658214 0.9650844472069134 0.9831232858555317 1.0011621245041498 1.0192009631527679 1.0372398018013862 1.0552786404500043 1.0733174790986224 1.0913563177472405 1.1093951563958586 1.127433995044477 1.145472833693095 0.054527166306904996 0.07256600495552315 0.09060484360414131 0.10864368225275947 0.12668252090137763 0.1447213595499958 0.16276019819861395 0.18079903684723211 0.19883787549585027 0.21687671414446844 0.2349155527930866 0.1373051009341785 0.15534393958279666 0.17338277823141482 0.19142161688003298 0.20946045552865114 0.2274992941772693 0.24553813282588746 0.26357697147450565 0.28161581012312376 0.29965464877174197 0.3176934874203601 0.22008303556145198 0.23812187421007014 0.2561607128586883 0.27419955150730646 0.2922383901559246 0.3102772288045428 0.32831606745316094 0.3463549061017791 0.36439374475039726 0.3824325833990154 0.4004714220476336 0.3028609701887255 0.32089980883734365 0.3389386474859618 0.35697748613457997 0.37501632478319813 0.3930551634318163 0.41109400208043445 0.4291328407290526 0.44717167937767077 0.46521051802628893 0.4832493566749071 0.385638904815999 0.40367774346461716 0.4217165821132353 0.4397554207618535 0.45779425941047164 0.4758330980590898 0.49387193670770796 0.5119107753563261 0.5299496140049442 0.5479884526535624 0.5660272913021807 0.46841683944327245 0.4864556780918906 0.5044945167405088 0.5225333553891269 0.540572194037745 0.5586110326863633 0.5766498713349815 0.5946887099835996 0.6127275486322177 0.6307663872808359 0.6488052259294541 0.551194774070546 0.5692336127191642 0.5872724513677823 0.6053112900164004 0.6233501286650186 0.6413889673136368 0.6594278059622549 0.677466644610873 0.6955054832594912 0.7135443219081095 0.7315831605567276 0.6339727086978194 0.6520115473464376 0.6700503859950557 0.6880892246436738 0.706128063292292 0.7241669019409103 0.7422057405895284 0.7602445792381465 0.7782834178867647 0.7963222565353829 0.814361095184001 0.716750643325093 0.7347894819737111 0.7528283206223293 0.7708671592709475 0.7889059979195656 0.8069448365681837 0.8249836752168019 0.8430225138654202 0.8610613525140383 0.8791001911626564 0.8971390298112746 0.7995285779523665 0.8175674166009848 0.8356062552496029 0.853645093898221 0.8716839325468392 0.8897227711954574 0.9077616098440755 0.9258004484926936 0.9438392871413118 0.96187812578993 0.9799169644385481 0.8823065125796399 0.900345351228258 0.9183841898768762 0.9364230285254944 0.9544618671741125 0.9725007058227306 0.9905395444713488 1.008578383119967 1.0266172217685852 1.0446560604172033 1.0626948990658214 0.9650844472069134 0.9831232858555317 1.0011621245041498 1.0192009631527679 1.0372398018013862 1.0552786404500043 1.0733174790986224 1.0913563177472405 1.1093951563958586 1.127433995044477 1.145472833693095; 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.05 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.14198039027185572 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.2339607805437114 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671 0.3259411708155671] - shape = ExtrudeGeometry((p1, p2, p3); direction, particle_spacing=0.1, n_extrude=3, - density=1000.0, tlsph=false) + shape = ExtrudeGeometry((p1, p2, p3); direction, particle_spacing=0.1, n_extrude=4, + density=1000.0) @test shape.coordinates ≈ expected_coords end From b3a979b6c58ea5ca4da037d6735f1c57c4a5f9a5 Mon Sep 17 00:00:00 2001 From: LasNikas Date: Fri, 9 Feb 2024 08:51:45 +0100 Subject: [PATCH 015/107] calculate particle spacing differently --- src/setups/extrude_geometry.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/setups/extrude_geometry.jl b/src/setups/extrude_geometry.jl index f9dc854ec..a3d0dbfac 100644 --- a/src/setups/extrude_geometry.jl +++ b/src/setups/extrude_geometry.jl @@ -152,7 +152,8 @@ function sample_plane(plane_points::NTuple{3}, particle_spacing) end end - particle_spacing_new = norm(coords[:, 1] - coords[:, 2]) + particle_spacing_new = min(norm(edge1 / num_points_edge1), + norm(edge2 / num_points_edge2)) return coords, particle_spacing_new end From 4c6bcf93f7bcf273a02814c7180076fbf8943ff0 Mon Sep 17 00:00:00 2001 From: LasNikas Date: Fri, 9 Feb 2024 15:59:55 +0100 Subject: [PATCH 016/107] add show-tests --- src/schemes/boundary/open_boundary/system.jl | 35 ++++- test/systems/open_bounary_sytem.jl | 43 ------ test/systems/open_boundary_system.jl | 130 +++++++++++++++++++ test/systems/systems.jl | 1 + 4 files changed, 163 insertions(+), 46 deletions(-) delete mode 100644 test/systems/open_bounary_sytem.jl create mode 100644 test/systems/open_boundary_system.jl diff --git a/src/schemes/boundary/open_boundary/system.jl b/src/schemes/boundary/open_boundary/system.jl index f06185c8e..768e4a2ee 100644 --- a/src/schemes/boundary/open_boundary/system.jl +++ b/src/schemes/boundary/open_boundary/system.jl @@ -22,7 +22,11 @@ struct OpenBoundarySPHSystem{BZ, NDIMS, ELTYPE <: Real, S, VF} <: FluidSystem{ND flow_direction, open_boundary_layers=0, density, velocity=zeros(length(plane_points)), pressure=0.0, velocity_function=nothing, mass=nothing) - if !isa(open_boundary_layers, Int) + if !((boundary_zone isa InFlow) || (boundary_zone isa OutFlow)) + throw(ArgumentError("`boundary_zone` must either be of type InFlow or OutFlow")) + end + + if !(open_boundary_layers isa Int) throw(ArgumentError("`open_boundary_layers` must be of type Int")) elseif open_boundary_layers < sqrt(eps()) throw(ArgumentError("`open_boundary_layers` must be positive and greater than zero")) @@ -62,8 +66,8 @@ struct OpenBoundarySPHSystem{BZ, NDIMS, ELTYPE <: Real, S, VF} <: FluidSystem{ND # Flip the outflow vector in downstream direction (boundary_zone isa OutFlow) && (spanning_set[:, 1] .*= -1) else - throw(ArgumentError("Flow direction and normal vector of " * - "$(typeof(boundary_zone))-plane do not correspond.")) + throw(ArgumentError("flow direction and normal vector of " * + "$(typeof(boundary_zone))-plane do not correspond")) end spanning_set_ = reinterpret(reshape, SVector{NDIMS, ELTYPE}, spanning_set) @@ -87,6 +91,31 @@ struct OpenBoundarySPHSystem{BZ, NDIMS, ELTYPE <: Real, S, VF} <: FluidSystem{ND end end +timer_name(::OpenBoundarySPHSystem) = "open_boundary" + +function Base.show(io::IO, system::OpenBoundarySPHSystem) + @nospecialize system # reduce precompilation time + + print(io, "OpenBoundarySPHSystem{", ndims(system), "}(") + print(io, system.boundary_zone) + print(io, ") with ", nparticles(system), " particles") +end + +function Base.show(io::IO, ::MIME"text/plain", system::OpenBoundarySPHSystem) + @nospecialize system # reduce precompilation time + + if get(io, :compact, false) + show(io, system) + else + summary_header(io, "OpenBoundarySPHSystem{$(ndims(system))}") + summary_line(io, "#particles", nparticles(system)) + summary_line(io, "boundary", system.boundary_zone) + summary_line(io, "flow direction", system.flow_direction) + summary_line(io, "width", round(norm(system.spanning_set[1]), digits=3)) + summary_footer(io) + end +end + @inline viscosity_model(system, neighbor_system::OpenBoundarySPHSystem) = system.viscosity function spanning_vectors(plane_points, zone_width) diff --git a/test/systems/open_bounary_sytem.jl b/test/systems/open_bounary_sytem.jl deleted file mode 100644 index 39f270487..000000000 --- a/test/systems/open_bounary_sytem.jl +++ /dev/null @@ -1,43 +0,0 @@ -using TrixiParticles, Test, LinearAlgebra -@testset verbose=true "OpenBoundarySPHSystem" begin - @testset verbose=true "Boundary Zone 2D" begin - boundary_zones = [InFlow(), OutFlow()] - particle_spacing = 0.2 - open_boundary_layers = 4 - - point1s = [[0.0, 0.0], [0.5, -0.5], [1.0, 0.5]] - point2s = [[0.0, 1.0], [0.2, 2.0], [2.3, 0.5]] - - @testset "Boundary Zone $boundary_zone" for boundary_zone in boundary_zones - @testset "Points $(i)" for i in eachindex(point1s) - plane_size = point2s[i] - point1s[i] - flow_directions = [ - normalize([-plane_size[2], plane_size[1]]), - -normalize([-plane_size[2], plane_size[1]]), - ] - - plane_points = [point1s[i], point2s[i]] - - @testset "Flow Direction $(j)" for j in eachindex(flow_directions) - system = OpenBoundarySPHSystem(plane_points, boundary_zone, 1.0; - flow_direction=flow_directions[j], - particle_spacing, open_boundary_layers, - density=1.0) - zone_width = open_boundary_layers * - system.initial_condition.particle_spacing - sign_ = (boundary_zone isa InFlow) ? -1 : 1 - - @test point1s[i] == system.zone_origin - @test point2s[i] - system.zone_origin == system.spanning_set[2] - @test sign_ * flow_directions[j] ≈ normalize(system.spanning_set[1]) - @test zone_width ≈ norm(system.spanning_set[1]) - end - end - end - end -end - - -points = (system.zone_origin, -system.zone_origin + system.spanning_set[2], -system.zone_origin + system.spanning_set[1]) diff --git a/test/systems/open_boundary_system.jl b/test/systems/open_boundary_system.jl new file mode 100644 index 000000000..23678806e --- /dev/null +++ b/test/systems/open_boundary_system.jl @@ -0,0 +1,130 @@ +@testset verbose=true "OpenBoundarySPHSystem" begin + @testset verbose=true "Boundary Zone 2D" begin + boundary_zones = [InFlow(), OutFlow()] + particle_spacing = 0.2 + open_boundary_layers = 4 + + point1s = [[0.0, 0.0], [0.5, -0.5], [1.0, 0.5]] + point2s = [[0.0, 1.0], [0.2, 2.0], [2.3, 0.5]] + + @testset "Boundary Zone $boundary_zone" for boundary_zone in boundary_zones + @testset "Points $(i)" for i in eachindex(point1s) + plane_size = point2s[i] - point1s[i] + flow_directions = [ + normalize([-plane_size[2], plane_size[1]]), + -normalize([-plane_size[2], plane_size[1]]), + ] + + plane_points = [point1s[i], point2s[i]] + + @testset "Flow Direction $(j)" for j in eachindex(flow_directions) + system = OpenBoundarySPHSystem(plane_points, boundary_zone, 1.0; + flow_direction=flow_directions[j], + particle_spacing, + open_boundary_layers, + density=1.0) + zone_width = open_boundary_layers * + system.initial_condition.particle_spacing + sign_ = (boundary_zone isa InFlow) ? -1 : 1 + + @test point1s[i] == system.zone_origin + @test point2s[i] - system.zone_origin == system.spanning_set[2] + @test sign_ * flow_directions[j] ≈ normalize(system.spanning_set[1]) + @test zone_width ≈ norm(system.spanning_set[1]) + end + end + end + end + + @testset verbose=true "Boundary Zone 3D" begin + boundary_zones = [InFlow(), OutFlow()] + particle_spacing = 0.05 + open_boundary_layers = 4 + + point1s = [ + [0.0, 0.0, 0.0], + [0.3113730847835541, 0.19079485535621643, -0.440864622592926], + ] + point2s = [ + [1.0, 0.0, 0.0], + [-0.10468611121177673, 0.252103328704834, -0.44965094327926636], + ] + point3s = [ + [0.0, 1.0, 0.0], + [0.3113730847835541, 0.25057315826416016, -0.02374829351902008], + ] + + @testset "Boundary Zone $boundary_zone" for boundary_zone in boundary_zones + @testset "Points $(i)" for i in eachindex(point1s) + edge1 = point2s[i] - point1s[i] + edge2 = point3s[i] - point1s[i] + + flow_directions = [ + normalize(cross(edge1, edge2)), + -normalize(cross(edge1, edge2)), + ] + + plane_points = [point1s[i], point2s[i], point3s[i]] + + @testset "Flow Direction $(j)" for j in eachindex(flow_directions) + system = OpenBoundarySPHSystem(plane_points, boundary_zone, 1.0; + flow_direction=flow_directions[j], + particle_spacing, + open_boundary_layers, + density=1.0) + zone_width = open_boundary_layers * + system.initial_condition.particle_spacing + sign_ = (boundary_zone isa InFlow) ? -1 : 1 + + @test point1s[i] == system.zone_origin + @test point2s[i] - system.zone_origin == system.spanning_set[2] + @test point3s[i] - system.zone_origin == system.spanning_set[3] + @test sign_ * flow_directions[j] ≈ normalize(system.spanning_set[1]) + @test zone_width ≈ norm(system.spanning_set[1]) + end + end + end + end + @testset verbose=true "Illegal Inputs" begin + no_rectangular_plane = [[0.2, 0.3, -0.5], [-1.0, 1.5, 0.2], [-0.2, 2.0, -0.5]] + flow_direction = [0.0, 0.0, 1.0] + error_str = "the provided points do not span a rectangular plane" + @test_throws ArgumentError(error_str) system=OpenBoundarySPHSystem(no_rectangular, + InFlow(), + 1.0; + flow_direction, + particle_spacing=0.1, + open_boundary_layers=2, + density=1.0) + + rectangular_plane = [[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0]] + flow_direction = [0.0, 1.0, 0.0] + error_str = "flow direction and normal vector of " * + "InFlow-plane do not correspond" + @test_throws ArgumentError(error_str) system=OpenBoundarySPHSystem(rectangular_plane, + InFlow(), + 1.0; + flow_direction, + particle_spacing=0.1, + open_boundary_layers=2, + density=1.0) + end + @trixi_testset "show" begin + system = OpenBoundarySPHSystem(([0.0, 0.0], [0.0, 1.0]), InFlow(), 1.0; + flow_direction=(1.0, 0.0), density=1.0, + particle_spacing=0.05, open_boundary_layers=4) + + show_compact = "OpenBoundarySPHSystem{2}(InFlow()) with 80 particles" + @test repr(system) == show_compact + show_box = """ + ┌──────────────────────────────────────────────────────────────────────────────────────────────────┐ + │ OpenBoundarySPHSystem{2} │ + │ ════════════════════════ │ + │ #particles: ………………………………………………… 80 │ + │ boundary: ……………………………………………………… InFlow() │ + │ flow direction: ……………………………………… [1.0, 0.0] │ + │ width: ……………………………………………………………… 0.2 │ + └──────────────────────────────────────────────────────────────────────────────────────────────────┘""" + @test repr("text/plain", system) == show_box + end +end diff --git a/test/systems/systems.jl b/test/systems/systems.jl index 6fe2ac7fb..933ff0704 100644 --- a/test/systems/systems.jl +++ b/test/systems/systems.jl @@ -2,3 +2,4 @@ include("wcsph_system.jl") include("edac_system.jl") include("solid_system.jl") include("boundary_system.jl") +include("open_boundary_system.jl") From 33f4fc92e12b7ae9a9fab560a51e206dc67f7b0f Mon Sep 17 00:00:00 2001 From: LasNikas Date: Fri, 9 Feb 2024 16:58:44 +0100 Subject: [PATCH 017/107] add `within_boundary_zone` --- src/schemes/boundary/open_boundary/system.jl | 33 ++++++++++++ test/systems/open_boundary_system.jl | 56 +++++++++++++++++++- 2 files changed, 88 insertions(+), 1 deletion(-) diff --git a/src/schemes/boundary/open_boundary/system.jl b/src/schemes/boundary/open_boundary/system.jl index 768e4a2ee..dceb5bdd3 100644 --- a/src/schemes/boundary/open_boundary/system.jl +++ b/src/schemes/boundary/open_boundary/system.jl @@ -118,6 +118,20 @@ end @inline viscosity_model(system, neighbor_system::OpenBoundarySPHSystem) = system.viscosity +@inline source_terms(system::OpenBoundarySPHSystem) = nothing + +@inline function particle_density(v, system::OpenBoundarySPHSystem, particle) + return system.density[particle] +end + +@inline function particle_pressure(v, system::OpenBoundarySPHSystem, particle) + return system.pressure[particle] +end + +@inline set_particle_density(particle, v, system::OpenBoundarySPHSystem, density) = system + +@inline set_particle_pressure(particle, v, system, pressure) = system + function spanning_vectors(plane_points, zone_width) # Convert to tuple @@ -147,3 +161,22 @@ function spanning_vectors(plane_points::NTuple{3}, zone_width) return hcat(c, edge1, edge2) end + +@inline function within_boundary_zone(particle_coords, system) + (; zone_origin, spanning_set) = system + particle_positon = particle_coords - zone_origin + + for dim in 1:ndims(system) + span_dim = spanning_set[dim] + # Checks whether the projection of the particle position + # falls within the range of the zone. + if !(0 <= dot(particle_positon, span_dim) <= dot(span_dim, span_dim)) + + # Particle is not in boundary zone. + return false + end + end + + # Particle is in boundary zone. + return true +end diff --git a/test/systems/open_boundary_system.jl b/test/systems/open_boundary_system.jl index 23678806e..5508461f7 100644 --- a/test/systems/open_boundary_system.jl +++ b/test/systems/open_boundary_system.jl @@ -85,11 +85,65 @@ end end end + + @testset verbose=true "Particle In Boundary Zone 3D" begin + point1 = [-0.2, -0.5, 0.0] + point2 = [0.3, 0.5, 0.0] + point3 = [0.13111173850909402, -0.665555869254547, 0.0] + + flow_direction = normalize(cross(point2 - point1, point3 - point1)) + system = OpenBoundarySPHSystem([point1, point2, point3], InFlow(), 1.0; + flow_direction, + density=1.0, particle_spacing=0.1, + open_boundary_layers=4) + + query_points = Dict( + "Behind" => ([-1.0, -1.0, 1.2], false), + "Before" => ([2.0, 2.0, -1.2], false), + "On Point 1" => (plane_points[1], true), + "On Point 2" => (plane_points[2], true), + "On Point 3" => (plane_points[3], true), + "On Point 4" => (system.spanning_set[1] + system.zone_origin, true), + "Closely On Point 1" => (plane_points[1] .+ eps() * flow_direction, false)) + + @testset "$key" for key in keys(query_points) + (particle_position, evaluation) = query_points[key] + + @test evaluation == + TrixiParticles.within_boundary_zone(particle_position, system) + end + end + + @testset verbose=true "Particle In Boundary Zone 2D" begin + plane_points = [[-0.2, -0.5], [0.3, 0.5]] + plane_size = plane_points[2] - plane_points[1] + + flow_direction = normalize([-plane_size[2], plane_size[1]]) + system = OpenBoundarySPHSystem(plane_points, InFlow(), 1.0; flow_direction, + density=1.0, + particle_spacing=0.1, open_boundary_layers=4) + + query_points = Dict( + "Behind" => ([-1.0, -1.0], false), + "Before" => ([2.0, 2.0], false), + "On Point 1" => (plane_points[1], true), + "On Point 2" => (plane_points[2], true), + "On Point 3" => (system.spanning_set[1] + system.zone_origin, true), + "Closely On Point 1" => (plane_points[1] .+ eps() * flow_direction, false)) + + @testset "$key" for key in keys(query_points) + (particle_position, evaluation) = query_points[key] + + @test evaluation == + TrixiParticles.within_boundary_zone(particle_position, system) + end + end + @testset verbose=true "Illegal Inputs" begin no_rectangular_plane = [[0.2, 0.3, -0.5], [-1.0, 1.5, 0.2], [-0.2, 2.0, -0.5]] flow_direction = [0.0, 0.0, 1.0] error_str = "the provided points do not span a rectangular plane" - @test_throws ArgumentError(error_str) system=OpenBoundarySPHSystem(no_rectangular, + @test_throws ArgumentError(error_str) system=OpenBoundarySPHSystem(no_rectangular_plane, InFlow(), 1.0; flow_direction, From f4cd24310d9710d8f4d300d17a0e671a4448b2aa Mon Sep 17 00:00:00 2001 From: LasNikas Date: Fri, 9 Feb 2024 17:11:01 +0100 Subject: [PATCH 018/107] change `floor` to `ceil` --- src/setups/extrude_geometry.jl | 2 +- test/setups/extrude_geometry.jl | 29 ++++++++++++++--------------- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/src/setups/extrude_geometry.jl b/src/setups/extrude_geometry.jl index a3d0dbfac..8d6614050 100644 --- a/src/setups/extrude_geometry.jl +++ b/src/setups/extrude_geometry.jl @@ -113,7 +113,7 @@ function sample_plane(plane_points::NTuple{2}, particle_spacing) throw(ArgumentError("all points must be 2D coordinates")) end - n_points = floor(Int, norm(plane_points[2] - plane_points[1]) / particle_spacing) + 1 + n_points = ceil(Int, norm(plane_points[2] - plane_points[1]) / particle_spacing) + 1 coords = stack(range(plane_points[1], plane_points[2], length=n_points)) particle_spacing_new = norm(coords[:, 1] - coords[:, 2]) diff --git a/test/setups/extrude_geometry.jl b/test/setups/extrude_geometry.jl index 4dfaac9c1..46764f4fe 100644 --- a/test/setups/extrude_geometry.jl +++ b/test/setups/extrude_geometry.jl @@ -39,18 +39,18 @@ @testset verbose=true "Extrude Line-Points" begin expected_coords = [ - [0.0 0.07142857142857142 0.14285714285714285 0.21428571428571427 0.2857142857142857 0.35714285714285715 0.42857142857142855 0.5 -0.07142857142857142 0.0 0.07142857142857142 0.14285714285714285 0.21428571428571427 0.2857142857142857 0.3571428571428571 0.4285714285714286 -0.14285714285714285 -0.07142857142857142 0.0 0.07142857142857142 0.14285714285714285 0.2142857142857143 0.2857142857142857 0.35714285714285715 -0.21428571428571425 -0.14285714285714282 -0.0714285714285714 2.7755575615628914e-17 0.07142857142857145 0.1428571428571429 0.2142857142857143 0.28571428571428575 -0.2857142857142857 -0.21428571428571427 -0.14285714285714285 -0.07142857142857142 0.0 0.07142857142857145 0.14285714285714285 0.2142857142857143; - 0.0 0.14285714285714285 0.2857142857142857 0.42857142857142855 0.5714285714285714 0.7142857142857143 0.8571428571428571 1.0 0.14285714285714285 0.2857142857142857 0.42857142857142855 0.5714285714285714 0.7142857142857142 0.8571428571428572 1.0 1.1428571428571428 0.2857142857142857 0.42857142857142855 0.5714285714285714 0.7142857142857142 0.8571428571428571 1.0 1.1428571428571428 1.2857142857142856 0.4285714285714285 0.5714285714285714 0.7142857142857142 0.857142857142857 0.9999999999999999 1.1428571428571428 1.2857142857142856 1.4285714285714284 0.5714285714285714 0.7142857142857142 0.8571428571428571 1.0 1.1428571428571428 1.2857142857142856 1.4285714285714284 1.5714285714285714], - [0.0 0.07142857142857142 0.14285714285714285 0.21428571428571427 0.2857142857142857 0.35714285714285715 0.42857142857142855 0.5 0.07142857142857142 0.14285714285714285 0.21428571428571427 0.2857142857142857 0.3571428571428571 0.4285714285714286 0.5 0.5714285714285714 0.14285714285714285 0.21428571428571427 0.2857142857142857 0.3571428571428571 0.42857142857142855 0.5 0.5714285714285714 0.6428571428571428 0.21428571428571425 0.2857142857142857 0.3571428571428571 0.4285714285714285 0.49999999999999994 0.5714285714285714 0.6428571428571428 0.7142857142857142 0.2857142857142857 0.3571428571428571 0.42857142857142855 0.5 0.5714285714285714 0.6428571428571428 0.7142857142857142 0.7857142857142857; - 0.0 0.14285714285714285 0.2857142857142857 0.42857142857142855 0.5714285714285714 0.7142857142857143 0.8571428571428571 1.0 -0.14285714285714285 0.0 0.14285714285714285 0.2857142857142857 0.42857142857142855 0.5714285714285714 0.7142857142857142 0.8571428571428572 -0.2857142857142857 -0.14285714285714285 0.0 0.14285714285714285 0.2857142857142857 0.4285714285714286 0.5714285714285714 0.7142857142857143 -0.4285714285714285 -0.28571428571428564 -0.1428571428571428 5.551115123125783e-17 0.1428571428571429 0.2857142857142858 0.4285714285714286 0.5714285714285715 -0.5714285714285714 -0.42857142857142855 -0.2857142857142857 -0.14285714285714285 0.0 0.1428571428571429 0.2857142857142857 0.4285714285714286], - [0.0 0.07142857142857142 0.14285714285714285 0.21428571428571427 0.2857142857142857 0.35714285714285715 0.42857142857142855 0.5 -0.14285714285714285 -0.07142857142857142 0.0 0.07142857142857142 0.14285714285714285 0.2142857142857143 0.2857142857142857 0.35714285714285715 -0.2857142857142857 -0.21428571428571427 -0.14285714285714285 -0.07142857142857142 0.0 0.07142857142857145 0.14285714285714285 0.2142857142857143 -0.4285714285714285 -0.3571428571428571 -0.28571428571428564 -0.21428571428571422 -0.1428571428571428 -0.07142857142857134 5.551115123125783e-17 0.07142857142857151 -0.5714285714285714 -0.5 -0.42857142857142855 -0.3571428571428571 -0.2857142857142857 -0.21428571428571425 -0.14285714285714285 -0.0714285714285714; - 0.0 0.14285714285714285 0.2857142857142857 0.42857142857142855 0.5714285714285714 0.7142857142857143 0.8571428571428571 1.0 0.07142857142857142 0.21428571428571427 0.3571428571428571 0.5 0.6428571428571428 0.7857142857142857 0.9285714285714285 1.0714285714285714 0.14285714285714285 0.2857142857142857 0.42857142857142855 0.5714285714285714 0.7142857142857142 0.8571428571428572 1.0 1.1428571428571428 0.21428571428571425 0.3571428571428571 0.49999999999999994 0.6428571428571428 0.7857142857142856 0.9285714285714286 1.0714285714285714 1.2142857142857142 0.2857142857142857 0.42857142857142855 0.5714285714285714 0.7142857142857142 0.8571428571428571 1.0 1.1428571428571428 1.2857142857142856], - [0.0 0.07142857142857142 0.14285714285714285 0.21428571428571427 0.2857142857142857 0.35714285714285715 0.42857142857142855 0.5 0.14285714285714285 0.21428571428571427 0.2857142857142857 0.3571428571428571 0.42857142857142855 0.5 0.5714285714285714 0.6428571428571428 0.2857142857142857 0.3571428571428571 0.42857142857142855 0.5 0.5714285714285714 0.6428571428571428 0.7142857142857142 0.7857142857142857 0.4285714285714285 0.4999999999999999 0.5714285714285714 0.6428571428571428 0.7142857142857142 0.7857142857142856 0.857142857142857 0.9285714285714285 0.5714285714285714 0.6428571428571428 0.7142857142857142 0.7857142857142857 0.8571428571428571 0.9285714285714286 1.0 1.0714285714285714; - 0.0 0.14285714285714285 0.2857142857142857 0.42857142857142855 0.5714285714285714 0.7142857142857143 0.8571428571428571 1.0 -0.07142857142857142 0.07142857142857142 0.21428571428571427 0.3571428571428571 0.5 0.6428571428571429 0.7857142857142857 0.9285714285714286 -0.14285714285714285 0.0 0.14285714285714285 0.2857142857142857 0.42857142857142855 0.5714285714285714 0.7142857142857142 0.8571428571428572 -0.21428571428571425 -0.0714285714285714 0.07142857142857145 0.2142857142857143 0.35714285714285715 0.5 0.6428571428571428 0.7857142857142858 -0.2857142857142857 -0.14285714285714285 0.0 0.14285714285714285 0.2857142857142857 0.4285714285714286 0.5714285714285714 0.7142857142857143], - [0.0 0.07142857142857142 0.14285714285714285 0.21428571428571427 0.2857142857142857 0.35714285714285715 0.42857142857142855 0.5 0.15971914124998496 0.23114771267855638 0.3025762841071278 0.37400485553569923 0.4454334269642707 0.5168619983928421 0.5882905698214135 0.659719141249985 0.3194382824999699 0.39086685392854137 0.46229542535711277 0.5337239967856842 0.6051525682142556 0.6765811396428271 0.7480097110713985 0.81943828249997 0.47915742374995485 0.5505859951785262 0.6220145666070978 0.6934431380356691 0.7648717094642405 0.8363002808928119 0.9077288523213833 0.9791574237499548 0.6388765649999398 0.7103051364285112 0.7817337078570827 0.8531622792856541 0.9245908507142255 0.9960194221427969 1.0674479935713683 1.13887656499994; - 0.0 0.14285714285714285 0.2857142857142857 0.42857142857142855 0.5714285714285714 0.7142857142857143 0.8571428571428571 1.0 0.0 0.14285714285714285 0.2857142857142857 0.42857142857142855 0.5714285714285714 0.7142857142857143 0.8571428571428571 1.0 0.0 0.14285714285714285 0.2857142857142857 0.42857142857142855 0.5714285714285714 0.7142857142857143 0.8571428571428571 1.0 0.0 0.14285714285714285 0.2857142857142857 0.42857142857142855 0.5714285714285714 0.7142857142857143 0.8571428571428571 1.0 0.0 0.14285714285714285 0.2857142857142857 0.42857142857142855 0.5714285714285714 0.7142857142857143 0.8571428571428571 1.0], - [0.0 0.07142857142857142 0.14285714285714285 0.21428571428571427 0.2857142857142857 0.35714285714285715 0.42857142857142855 0.5 0.0 0.07142857142857142 0.14285714285714285 0.21428571428571427 0.2857142857142857 0.35714285714285715 0.42857142857142855 0.5 0.0 0.07142857142857142 0.14285714285714285 0.21428571428571427 0.2857142857142857 0.35714285714285715 0.42857142857142855 0.5 0.0 0.07142857142857142 0.14285714285714285 0.21428571428571427 0.2857142857142857 0.35714285714285715 0.42857142857142855 0.5 0.0 0.07142857142857142 0.14285714285714285 0.21428571428571427 0.2857142857142857 0.35714285714285715 0.42857142857142855 0.5; - 0.0 0.14285714285714285 0.2857142857142857 0.42857142857142855 0.5714285714285714 0.7142857142857143 0.8571428571428571 1.0 0.15971914124998496 0.3025762841071278 0.4454334269642707 0.5882905698214135 0.7311477126785564 0.8740048555356993 1.016861998392842 1.159719141249985 0.3194382824999699 0.46229542535711277 0.6051525682142556 0.7480097110713985 0.8908668539285414 1.0337239967856842 1.176581139642827 1.31943828249997 0.47915742374995485 0.6220145666070978 0.7648717094642405 0.9077288523213833 1.0505859951785261 1.1934431380356691 1.336300280892812 1.479157423749955 0.6388765649999398 0.7817337078570827 0.9245908507142255 1.0674479935713683 1.2103051364285111 1.3531622792856541 1.496019422142797 1.63887656499994], + [0.0 0.0625 0.125 0.1875 0.25 0.3125 0.375 0.4375 0.5 -0.0625 0.0 0.0625 0.125 0.1875 0.25 0.3125 0.375 0.4375 -0.125 -0.0625 0.0 0.0625 0.125 0.1875 0.25 0.3125 0.375 -0.1875 -0.125 -0.0625 0.0 0.0625 0.125 0.1875 0.25 0.3125 -0.25 -0.1875 -0.125 -0.0625 0.0 0.0625 0.125 0.1875 0.25; + 0.0 0.125 0.25 0.375 0.5 0.625 0.75 0.875 1.0 0.125 0.25 0.375 0.5 0.625 0.75 0.875 1.0 1.125 0.25 0.375 0.5 0.625 0.75 0.875 1.0 1.125 1.25 0.375 0.5 0.625 0.75 0.875 1.0 1.125 1.25 1.375 0.5 0.625 0.75 0.875 1.0 1.125 1.25 1.375 1.5], + [0.0 0.0625 0.125 0.1875 0.25 0.3125 0.375 0.4375 0.5 0.0625 0.125 0.1875 0.25 0.3125 0.375 0.4375 0.5 0.5625 0.125 0.1875 0.25 0.3125 0.375 0.4375 0.5 0.5625 0.625 0.1875 0.25 0.3125 0.375 0.4375 0.5 0.5625 0.625 0.6875 0.25 0.3125 0.375 0.4375 0.5 0.5625 0.625 0.6875 0.75; + 0.0 0.125 0.25 0.375 0.5 0.625 0.75 0.875 1.0 -0.125 0.0 0.125 0.25 0.375 0.5 0.625 0.75 0.875 -0.25 -0.125 0.0 0.125 0.25 0.375 0.5 0.625 0.75 -0.375 -0.25 -0.125 0.0 0.125 0.25 0.375 0.5 0.625 -0.5 -0.375 -0.25 -0.125 0.0 0.125 0.25 0.375 0.5], + [0.0 0.0625 0.125 0.1875 0.25 0.3125 0.375 0.4375 0.5 -0.125 -0.0625 0.0 0.0625 0.125 0.1875 0.25 0.3125 0.375 -0.25 -0.1875 -0.125 -0.0625 0.0 0.0625 0.125 0.1875 0.25 -0.375 -0.3125 -0.25 -0.1875 -0.125 -0.0625 0.0 0.0625 0.125 -0.5 -0.4375 -0.375 -0.3125 -0.25 -0.1875 -0.125 -0.0625 0.0; + 0.0 0.125 0.25 0.375 0.5 0.625 0.75 0.875 1.0 0.0625 0.1875 0.3125 0.4375 0.5625 0.6875 0.8125 0.9375 1.0625 0.125 0.25 0.375 0.5 0.625 0.75 0.875 1.0 1.125 0.1875 0.3125 0.4375 0.5625 0.6875 0.8125 0.9375 1.0625 1.1875 0.25 0.375 0.5 0.625 0.75 0.875 1.0 1.125 1.25], + [0.0 0.0625 0.125 0.1875 0.25 0.3125 0.375 0.4375 0.5 0.125 0.1875 0.25 0.3125 0.375 0.4375 0.5 0.5625 0.625 0.25 0.3125 0.375 0.4375 0.5 0.5625 0.625 0.6875 0.75 0.375 0.4375 0.5 0.5625 0.625 0.6875 0.75 0.8125 0.875 0.5 0.5625 0.625 0.6875 0.75 0.8125 0.875 0.9375 1.0; + 0.0 0.125 0.25 0.375 0.5 0.625 0.75 0.875 1.0 -0.0625 0.0625 0.1875 0.3125 0.4375 0.5625 0.6875 0.8125 0.9375 -0.125 0.0 0.125 0.25 0.375 0.5 0.625 0.75 0.875 -0.1875 -0.0625 0.0625 0.1875 0.3125 0.4375 0.5625 0.6875 0.8125 -0.25 -0.125 0.0 0.125 0.25 0.375 0.5 0.625 0.75], + [0.0 0.0625 0.125 0.1875 0.25 0.3125 0.375 0.4375 0.5 0.13975424859373686 0.20225424859373686 0.26475424859373686 0.32725424859373686 0.38975424859373686 0.45225424859373686 0.5147542485937369 0.5772542485937369 0.6397542485937369 0.2795084971874737 0.3420084971874737 0.4045084971874737 0.4670084971874737 0.5295084971874737 0.5920084971874737 0.6545084971874737 0.7170084971874737 0.7795084971874737 0.4192627457812106 0.4817627457812106 0.5442627457812106 0.6067627457812106 0.6692627457812106 0.7317627457812106 0.7942627457812106 0.8567627457812106 0.9192627457812106 0.5590169943749475 0.6215169943749475 0.6840169943749475 0.7465169943749475 0.8090169943749475 0.8715169943749475 0.9340169943749475 0.9965169943749475 1.0590169943749475; + 0.0 0.125 0.25 0.375 0.5 0.625 0.75 0.875 1.0 0.0 0.125 0.25 0.375 0.5 0.625 0.75 0.875 1.0 0.0 0.125 0.25 0.375 0.5 0.625 0.75 0.875 1.0 0.0 0.125 0.25 0.375 0.5 0.625 0.75 0.875 1.0 0.0 0.125 0.25 0.375 0.5 0.625 0.75 0.875 1.0], + [0.0 0.0625 0.125 0.1875 0.25 0.3125 0.375 0.4375 0.5 0.0 0.0625 0.125 0.1875 0.25 0.3125 0.375 0.4375 0.5 0.0 0.0625 0.125 0.1875 0.25 0.3125 0.375 0.4375 0.5 0.0 0.0625 0.125 0.1875 0.25 0.3125 0.375 0.4375 0.5 0.0 0.0625 0.125 0.1875 0.25 0.3125 0.375 0.4375 0.5; + 0.0 0.125 0.25 0.375 0.5 0.625 0.75 0.875 1.0 0.13975424859373686 0.26475424859373686 0.38975424859373686 0.5147542485937369 0.6397542485937369 0.7647542485937369 0.8897542485937369 1.0147542485937369 1.1397542485937369 0.2795084971874737 0.4045084971874737 0.5295084971874737 0.6545084971874737 0.7795084971874737 0.9045084971874737 1.0295084971874737 1.1545084971874737 1.2795084971874737 0.4192627457812106 0.5442627457812106 0.6692627457812106 0.7942627457812106 0.9192627457812106 1.0442627457812106 1.1692627457812106 1.2942627457812106 1.4192627457812106 0.5590169943749475 0.6840169943749475 0.8090169943749475 0.9340169943749475 1.0590169943749475 1.1840169943749475 1.3090169943749475 1.4340169943749475 1.5590169943749475], ] @testset "Direction $i" for i in eachindex(directions) @@ -65,9 +65,8 @@ point1 = [0.0, 0.0] point2 = [0.0, 1.0] - expected_coords = [-0.05 -0.05 -0.05 -0.05 -0.05 -0.05 -0.05 -0.05 -0.05 -0.1625 -0.1625 -0.1625 -0.1625 -0.1625 -0.1625 -0.1625 -0.1625 -0.1625 -0.275 -0.275 -0.275 -0.275 -0.275 -0.275 -0.275 -0.275 -0.275 -0.3875 -0.3875 -0.3875 -0.3875 -0.3875 -0.3875 -0.3875 -0.3875 -0.3875 -0.5 -0.5 -0.5 -0.5 -0.5 -0.5 -0.5 -0.5 -0.5; - 0.05 0.1625 0.275 0.38749999999999996 0.5 0.6125 0.7249999999999999 0.8374999999999999 0.95 0.05 0.1625 0.275 0.38749999999999996 0.5 0.6125 0.7249999999999999 0.8374999999999999 0.95 0.05 0.1625 0.275 0.38749999999999996 0.5 0.6125 0.7249999999999999 0.8374999999999999 0.95 0.05 0.1625 0.275 0.38749999999999996 0.5 0.6125 0.7249999999999999 0.8374999999999999 0.95 0.05 0.1625 0.275 0.38749999999999996 0.5 0.6125 0.7249999999999999 0.8374999999999999 0.95] - + expected_coords = [-0.05 -0.05 -0.05 -0.05 -0.05 -0.05 -0.05 -0.05 -0.05 -0.05 -0.15 -0.15 -0.15 -0.15 -0.15 -0.15 -0.15 -0.15 -0.15 -0.15 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.35 -0.35 -0.35 -0.35 -0.35 -0.35 -0.35 -0.35 -0.35 -0.35 -0.44999999999999996 -0.44999999999999996 -0.44999999999999996 -0.44999999999999996 -0.44999999999999996 -0.44999999999999996 -0.44999999999999996 -0.44999999999999996 -0.44999999999999996 -0.44999999999999996; + 0.05 0.15 0.24999999999999997 0.35 0.44999999999999996 0.55 0.65 0.7499999999999999 0.8499999999999999 0.95 0.05 0.15 0.24999999999999997 0.35 0.44999999999999996 0.55 0.65 0.7499999999999999 0.8499999999999999 0.95 0.05 0.15 0.24999999999999997 0.35 0.44999999999999996 0.55 0.65 0.7499999999999999 0.8499999999999999 0.95 0.05 0.15 0.24999999999999997 0.35 0.44999999999999996 0.55 0.65 0.7499999999999999 0.8499999999999999 0.95 0.05 0.15 0.24999999999999997 0.35 0.44999999999999996 0.55 0.65 0.7499999999999999 0.8499999999999999 0.95] shape = ExtrudeGeometry((point1, point2); direction=[-1.0, 0.0], particle_spacing=0.1, n_extrude=5, density=1.0) From 6c6a464b1068b0a116120d4313020b88dfecbcb1 Mon Sep 17 00:00:00 2001 From: LasNikas Date: Mon, 12 Feb 2024 12:06:50 +0100 Subject: [PATCH 019/107] boundary zone tests --- test/systems/open_boundary_system.jl | 58 ++++++++++++++-------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/test/systems/open_boundary_system.jl b/test/systems/open_boundary_system.jl index 5508461f7..3027176a0 100644 --- a/test/systems/open_boundary_system.jl +++ b/test/systems/open_boundary_system.jl @@ -7,7 +7,7 @@ point1s = [[0.0, 0.0], [0.5, -0.5], [1.0, 0.5]] point2s = [[0.0, 1.0], [0.2, 2.0], [2.3, 0.5]] - @testset "Boundary Zone $boundary_zone" for boundary_zone in boundary_zones + @testset "$boundary_zone" for boundary_zone in boundary_zones @testset "Points $(i)" for i in eachindex(point1s) plane_size = point2s[i] - point1s[i] flow_directions = [ @@ -54,7 +54,7 @@ [0.3113730847835541, 0.25057315826416016, -0.02374829351902008], ] - @testset "Boundary Zone $boundary_zone" for boundary_zone in boundary_zones + @testset "$boundary_zone" for boundary_zone in boundary_zones @testset "Points $(i)" for i in eachindex(point1s) edge1 = point2s[i] - point1s[i] edge2 = point3s[i] - point1s[i] @@ -86,24 +86,21 @@ end end - @testset verbose=true "Particle In Boundary Zone 3D" begin - point1 = [-0.2, -0.5, 0.0] - point2 = [0.3, 0.5, 0.0] - point3 = [0.13111173850909402, -0.665555869254547, 0.0] + @testset verbose=true "Particle In Boundary Zone 2D" begin + plane_points = [[-0.2, -0.5], [0.3, 0.5]] + plane_size = plane_points[2] - plane_points[1] - flow_direction = normalize(cross(point2 - point1, point3 - point1)) - system = OpenBoundarySPHSystem([point1, point2, point3], InFlow(), 1.0; - flow_direction, - density=1.0, particle_spacing=0.1, - open_boundary_layers=4) + flow_direction = normalize([-plane_size[2], plane_size[1]]) + system = OpenBoundarySPHSystem(plane_points, InFlow(), 1.0; flow_direction, + density=1.0, + particle_spacing=0.1, open_boundary_layers=4) query_points = Dict( - "Behind" => ([-1.0, -1.0, 1.2], false), - "Before" => ([2.0, 2.0, -1.2], false), + "Behind" => ([-1.0, -1.0], false), + "Before" => ([2.0, 2.0], false), "On Point 1" => (plane_points[1], true), "On Point 2" => (plane_points[2], true), - "On Point 3" => (plane_points[3], true), - "On Point 4" => (system.spanning_set[1] + system.zone_origin, true), + "On Point 3" => (system.spanning_set[1] + system.zone_origin, true), "Closely On Point 1" => (plane_points[1] .+ eps() * flow_direction, false)) @testset "$key" for key in keys(query_points) @@ -114,22 +111,25 @@ end end - @testset verbose=true "Particle In Boundary Zone 2D" begin - plane_points = [[-0.2, -0.5], [0.3, 0.5]] - plane_size = plane_points[2] - plane_points[1] + @testset verbose=true "Particle In Boundary Zone 3D" begin + point1 = [-0.2, -0.5, 0.0] + point2 = [0.3, 0.5, 0.0] + point3 = [0.13111173850909402, -0.665555869254547, 0.0] - flow_direction = normalize([-plane_size[2], plane_size[1]]) - system = OpenBoundarySPHSystem(plane_points, InFlow(), 1.0; flow_direction, - density=1.0, - particle_spacing=0.1, open_boundary_layers=4) + flow_direction = normalize(cross(point2 - point1, point3 - point1)) + system = OpenBoundarySPHSystem([point1, point2, point3], InFlow(), 1.0; + flow_direction, + density=1.0, particle_spacing=0.1, + open_boundary_layers=4) query_points = Dict( - "Behind" => ([-1.0, -1.0], false), - "Before" => ([2.0, 2.0], false), - "On Point 1" => (plane_points[1], true), - "On Point 2" => (plane_points[2], true), - "On Point 3" => (system.spanning_set[1] + system.zone_origin, true), - "Closely On Point 1" => (plane_points[1] .+ eps() * flow_direction, false)) + "Behind" => ([-1.0, -1.0, 1.2], false), + "Before" => ([2.0, 2.0, -1.2], false), + "On Point 1" => (point1, true), + "On Point 2" => (point2, true), + "On Point 3" => (point3, true), + "On Point 4" => (system.spanning_set[1] + system.zone_origin, true), + "Closely On Point 1" => (point1 .+ eps() * flow_direction, false)) @testset "$key" for key in keys(query_points) (particle_position, evaluation) = query_points[key] @@ -163,7 +163,7 @@ open_boundary_layers=2, density=1.0) end - @trixi_testset "show" begin + @testset "show" begin system = OpenBoundarySPHSystem(([0.0, 0.0], [0.0, 1.0]), InFlow(), 1.0; flow_direction=(1.0, 0.0), density=1.0, particle_spacing=0.05, open_boundary_layers=4) From 99645bbe7d8bdef12b753799e6a28089c5aafd80 Mon Sep 17 00:00:00 2001 From: LasNikas Date: Tue, 13 Feb 2024 16:12:23 +0100 Subject: [PATCH 020/107] add `evaluate_characteristics` --- src/general/semidiscretization.jl | 11 + src/schemes/boundary/open_boundary/system.jl | 208 ++++++++++++++++++- 2 files changed, 210 insertions(+), 9 deletions(-) diff --git a/src/general/semidiscretization.jl b/src/general/semidiscretization.jl index e2306f65d..33fa841f3 100644 --- a/src/general/semidiscretization.jl +++ b/src/general/semidiscretization.jl @@ -130,6 +130,17 @@ end return compact_support(smoothing_kernel, smoothing_length) end +@inline function compact_support(system::OpenBoundarySPHSystem, neighbor) + # Use the compact support of the fluid + return compact_support(neighbor, system) +end + +@inline function compact_support(system::OpenBoundarySPHSystem, + neighbor::OpenBoundarySPHSystem) + # This NHS is never used + return 0.0 +end + @inline function compact_support(system::TotalLagrangianSPHSystem, neighbor::TotalLagrangianSPHSystem) (; smoothing_kernel, smoothing_length) = system diff --git a/src/schemes/boundary/open_boundary/system.jl b/src/schemes/boundary/open_boundary/system.jl index dceb5bdd3..fb280304b 100644 --- a/src/schemes/boundary/open_boundary/system.jl +++ b/src/schemes/boundary/open_boundary/system.jl @@ -2,7 +2,7 @@ struct InFlow end struct OutFlow end -struct OpenBoundarySPHSystem{BZ, NDIMS, ELTYPE <: Real, S, VF} <: FluidSystem{NDIMS} +struct OpenBoundarySPHSystem{BZ, NDIMS, ELTYPE <: Real, S, VF, PF, DF} <: System{NDIMS} initial_condition :: InitialCondition{ELTYPE} mass :: Array{ELTYPE, 1} # [particle] density :: Array{ELTYPE, 1} # [particle] @@ -16,12 +16,15 @@ struct OpenBoundarySPHSystem{BZ, NDIMS, ELTYPE <: Real, S, VF} <: FluidSystem{ND zone_origin :: SVector{NDIMS, ELTYPE} spanning_set :: S velocity_function :: VF + pressure_function :: PF + density_function :: DF function OpenBoundarySPHSystem(plane_points, boundary_zone, sound_speed; sample_geometry=plane_points, particle_spacing, flow_direction, open_boundary_layers=0, density, - velocity=zeros(length(plane_points)), - pressure=0.0, velocity_function=nothing, mass=nothing) + velocity=zeros(length(plane_points)), mass=nothing, + pressure=0.0, velocity_function=nothing, + pressure_function=nothing, density_function=nothing) if !((boundary_zone isa InFlow) || (boundary_zone isa OutFlow)) throw(ArgumentError("`boundary_zone` must either be of type InFlow or OutFlow")) end @@ -80,14 +83,16 @@ struct OpenBoundarySPHSystem{BZ, NDIMS, ELTYPE <: Real, S, VF} <: FluidSystem{ND volume = similar(initial_condition.density) characteristics = zeros(ELTYPE, 3, length(mass)) - previous_characteristics = zeros(ELTYPE, 4, length(mass)) + previous_characteristics = zeros(ELTYPE, 3, length(mass)) return new{typeof(boundary_zone), NDIMS, ELTYPE, typeof(spanning_set_), - typeof(velocity_function)}(initial_condition, mass, density, volume, - pressure, characteristics, - previous_characteristics, sound_speed, - boundary_zone, flow_direction_, zone_origin, - spanning_set_, velocity_function) + typeof(velocity_function), typeof(pressure_function), + typeof(density_function)}(initial_condition, mass, density, volume, + pressure, characteristics, + previous_characteristics, sound_speed, + boundary_zone, flow_direction_, zone_origin, + spanning_set_, velocity_function, + pressure_function, density_function) end end @@ -120,6 +125,8 @@ end @inline source_terms(system::OpenBoundarySPHSystem) = nothing +@inline hydrodynamic_mass(system::OpenBoundarySPHSystem, particle) = system.mass[particle] + @inline function particle_density(v, system::OpenBoundarySPHSystem, particle) return system.density[particle] end @@ -180,3 +187,186 @@ end # Particle is in boundary zone. return true end + +function update_final!(system::OpenBoundarySPHSystem, v, u, v_ode, u_ode, semi, t) + evaluate_characteristics!(system, v, u, v_ode, u_ode, semi, t) +end + +# ==== Characteristics +# J1: Associated with convection and entropy and propagates at flow velocity. +# J2: Propagates downstream to the local flow +# J3: Propagates upstream to the local flow +function evaluate_characteristics!(system, v, u, v_ode, u_ode, semi, t) + (; volume, characteristics, previous_characteristics, boundary_zone) = system + + for particle in eachparticle(system) + previous_characteristics[1, particle] = characteristics[1, particle] + previous_characteristics[2, particle] = characteristics[2, particle] + previous_characteristics[3, particle] = characteristics[3, particle] + end + + set_zero!(characteristics) + set_zero!(volume) + + # Use all other systems for the characteristics + @trixi_timeit timer() "Evaluate Characteristics" foreach_system(semi) do neighbor_system + evaluate_characteristics!(system, neighbor_system, v, u, v_ode, u_ode, semi, t) + end + + # Only some of the in-/outlet particles are in the influence of the interior particles. + # Thus, we find the characteristics for the particle which are outside the influence + # using the average of the values of the previous time step. + @threaded for particle in each_moving_particle(system) + + # Particle is outside of the influence of interior particles + if isapprox(volume[particle], 0.0) + + # Using the average of the values at the previous time step for particles which + # are outside of the influence of interior particles. + avg_J1 = 0.0 + avg_J2 = 0.0 + avg_J3 = 0.0 + counter = 0 + + for neighbor in each_moving_particle(system) + # Make sure that only neighbors in the influence of + # the interior particles are used. + if volume[neighbor] > sqrt(eps()) + avg_J1 += previous_characteristics[1, neighbor] + avg_J2 += previous_characteristics[2, neighbor] + avg_J3 += previous_characteristics[3, neighbor] + counter += 1 + end + end + + characteristics[1, particle] = avg_J1 / counter + characteristics[2, particle] = avg_J2 / counter + characteristics[3, particle] = avg_J3 / counter + else + characteristics[1, particle] /= volume[particle] + characteristics[2, particle] /= volume[particle] + characteristics[3, particle] /= volume[particle] + end + prescribe_conditions!(characteristics, particle, boundary_zone) + end + + return system +end + +evaluate_characteristics!(system, neighbor_system, v, u, v_ode, u_ode, semi, t) = system + +function evaluate_characteristics!(system, neighbor_system::FluidSystem, + v, u, v_ode, u_ode, semi, t) + (; volume, sound_speed, characteristics, + velocity_function, density_function, pressure_function, flow_direction) = system + + v_neighbor_system = wrap_v(v_ode, neighbor_system, semi) + u_neighbor_system = wrap_u(u_ode, neighbor_system, semi) + + nhs = get_neighborhood_search(system, neighbor_system, semi) + + system_coords = current_coordinates(u, system) + neighbor_coords = current_coordinates(u_neighbor_system, neighbor_system) + + # Loop over all interior neighbors within the kernel cutoff. + for_particle_neighbor(system, neighbor_system, system_coords, neighbor_coords, + nhs) do particle, neighbor, pos_diff, distance + # Determine current and prescribed quantities + rho = particle_density(v_neighbor_system, neighbor_system, neighbor) + rho_ref = reference_density(system, density_function, + neighbor, u_neighbor_system, t) + + p = particle_pressure(v_neighbor_system, neighbor_system, neighbor) + p_ref = reference_pressure(system, pressure_function, + neighbor, u_neighbor_system, t) + + v_neighbor = current_velocity(v_neighbor_system, neighbor_system, neighbor) + v_neighbor_ref = reference_velocity(system, velocity_function, + neighbor, u_neighbor_system, t) + + # Determine characteristic variables + density_term = -sound_speed^2 * (rho - rho_ref) + pressure_term = p - p_ref + velocity_term = rho * sound_speed * + (dot(v_neighbor - v_neighbor_ref, flow_direction)) + + kernel_ = smoothing_kernel(neighbor_system, distance) + + characteristics[1, particle] += (density_term + pressure_term) * kernel_ + characteristics[2, particle] += (velocity_term + pressure_term) * kernel_ + characteristics[3, particle] += (-velocity_term + pressure_term) * kernel_ + + volume[particle] += kernel_ + end + + return system +end + +@inline function prescribe_conditions!(characteristics, particle, ::OutFlow) + # J3 is prescribed (i.e. determined from the exterior of the domain). + # J1 and J2 is transimtted from the domain interior. + characteristics[3, particle] = zero(eltype(characteristics)) + + return characteristics +end + +@inline function prescribe_conditions!(characteristics, particle, ::InFlow) + # Allow only J3 to propagate upstream to the boundary + characteristics[1, particle] = zero(eltype(characteristics)) + characteristics[2, particle] = zero(eltype(characteristics)) + + return characteristics +end + +function write_v0!(v0, system::OpenBoundarySPHSystem) + (; initial_condition) = system + + for particle in eachparticle(system) + # Write particle velocities + for dim in 1:ndims(system) + v0[dim, particle] = initial_condition.velocity[dim, particle] + end + end + + return v0 +end + +function write_u0!(u0, system::OpenBoundarySPHSystem) + (; initial_condition) = system + + for particle in eachparticle(system) + # Write particle velocities + for dim in 1:ndims(system) + u0[dim, particle] = initial_condition.coordinates[dim, particle] + end + end + + return u0 +end + +function reference_velocity(system, velocity_function, particle, u, t) + position = current_coords(u, system, particle) + return SVector{ndims(system)}(velocity_function(position, t)) +end + +function reference_velocity(system, ::Nothing, particle, u, t) + return extract_svector(system.initial_condition.velocity, system, particle) +end + +function reference_pressure(system, pressure_function, particle, u, t) + position = current_coords(u, system, particle) + return pressure_function(position, t) +end + +function reference_pressure(system, ::Nothing, particle, u, t) + return system.initial_condition.pressure[particle] +end + +function reference_density(system, density_function, particle, u, t) + position = current_coords(u, system, particle) + return density_function(position, t) +end + +function reference_density(system, ::Nothing, particle, u, t) + return system.initial_condition.density[particle] +end From 22847330ec77537060fa1e329e4dd26ab8eed279 Mon Sep 17 00:00:00 2001 From: LasNikas Date: Tue, 13 Feb 2024 16:24:06 +0100 Subject: [PATCH 021/107] add tests --- .../open_boundary/characteristic_variables.jl | 122 ++++++++++++++++++ test/schemes/schemes.jl | 1 + 2 files changed, 123 insertions(+) create mode 100644 test/schemes/boundary/open_boundary/characteristic_variables.jl diff --git a/test/schemes/boundary/open_boundary/characteristic_variables.jl b/test/schemes/boundary/open_boundary/characteristic_variables.jl new file mode 100644 index 000000000..b9620bc4e --- /dev/null +++ b/test/schemes/boundary/open_boundary/characteristic_variables.jl @@ -0,0 +1,122 @@ +@testset verbose=true "Characteristic Variables" begin + particle_spacing = 0.1 + boundary_zones = [InFlow(), OutFlow()] + + # Number of boundary particles in the influence of fluid particles + influenced_particles = [20, 52, 26] + + open_boundary_layers = 8 + sound_speed = 20.0 + density = 1000.0 + pressure = 5.0 + + smoothing_kernel = SchoenbergCubicSplineKernel{2}() + smoothing_length = 1.2particle_spacing + + # Prescribed quantities + velocity_function = (pos, t) -> [1.0, 0.0] * t + pressure_function = (pos, t) -> 50_000.0 * t + density_function = (pos, t) -> 1000.0 * t + + # Plane points of open boundary + point1s = [[0.0, 0.0], [0.5, -0.5], [1.0, 0.5]] + point2s = [[0.0, 1.0], [0.2, 2.0], [2.3, 0.5]] + + @testset "$boundary_zone" for boundary_zone in boundary_zones + @testset "Points $(i)" for i in eachindex(point1s) + n_influenced = influenced_particles[i] + + plane_points = [point1s[i], point2s[i]] + + plane_size = plane_points[2] - plane_points[1] + flow_directions = [ + normalize([-plane_size[2], plane_size[1]]), + -normalize([-plane_size[2], plane_size[1]]), + ] + + @testset "Flow Direction $(j)" for j in eachindex(flow_directions) + flow_direction = flow_directions[j] + + inlet_system = OpenBoundarySPHSystem(plane_points, boundary_zone, + sound_speed; flow_direction, + particle_spacing, open_boundary_layers, + density, velocity_function, + pressure_function, density_function) + + sign_ = (boundary_zone isa InFlow) ? 1 : -1 + fluid = ExtrudeGeometry(plane_points; particle_spacing, n_extrude=4, + density, pressure, + direction=(sign_ * flow_direction)) + + fluid_system = EntropicallyDampedSPHSystem(fluid, smoothing_kernel, + smoothing_length, sound_speed) + + semi = Semidiscretization(fluid_system, inlet_system) + + ode = semidiscretize(semi, (0.0, 5.0)) + + v0_ode, u0_ode = ode.u0.x + v = TrixiParticles.wrap_v(v0_ode, inlet_system, semi) + u = TrixiParticles.wrap_u(u0_ode, inlet_system, semi) + + # ==== Characteristic Variables + # `J1 = -sound_speed^2 * (rho - rho_ref) + (p - p_ref)` + # `J2 = rho * sound_speed * (v - v_ref) + (p - p_ref)` + # `J3 = - rho * sound_speed * (v - v_ref) + (p - p_ref)` + function J1(t) + return -sound_speed^2 * (density - density_function(0, t)) + + (pressure - pressure_function(0, t)) + end + function J2(t) + return density * sound_speed * + dot(-velocity_function(0, t), flow_direction) + + (pressure - pressure_function(0, t)) + end + function J3(t) + return -density * sound_speed * + dot(-velocity_function(0, t), flow_direction) + + (pressure - pressure_function(0, t)) + end + + # First evaluation + t1 = 2.0 + TrixiParticles.evaluate_characteristics!(inlet_system, + v, u, v0_ode, u0_ode, semi, t1) + evaluated_vars1 = inlet_system.characteristics + + if boundary_zone isa InFlow + @test all(isapprox.(evaluated_vars1[1, :], 0.0)) + @test all(isapprox.(evaluated_vars1[2, :], 0.0)) + @test all(isapprox.(evaluated_vars1[3, 1:n_influenced], J3(t1))) + @test all(isapprox.(evaluated_vars1[3, (n_influenced + 1):end], 0.0)) + + elseif boundary_zone isa OutFlow + @test all(isapprox.(evaluated_vars1[1, 1:n_influenced], J1(t1))) + @test all(isapprox.(evaluated_vars1[2, 1:n_influenced], J2(t1))) + @test all(isapprox.(evaluated_vars1[1:2, (n_influenced + 1):end], 0.0)) + @test all(isapprox.(evaluated_vars1[3, :], 0.0)) + end + + # Second evaluation + t2 = 3.0 + TrixiParticles.evaluate_characteristics!(inlet_system, + v, u, v0_ode, u0_ode, semi, t2) + evaluated_vars2 = inlet_system.characteristics + + if boundary_zone isa InFlow + @test all(isapprox.(evaluated_vars2[1, :], 0.0)) + @test all(isapprox.(evaluated_vars2[2, :], 0.0)) + @test all(isapprox.(evaluated_vars2[3, 1:n_influenced], J3(t2))) + @test all(isapprox.(evaluated_vars2[3, (n_influenced + 1):end], J3(t1))) + + elseif boundary_zone isa OutFlow + @test all(isapprox.(evaluated_vars2[1, 1:n_influenced], J1(t2))) + @test all(isapprox.(evaluated_vars2[2, 1:n_influenced], J2(t2))) + @test all(isapprox.(evaluated_vars2[1, (n_influenced + 1):end], J1(t1))) + @test all(isapprox.(evaluated_vars2[2, (n_influenced + 1):end], J2(t1))) + @test all(isapprox.(evaluated_vars2[3, :], 0.0)) + end + end + end + end +end diff --git a/test/schemes/schemes.jl b/test/schemes/schemes.jl index 2e5e609e5..c25bbba21 100644 --- a/test/schemes/schemes.jl +++ b/test/schemes/schemes.jl @@ -1,4 +1,5 @@ include("solid/total_lagrangian_sph/total_lagrangian_sph.jl") include("boundary/dummy_particles/dummy_particles.jl") include("boundary/monaghan_kajtar/monaghan_kajtar.jl") +include("boundary/open_boundary/characteristic_variables.jl") include("fluid/fluid.jl") From 59bdaef7cbefe1563e39aa6bda8f39183810a9a7 Mon Sep 17 00:00:00 2001 From: LasNikas Date: Tue, 13 Feb 2024 18:09:24 +0100 Subject: [PATCH 022/107] add reference functions --- src/schemes/boundary/open_boundary/system.jl | 99 ++++++++++--------- .../open_boundary/characteristic_variables.jl | 22 ++--- test/systems/open_boundary_system.jl | 40 ++++++++ 3 files changed, 105 insertions(+), 56 deletions(-) diff --git a/src/schemes/boundary/open_boundary/system.jl b/src/schemes/boundary/open_boundary/system.jl index fb280304b..5e10a0c52 100644 --- a/src/schemes/boundary/open_boundary/system.jl +++ b/src/schemes/boundary/open_boundary/system.jl @@ -2,7 +2,7 @@ struct InFlow end struct OutFlow end -struct OpenBoundarySPHSystem{BZ, NDIMS, ELTYPE <: Real, S, VF, PF, DF} <: System{NDIMS} +struct OpenBoundarySPHSystem{BZ, NDIMS, ELTYPE <: Real, S, RV, RP, RD} <: System{NDIMS} initial_condition :: InitialCondition{ELTYPE} mass :: Array{ELTYPE, 1} # [particle] density :: Array{ELTYPE, 1} # [particle] @@ -15,16 +15,16 @@ struct OpenBoundarySPHSystem{BZ, NDIMS, ELTYPE <: Real, S, VF, PF, DF} <: System flow_direction :: SVector{NDIMS, ELTYPE} zone_origin :: SVector{NDIMS, ELTYPE} spanning_set :: S - velocity_function :: VF - pressure_function :: PF - density_function :: DF + reference_velocity :: RV + reference_pressure :: RP + reference_density :: RD function OpenBoundarySPHSystem(plane_points, boundary_zone, sound_speed; sample_geometry=plane_points, particle_spacing, flow_direction, open_boundary_layers=0, density, - velocity=zeros(length(plane_points)), mass=nothing, - pressure=0.0, velocity_function=nothing, - pressure_function=nothing, density_function=nothing) + velocity=zeros(length(flow_direction)), mass=nothing, + pressure=0.0, reference_velocity=velocity, + reference_pressure=pressure, reference_density=density) if !((boundary_zone isa InFlow) || (boundary_zone isa OutFlow)) throw(ArgumentError("`boundary_zone` must either be of type InFlow or OutFlow")) end @@ -47,11 +47,34 @@ struct OpenBoundarySPHSystem{BZ, NDIMS, ELTYPE <: Real, S, VF, PF, DF} <: System n_extrude=open_boundary_layers, velocity, mass, density, pressure) - zone_width = open_boundary_layers * initial_condition.particle_spacing - NDIMS = ndims(initial_condition) ELTYPE = eltype(initial_condition) + if !(reference_velocity isa Function || + (reference_velocity isa Vector && length(reference_velocity) == NDIMS)) + throw(ArgumentError("`reference_velocity` must be either a function mapping " * + "each particle's coordinates and time to its velocity or a " * + "vector of length $NDIMS for a $(NDIMS)D problem")) + else + reference_velocity_ = wrap_reference_function(reference_velocity, Val(NDIMS)) + end + + if !(reference_pressure isa Function || reference_pressure isa Real) + throw(ArgumentError("`reference_pressure` must be either a function mapping " * + "each particle's coordinates and time to its pressure or a scalar")) + else + reference_pressure_ = wrap_reference_function(reference_pressure, Val(NDIMS)) + end + + if !(reference_density isa Function || reference_density isa Real) + throw(ArgumentError("`reference_density` must be either a function mapping " * + "each particle's coordinates and time to its density or a scalar")) + else + reference_density_ = wrap_reference_function(reference_density, Val(NDIMS)) + end + + zone_width = open_boundary_layers * initial_condition.particle_spacing + # Vectors spanning the boundary zone/box. spanning_set = spanning_vectors(plane_points, zone_width) @@ -86,13 +109,13 @@ struct OpenBoundarySPHSystem{BZ, NDIMS, ELTYPE <: Real, S, VF, PF, DF} <: System previous_characteristics = zeros(ELTYPE, 3, length(mass)) return new{typeof(boundary_zone), NDIMS, ELTYPE, typeof(spanning_set_), - typeof(velocity_function), typeof(pressure_function), - typeof(density_function)}(initial_condition, mass, density, volume, - pressure, characteristics, - previous_characteristics, sound_speed, - boundary_zone, flow_direction_, zone_origin, - spanning_set_, velocity_function, - pressure_function, density_function) + typeof(reference_velocity_), typeof(reference_pressure_), + typeof(reference_density_)}(initial_condition, mass, density, volume, + pressure, characteristics, + previous_characteristics, sound_speed, + boundary_zone, flow_direction_, zone_origin, + spanning_set_, reference_velocity_, + reference_pressure_, reference_density_) end end @@ -257,8 +280,8 @@ evaluate_characteristics!(system, neighbor_system, v, u, v_ode, u_ode, semi, t) function evaluate_characteristics!(system, neighbor_system::FluidSystem, v, u, v_ode, u_ode, semi, t) - (; volume, sound_speed, characteristics, - velocity_function, density_function, pressure_function, flow_direction) = system + (; volume, sound_speed, characteristics, flow_direction, + reference_velocity, reference_pressure, reference_density) = system v_neighbor_system = wrap_v(v_ode, neighbor_system, semi) u_neighbor_system = wrap_u(u_ode, neighbor_system, semi) @@ -271,18 +294,17 @@ function evaluate_characteristics!(system, neighbor_system::FluidSystem, # Loop over all interior neighbors within the kernel cutoff. for_particle_neighbor(system, neighbor_system, system_coords, neighbor_coords, nhs) do particle, neighbor, pos_diff, distance + neighbor_position = current_coords(u_neighbor_system, neighbor_system, neighbor) + # Determine current and prescribed quantities rho = particle_density(v_neighbor_system, neighbor_system, neighbor) - rho_ref = reference_density(system, density_function, - neighbor, u_neighbor_system, t) + rho_ref = reference_density(neighbor_position, t) p = particle_pressure(v_neighbor_system, neighbor_system, neighbor) - p_ref = reference_pressure(system, pressure_function, - neighbor, u_neighbor_system, t) + p_ref = reference_pressure(neighbor_position, t) v_neighbor = current_velocity(v_neighbor_system, neighbor_system, neighbor) - v_neighbor_ref = reference_velocity(system, velocity_function, - neighbor, u_neighbor_system, t) + v_neighbor_ref = reference_velocity(neighbor_position, t) # Determine characteristic variables density_term = -sound_speed^2 * (rho - rho_ref) @@ -344,29 +366,16 @@ function write_u0!(u0, system::OpenBoundarySPHSystem) return u0 end -function reference_velocity(system, velocity_function, particle, u, t) - position = current_coords(u, system, particle) - return SVector{ndims(system)}(velocity_function(position, t)) -end - -function reference_velocity(system, ::Nothing, particle, u, t) - return extract_svector(system.initial_condition.velocity, system, particle) -end - -function reference_pressure(system, pressure_function, particle, u, t) - position = current_coords(u, system, particle) - return pressure_function(position, t) -end - -function reference_pressure(system, ::Nothing, particle, u, t) - return system.initial_condition.pressure[particle] +function wrap_reference_function(function_::Function, ::Val) + # Already a function + return function_ end -function reference_density(system, density_function, particle, u, t) - position = current_coords(u, system, particle) - return density_function(position, t) +function wrap_reference_function(constant_scalar::Number, ::Val) + return (coords, t) -> constant_scalar end -function reference_density(system, ::Nothing, particle, u, t) - return system.initial_condition.density[particle] +# For vectors and tuples +function wrap_reference_function(constant_vector, ::Val{NDIMS}) where {NDIMS} + return (coords, t) -> SVector{NDIMS}(constant_vector) end diff --git a/test/schemes/boundary/open_boundary/characteristic_variables.jl b/test/schemes/boundary/open_boundary/characteristic_variables.jl index b9620bc4e..ee8f4a4b4 100644 --- a/test/schemes/boundary/open_boundary/characteristic_variables.jl +++ b/test/schemes/boundary/open_boundary/characteristic_variables.jl @@ -14,9 +14,9 @@ smoothing_length = 1.2particle_spacing # Prescribed quantities - velocity_function = (pos, t) -> [1.0, 0.0] * t - pressure_function = (pos, t) -> 50_000.0 * t - density_function = (pos, t) -> 1000.0 * t + reference_velocity = (pos, t) -> [1.0, 0.0] * t + reference_pressure = (pos, t) -> 50_000.0 * t + reference_density = (pos, t) -> 1000.0 * t # Plane points of open boundary point1s = [[0.0, 0.0], [0.5, -0.5], [1.0, 0.5]] @@ -40,8 +40,8 @@ inlet_system = OpenBoundarySPHSystem(plane_points, boundary_zone, sound_speed; flow_direction, particle_spacing, open_boundary_layers, - density, velocity_function, - pressure_function, density_function) + density, reference_velocity, + reference_pressure, reference_density) sign_ = (boundary_zone isa InFlow) ? 1 : -1 fluid = ExtrudeGeometry(plane_points; particle_spacing, n_extrude=4, @@ -64,18 +64,18 @@ # `J2 = rho * sound_speed * (v - v_ref) + (p - p_ref)` # `J3 = - rho * sound_speed * (v - v_ref) + (p - p_ref)` function J1(t) - return -sound_speed^2 * (density - density_function(0, t)) + - (pressure - pressure_function(0, t)) + return -sound_speed^2 * (density - reference_density(0, t)) + + (pressure - reference_pressure(0, t)) end function J2(t) return density * sound_speed * - dot(-velocity_function(0, t), flow_direction) + - (pressure - pressure_function(0, t)) + dot(-reference_velocity(0, t), flow_direction) + + (pressure - reference_pressure(0, t)) end function J3(t) return -density * sound_speed * - dot(-velocity_function(0, t), flow_direction) + - (pressure - pressure_function(0, t)) + dot(-reference_velocity(0, t), flow_direction) + + (pressure - reference_pressure(0, t)) end # First evaluation diff --git a/test/systems/open_boundary_system.jl b/test/systems/open_boundary_system.jl index 3027176a0..0394f4df6 100644 --- a/test/systems/open_boundary_system.jl +++ b/test/systems/open_boundary_system.jl @@ -162,6 +162,46 @@ particle_spacing=0.1, open_boundary_layers=2, density=1.0) + + error_str = "`reference_velocity` must be either a function mapping " * + "each particle's coordinates and time to its velocity or a " * + "vector of length 2 for a 2D problem" + reference_velocity = 1.0 + @test_throws ArgumentError(error_str) system=OpenBoundarySPHSystem(([0.0, 0.0], + [0.0, 1.0]), + InFlow(), 1.0; + flow_direction=(1.0, + 0.0), + particle_spacing=0.1, + reference_velocity, + open_boundary_layers=2, + density=1.0) + + error_str = "`reference_pressure` must be either a function mapping " * + "each particle's coordinates and time to its pressure or a scalar" + reference_pressure = [1.0, 1.0] + @test_throws ArgumentError(error_str) system=OpenBoundarySPHSystem(([0.0, 0.0], + [0.0, 1.0]), + InFlow(), 1.0; + flow_direction=(1.0, + 0.0), + particle_spacing=0.1, + reference_pressure, + open_boundary_layers=2, + density=1.0) + + error_str = "`reference_density` must be either a function mapping " * + "each particle's coordinates and time to its density or a scalar" + reference_density = [1.0, 1.0] + @test_throws ArgumentError(error_str) system=OpenBoundarySPHSystem(([0.0, 0.0], + [0.0, 1.0]), + InFlow(), 1.0; + flow_direction=(1.0, + 0.0), + particle_spacing=0.1, + reference_density, + open_boundary_layers=2, + density=1.0) end @testset "show" begin system = OpenBoundarySPHSystem(([0.0, 0.0], [0.0, 1.0]), InFlow(), 1.0; From e270102aef336dcd8e5d7d83a0698d9913a26955 Mon Sep 17 00:00:00 2001 From: LasNikas Date: Tue, 13 Feb 2024 18:16:00 +0100 Subject: [PATCH 023/107] add `update_quantities!` --- src/schemes/boundary/open_boundary/system.jl | 29 ++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/schemes/boundary/open_boundary/system.jl b/src/schemes/boundary/open_boundary/system.jl index 5e10a0c52..4ac8478a3 100644 --- a/src/schemes/boundary/open_boundary/system.jl +++ b/src/schemes/boundary/open_boundary/system.jl @@ -340,6 +340,35 @@ end return characteristics end +@inline function update_quantities!(system::OpenBoundarySPHSystem, v, u, t) + (; density, pressure, characteristics, flow_direction, sound_speed, + reference_velocity, reference_pressure, reference_density) = system + + @threaded for particle in each_moving_particle(system) + particle_position = current_coords(u, system, particle) + + J1 = characteristics[1, particle] + J2 = characteristics[2, particle] + J3 = characteristics[3, particle] + + rho_ref = reference_density(particle_position, t) + density[particle] = rho_ref + ((-J1 + 0.5 * (J2 + J3)) / sound_speed^2) + + p_ref = reference_pressure(particle_position, t) + pressure[particle] = p_ref + 0.5 * (J2 + J3) + + v_ref = reference_velocity(particle_position, t) + rho = density[particle] + v_ = v_ref + ((J2 - J3) / (2 * sound_speed * rho)) * flow_direction + + for dim in 1:ndims(system) + v[dim, particle] = v_[dim] + end + end + + return system +end + function write_v0!(v0, system::OpenBoundarySPHSystem) (; initial_condition) = system From 129c786b15076d293898095569226ed9f56d3ac6 Mon Sep 17 00:00:00 2001 From: LasNikas Date: Tue, 13 Feb 2024 19:50:08 +0100 Subject: [PATCH 024/107] add buffer --- src/general/buffer.jl | 69 +++++++++++++++++++ src/general/general.jl | 1 + src/general/system.jl | 3 + src/schemes/boundary/open_boundary/system.jl | 31 ++++++--- .../fluid/entropically_damped_sph/system.jl | 16 +++-- src/schemes/fluid/fluid.jl | 8 +++ .../fluid/weakly_compressible_sph/system.jl | 24 ++++--- src/visualization/write2vtk.jl | 28 ++++++-- 8 files changed, 151 insertions(+), 29 deletions(-) create mode 100644 src/general/buffer.jl diff --git a/src/general/buffer.jl b/src/general/buffer.jl new file mode 100644 index 000000000..fbd560000 --- /dev/null +++ b/src/general/buffer.jl @@ -0,0 +1,69 @@ +struct SystemBuffer{} + active_particle :: BitVector + eachparticle :: Vector{Int} + buffer_size :: Int + + function SystemBuffer(active_size, buffer_size) + if !(buffer_size isa Int) + throw(ArgumentError("`buffer_size` must be of type Int")) + end + + active_particle = vcat(trues(active_size), falses(buffer_size)) + eachparticle = collect(1:active_size) + + return new{}(active_particle, eachparticle, buffer_size) + end +end + +allocate_buffer(initial_condition, buffer) = initial_condition + +function allocate_buffer(initial_condition, buffer::SystemBuffer) + (; buffer_size) = buffer + NDIMS = ndims(initial_condition) + + # Initialize particles far away from simulation domain + coordinates = inv(eps()) * ones(ndims(initial_condition), buffer_size) + + if all(rho -> rho ≈ density[1], density) + density = initial_condition.density[1] + else + throw(ArgumentError("`density` needs to be constant when using a `SystemBuffer`")) + end + + particle_spacing = initial_condition.particle_spacing + + buffer_ic = InitialCondition{NDIMS}(coordinates, density, particle_spacing) + + return union(initial_condition, buffer_ic) +end + +@inline update!(buffer::Nothing) = buffer + +# `view(eachindex(buffer.active_particle), buffer.active_particle)` is a allocation +# (but thread supporting) version of: +# `(i for i in eachindex(buffer.active_particle) if buffer.active_particle[i])` +# TODO: Find a non-allocation version + +# This is also a allocation version but only in every `update!(buffer)` call +@inline function update!(buffer::SystemBuffer) + (; active_particle) = buffer + + new_eachparticle = [i for i in eachindex(active_particle) if active_particle[i]] + resize!(buffer.eachparticle, length(new_eachparticle)) + + buffer.eachparticle .= new_eachparticle + + return buffer +end + +@inline eachparticle(system, ::Nothing) = Base.OneTo(nparticles(system)) + +@inline eachparticle(system, buffer) = buffer.eachparticle + +@inline each_moving_particle(system, ::Nothing) = Base.OneTo(n_moving_particles(system)) + +@inline each_moving_particle(system, buffer) = buffer.eachparticle + +@inline active_coordinates(u, system, ::Nothing) = current_coordinates(u, system) + +@inline active_coordinates(u, system, buffer) = view(u, :, buffer.active_particle) diff --git a/src/general/general.jl b/src/general/general.jl index 36b111b81..6d49374d8 100644 --- a/src/general/general.jl +++ b/src/general/general.jl @@ -23,3 +23,4 @@ include("smoothing_kernels.jl") include("initial_condition.jl") include("system.jl") include("interpolation.jl") +include("buffer.jl") diff --git a/src/general/system.jl b/src/general/system.jl index b27b229e3..abec7e349 100644 --- a/src/general/system.jl +++ b/src/general/system.jl @@ -49,6 +49,9 @@ end # are stored in u, for others in the system itself. By default, try to extract them from u. @inline current_coordinates(u, system) = u +# This can be dispatched when using a `SystemBuffer`. +@inline active_coordinates(u, system) = current_coordinates(u, system) + # Specifically get the initial coordinates of a particle for all system types. @inline function initial_coords(system, particle) return extract_svector(initial_coordinates(system), system, particle) diff --git a/src/schemes/boundary/open_boundary/system.jl b/src/schemes/boundary/open_boundary/system.jl index 4ac8478a3..0ccc52279 100644 --- a/src/schemes/boundary/open_boundary/system.jl +++ b/src/schemes/boundary/open_boundary/system.jl @@ -2,7 +2,7 @@ struct InFlow end struct OutFlow end -struct OpenBoundarySPHSystem{BZ, NDIMS, ELTYPE <: Real, S, RV, RP, RD} <: System{NDIMS} +struct OpenBoundarySPHSystem{BZ, NDIMS, ELTYPE <: Real, S, RV, RP, RD, B} <: System{NDIMS} initial_condition :: InitialCondition{ELTYPE} mass :: Array{ELTYPE, 1} # [particle] density :: Array{ELTYPE, 1} # [particle] @@ -18,13 +18,15 @@ struct OpenBoundarySPHSystem{BZ, NDIMS, ELTYPE <: Real, S, RV, RP, RD} <: System reference_velocity :: RV reference_pressure :: RP reference_density :: RD + buffer :: B function OpenBoundarySPHSystem(plane_points, boundary_zone, sound_speed; sample_geometry=plane_points, particle_spacing, flow_direction, open_boundary_layers=0, density, velocity=zeros(length(flow_direction)), mass=nothing, - pressure=0.0, reference_velocity=velocity, - reference_pressure=pressure, reference_density=density) + pressure=0.0, buffer=nothing, + reference_velocity=velocity, reference_pressure=pressure, + reference_density=density) if !((boundary_zone isa InFlow) || (boundary_zone isa OutFlow)) throw(ArgumentError("`boundary_zone` must either be of type InFlow or OutFlow")) end @@ -47,6 +49,9 @@ struct OpenBoundarySPHSystem{BZ, NDIMS, ELTYPE <: Real, S, RV, RP, RD} <: System n_extrude=open_boundary_layers, velocity, mass, density, pressure) + (buffer ≠ nothing) && (buffer = SystemBuffer(nparticles(initial_condition), buffer)) + initial_condition = allocate_buffer(initial_condition, buffer) + NDIMS = ndims(initial_condition) ELTYPE = eltype(initial_condition) @@ -110,12 +115,12 @@ struct OpenBoundarySPHSystem{BZ, NDIMS, ELTYPE <: Real, S, RV, RP, RD} <: System return new{typeof(boundary_zone), NDIMS, ELTYPE, typeof(spanning_set_), typeof(reference_velocity_), typeof(reference_pressure_), - typeof(reference_density_)}(initial_condition, mass, density, volume, - pressure, characteristics, - previous_characteristics, sound_speed, - boundary_zone, flow_direction_, zone_origin, - spanning_set_, reference_velocity_, - reference_pressure_, reference_density_) + typeof(reference_density_), + typeof(buffer)}(initial_condition, mass, density, volume, pressure, + characteristics, previous_characteristics, sound_speed, + boundary_zone, flow_direction_, zone_origin, + spanning_set_, reference_velocity_, reference_pressure_, + reference_density_, buffer) end end @@ -144,6 +149,14 @@ function Base.show(io::IO, ::MIME"text/plain", system::OpenBoundarySPHSystem) end end +@inline eachparticle(system::OpenBoundarySPHSystem) = eachparticle(system, system.buffer) + +@inline function each_moving_particle(system::OpenBoundarySPHSystem) + return each_moving_particle(system, system.buffer) +end + +@inline active_coordinates(u, system) = active_coordinates(system, system.buffer) + @inline viscosity_model(system, neighbor_system::OpenBoundarySPHSystem) = system.viscosity @inline source_terms(system::OpenBoundarySPHSystem) = nothing diff --git a/src/schemes/fluid/entropically_damped_sph/system.jl b/src/schemes/fluid/entropically_damped_sph/system.jl index 12dd2f8cd..654335a8e 100644 --- a/src/schemes/fluid/entropically_damped_sph/system.jl +++ b/src/schemes/fluid/entropically_damped_sph/system.jl @@ -34,7 +34,7 @@ is a good choice for a wide range of Reynolds numbers (0.0125 to 10000). In: Computers and Fluids 179 (2019), pages 579-594. [doi: 10.1016/j.compfluid.2018.11.023](https://doi.org/10.1016/j.compfluid.2018.11.023) """ -struct EntropicallyDampedSPHSystem{NDIMS, ELTYPE <: Real, DC, K, V, ST} <: +struct EntropicallyDampedSPHSystem{NDIMS, ELTYPE <: Real, DC, K, V, ST, B} <: FluidSystem{NDIMS} initial_condition :: InitialCondition{ELTYPE} mass :: Array{ELTYPE, 1} # [particle] @@ -47,13 +47,17 @@ struct EntropicallyDampedSPHSystem{NDIMS, ELTYPE <: Real, DC, K, V, ST} <: nu_edac :: ELTYPE acceleration :: SVector{NDIMS, ELTYPE} source_terms :: ST + buffer :: B function EntropicallyDampedSPHSystem(initial_condition, smoothing_kernel, smoothing_length, sound_speed; alpha=0.5, viscosity=NoViscosity(), acceleration=ntuple(_ -> 0.0, ndims(smoothing_kernel)), - source_terms=nothing) + source_terms=nothing, buffer=nothing) + (buffer ≠ nothing) && (buffer = SystemBuffer(nparticles(initial_condition), buffer)) + initial_condition = allocate_buffer(initial_condition, buffer) + NDIMS = ndims(initial_condition) ELTYPE = eltype(initial_condition) @@ -74,10 +78,10 @@ struct EntropicallyDampedSPHSystem{NDIMS, ELTYPE <: Real, DC, K, V, ST} <: density_calculator = SummationDensity() new{NDIMS, ELTYPE, typeof(density_calculator), - typeof(smoothing_kernel), typeof(viscosity), - typeof(source_terms)}(initial_condition, mass, density, density_calculator, - smoothing_kernel, smoothing_length, sound_speed, - viscosity, nu_edac, acceleration_, source_terms) + typeof(smoothing_kernel), typeof(viscosity), typeof(source_terms), + typeof(buffer)}(initial_condition, mass, density, density_calculator, + smoothing_kernel, smoothing_length, sound_speed, + viscosity, nu_edac, acceleration_, source_terms, buffer) end end diff --git a/src/schemes/fluid/fluid.jl b/src/schemes/fluid/fluid.jl index 539af19af..6f941255d 100644 --- a/src/schemes/fluid/fluid.jl +++ b/src/schemes/fluid/fluid.jl @@ -1,3 +1,11 @@ +@inline eachparticle(system::FluidSystem) = eachparticle(system, system.buffer) + +@inline function each_moving_particle(system::FluidSystem) + return each_moving_particle(system, system.buffer) +end + +@inline active_coordinates(u, system) = active_coordinates(system, system.buffer) + @inline hydrodynamic_mass(system::FluidSystem, particle) = system.mass[particle] function write_u0!(u0, system::FluidSystem) diff --git a/src/schemes/fluid/weakly_compressible_sph/system.jl b/src/schemes/fluid/weakly_compressible_sph/system.jl index 5ceb2e206..a983cc787 100644 --- a/src/schemes/fluid/weakly_compressible_sph/system.jl +++ b/src/schemes/fluid/weakly_compressible_sph/system.jl @@ -44,7 +44,7 @@ see [`ContinuityDensity`](@ref) and [`SummationDensity`](@ref). [doi: 10.1006/jcph.1994.1034](https://doi.org/10.1006/jcph.1994.1034) """ struct WeaklyCompressibleSPHSystem{NDIMS, ELTYPE <: Real, DC, SE, K, - V, DD, COR, PF, ST, C} <: FluidSystem{NDIMS} + V, DD, COR, PF, ST, B, C} <: FluidSystem{NDIMS} initial_condition :: InitialCondition{ELTYPE} mass :: Array{ELTYPE, 1} # [particle] pressure :: Array{ELTYPE, 1} # [particle] @@ -58,16 +58,20 @@ struct WeaklyCompressibleSPHSystem{NDIMS, ELTYPE <: Real, DC, SE, K, correction :: COR pressure_acceleration_formulation :: PF source_terms :: ST + buffer :: B cache :: C function WeaklyCompressibleSPHSystem(initial_condition, density_calculator, state_equation, smoothing_kernel, smoothing_length; - pressure_acceleration=nothing, + pressure_acceleration=nothing, buffer=nothing, viscosity=NoViscosity(), density_diffusion=nothing, acceleration=ntuple(_ -> 0.0, ndims(smoothing_kernel)), correction=nothing, source_terms=nothing) + (buffer ≠ nothing) && (buffer = SystemBuffer(nparticles(initial_condition), buffer)) + initial_condition = allocate_buffer(initial_condition, buffer) + NDIMS = ndims(initial_condition) ELTYPE = eltype(initial_condition) n_particles = nparticles(initial_condition) @@ -103,14 +107,14 @@ struct WeaklyCompressibleSPHSystem{NDIMS, ELTYPE <: Real, DC, SE, K, return new{NDIMS, ELTYPE, typeof(density_calculator), typeof(state_equation), typeof(smoothing_kernel), typeof(viscosity), typeof(density_diffusion), - typeof(correction), typeof(pressure_acceleration), - typeof(source_terms), typeof(cache)}(initial_condition, mass, pressure, - density_calculator, state_equation, - smoothing_kernel, smoothing_length, - acceleration_, viscosity, - density_diffusion, correction, - pressure_acceleration, - source_terms, cache) + typeof(correction), typeof(pressure_acceleration), typeof(source_terms), + typeof(buffer), typeof(cache)}(initial_condition, mass, pressure, + density_calculator, state_equation, + smoothing_kernel, smoothing_length, + acceleration_, viscosity, + density_diffusion, correction, + pressure_acceleration, source_terms, + buffer, cache) end end diff --git a/src/visualization/write2vtk.jl b/src/visualization/write2vtk.jl index bad071243..f476e8839 100644 --- a/src/visualization/write2vtk.jl +++ b/src/visualization/write2vtk.jl @@ -76,7 +76,7 @@ function trixi2vtk(v, u, t, system, periodic_box; output_directory="out", prefix # Reset the collection when the iteration is 0 pvd = paraview_collection(collection_file; append=iter > 0) - points = periodic_coords(current_coordinates(u, system), periodic_box) + points = periodic_coords(active_coordinates(u, system), periodic_box) cells = [MeshCell(VTKCellTypes.VTK_VERTEX, (i,)) for i in axes(points, 2)] if abs(maximum(points)) > max_coordinates || abs(minimum(points)) > max_coordinates @@ -161,13 +161,15 @@ end vtkname(system::FluidSystem) = "fluid" vtkname(system::TotalLagrangianSPHSystem) = "solid" vtkname(system::BoundarySPHSystem) = "boundary" +vtkname(system::OpenBoundarySPHSystem) = "open_boundary" function write2vtk!(vtk, v, u, t, system::FluidSystem; write_meta_data=true) - vtk["velocity"] = view(v, 1:ndims(system), :) + vtk["velocity"] = [current_velocity(v, system, particle) + for particle in each_moving_particle(system)] vtk["density"] = [particle_density(v, system, particle) - for particle in eachparticle(system)] + for particle in each_moving_particle(system)] vtk["pressure"] = [particle_pressure(v, system, particle) - for particle in eachparticle(system)] + for particle in each_moving_particle(system)] if write_meta_data vtk["acceleration"] = system.acceleration @@ -239,6 +241,24 @@ function write2vtk!(vtk, v, u, t, system::TotalLagrangianSPHSystem; write_meta_d write2vtk!(vtk, v, u, t, system.boundary_model, system, write_meta_data=write_meta_data) end +function write2vtk!(vtk, v, u, t, system::OpenBoundarySPHSystem; write_meta_data=true) + vtk["velocity"] = [current_velocity(v, system, particle) + for particle in each_moving_particle(system)] + vtk["density"] = [particle_density(v, system, particle) + for particle in each_moving_particle(system)] + vtk["pressure"] = [particle_pressure(v, system, particle) + for particle in each_moving_particle(system)] + + if write_meta_data + vtk["boundary_zone"] = type2string(system.boundary_zone) + vtk["sound_speed"] = system.sound_speed + vtk["open_boundary_layers"] = system.open_boundary_layers + vtk["flow_direction"] = system.flow_direction + end + + return vtk +end + function write2vtk!(vtk, v, u, t, system::BoundarySPHSystem; write_meta_data=true) write2vtk!(vtk, v, u, t, system.boundary_model, system, write_meta_data=write_meta_data) end From 03dce7e5377fe7b520aaec256e59e199c885a9ab Mon Sep 17 00:00:00 2001 From: LasNikas Date: Tue, 13 Feb 2024 22:50:01 +0100 Subject: [PATCH 025/107] add `SystemBuffer` tests --- src/general/buffer.jl | 32 ++++++++- src/schemes/boundary/open_boundary/system.jl | 11 ++- .../fluid/entropically_damped_sph/system.jl | 7 +- src/schemes/fluid/fluid.jl | 4 +- .../fluid/weakly_compressible_sph/system.jl | 7 +- test/general/buffer.jl | 70 +++++++++++++++++++ 6 files changed, 124 insertions(+), 7 deletions(-) create mode 100644 test/general/buffer.jl diff --git a/src/general/buffer.jl b/src/general/buffer.jl index fbd560000..c3747a1c9 100644 --- a/src/general/buffer.jl +++ b/src/general/buffer.jl @@ -24,7 +24,7 @@ function allocate_buffer(initial_condition, buffer::SystemBuffer) # Initialize particles far away from simulation domain coordinates = inv(eps()) * ones(ndims(initial_condition), buffer_size) - if all(rho -> rho ≈ density[1], density) + if all(rho -> rho ≈ initial_condition.density[1], initial_condition.density) density = initial_condition.density[1] else throw(ArgumentError("`density` needs to be constant when using a `SystemBuffer`")) @@ -32,7 +32,7 @@ function allocate_buffer(initial_condition, buffer::SystemBuffer) particle_spacing = initial_condition.particle_spacing - buffer_ic = InitialCondition{NDIMS}(coordinates, density, particle_spacing) + buffer_ic = InitialCondition(; coordinates, density, particle_spacing) return union(initial_condition, buffer_ic) end @@ -67,3 +67,31 @@ end @inline active_coordinates(u, system, ::Nothing) = current_coordinates(u, system) @inline active_coordinates(u, system, buffer) = view(u, :, buffer.active_particle) + +@inline function available_particle(system) + (; active_particle) = system.buffer + + for particle in eachindex(active_particle) + if !active_particle[particle] + active_particle[particle] = true + + return particle + end + end + + error("0 out of $(system.buffer.buffer_size) buffer particles available") +end + +@inline function deactivate_particle!(system, particle, u) + (; active_particle) = system.buffer + + active_particle[particle] = false + + # Set particle far away from simulation domain + for dim in 1:ndims(system) + # Inf or NaN causes instability outcome. + u[dim, particle] = inv(eps()) + end + + return system +end diff --git a/src/schemes/boundary/open_boundary/system.jl b/src/schemes/boundary/open_boundary/system.jl index 0ccc52279..797018b9b 100644 --- a/src/schemes/boundary/open_boundary/system.jl +++ b/src/schemes/boundary/open_boundary/system.jl @@ -141,7 +141,12 @@ function Base.show(io::IO, ::MIME"text/plain", system::OpenBoundarySPHSystem) show(io, system) else summary_header(io, "OpenBoundarySPHSystem{$(ndims(system))}") - summary_line(io, "#particles", nparticles(system)) + if system.buffer isa SystemBuffer + summary_line(io, "#particles", nparticles(system)) + summary_line(io, "#buffer_particles", system.buffer.buffer_size) + else + summary_line(io, "#particles", nparticles(system)) + end summary_line(io, "boundary", system.boundary_zone) summary_line(io, "flow direction", system.flow_direction) summary_line(io, "width", round(norm(system.spanning_set[1]), digits=3)) @@ -155,7 +160,9 @@ end return each_moving_particle(system, system.buffer) end -@inline active_coordinates(u, system) = active_coordinates(system, system.buffer) +@inline function active_coordinates(u, system::OpenBoundarySPHSystem) + return active_coordinates(u, system, system.buffer) +end @inline viscosity_model(system, neighbor_system::OpenBoundarySPHSystem) = system.viscosity diff --git a/src/schemes/fluid/entropically_damped_sph/system.jl b/src/schemes/fluid/entropically_damped_sph/system.jl index 654335a8e..6980d85ce 100644 --- a/src/schemes/fluid/entropically_damped_sph/system.jl +++ b/src/schemes/fluid/entropically_damped_sph/system.jl @@ -102,7 +102,12 @@ function Base.show(io::IO, ::MIME"text/plain", system::EntropicallyDampedSPHSyst show(io, system) else summary_header(io, "EntropicallyDampedSPHSystem{$(ndims(system))}") - summary_line(io, "#particles", nparticles(system)) + if system.buffer isa SystemBuffer + summary_line(io, "#particles", nparticles(system)) + summary_line(io, "#buffer_particles", system.buffer.buffer_size) + else + summary_line(io, "#particles", nparticles(system)) + end summary_line(io, "viscosity", system.viscosity |> typeof |> nameof) summary_line(io, "ν₍EDAC₎", "≈ $(round(system.nu_edac; digits=3))") summary_line(io, "smoothing kernel", system.smoothing_kernel |> typeof |> nameof) diff --git a/src/schemes/fluid/fluid.jl b/src/schemes/fluid/fluid.jl index 6f941255d..c49261645 100644 --- a/src/schemes/fluid/fluid.jl +++ b/src/schemes/fluid/fluid.jl @@ -4,7 +4,9 @@ return each_moving_particle(system, system.buffer) end -@inline active_coordinates(u, system) = active_coordinates(system, system.buffer) +@inline function active_coordinates(u, system::FluidSystem) + return active_coordinates(u, system, system.buffer) +end @inline hydrodynamic_mass(system::FluidSystem, particle) = system.mass[particle] diff --git a/src/schemes/fluid/weakly_compressible_sph/system.jl b/src/schemes/fluid/weakly_compressible_sph/system.jl index a983cc787..75bb08386 100644 --- a/src/schemes/fluid/weakly_compressible_sph/system.jl +++ b/src/schemes/fluid/weakly_compressible_sph/system.jl @@ -174,7 +174,12 @@ function Base.show(io::IO, ::MIME"text/plain", system::WeaklyCompressibleSPHSyst show(io, system) else summary_header(io, "WeaklyCompressibleSPHSystem{$(ndims(system))}") - summary_line(io, "#particles", nparticles(system)) + if system.buffer isa SystemBuffer + summary_line(io, "#particles", nparticles(system)) + summary_line(io, "#buffer_particles", system.buffer.buffer_size) + else + summary_line(io, "#particles", nparticles(system)) + end summary_line(io, "density calculator", system.density_calculator |> typeof |> nameof) summary_line(io, "correction method", diff --git a/test/general/buffer.jl b/test/general/buffer.jl new file mode 100644 index 000000000..6f457b5d6 --- /dev/null +++ b/test/general/buffer.jl @@ -0,0 +1,70 @@ +@testset verbose=true "SystemBuffer" begin + system = OpenBoundarySPHSystem(([0.0, 0.0], [0.0, 1.0]), InFlow(), 1.0; + flow_direction=[1.0, 0.0], particle_spacing=0.2, + open_boundary_layers=2, density=1.0) + system_buffer = OpenBoundarySPHSystem(([0.0, 0.0], [0.0, 1.0]), InFlow(), 1.0; + flow_direction=[1.0, 0.0], particle_spacing=0.2, + open_boundary_layers=2, density=1.0, buffer=5) + + n_particles = nparticles(system) + + @testset "Iterators" begin + @test Base.OneTo(n_particles) == TrixiParticles.eachparticle(system) + @test Base.OneTo(n_particles) == TrixiParticles.each_moving_particle(system) + + @test Base.OneTo(n_particles) == TrixiParticles.eachparticle(system_buffer) + @test Base.OneTo(n_particles) == TrixiParticles.each_moving_particle(system_buffer) + + particle_ID = TrixiParticles.available_particle(system_buffer) + + TrixiParticles.update!(system_buffer.buffer) + + @test Base.OneTo(n_particles + 1) == TrixiParticles.eachparticle(system_buffer) + @test Base.OneTo(n_particles + 1) == + TrixiParticles.each_moving_particle(system_buffer) + + TrixiParticles.deactivate_particle!(system_buffer, particle_ID, + ones(2, particle_ID)) + + TrixiParticles.update!(system_buffer.buffer) + + @test Base.OneTo(n_particles) == TrixiParticles.eachparticle(system_buffer) + @test Base.OneTo(n_particles) == TrixiParticles.each_moving_particle(system_buffer) + + particle_ID = 5 + TrixiParticles.deactivate_particle!(system_buffer, particle_ID, + ones(2, particle_ID)) + + TrixiParticles.update!(system_buffer.buffer) + + @test setdiff(Base.OneTo(n_particles), particle_ID) == + TrixiParticles.eachparticle(system_buffer) + @test setdiff(Base.OneTo(n_particles), particle_ID) == + TrixiParticles.each_moving_particle(system_buffer) + end + + @trixi_testset "Allocate Buffer" begin + initial_condition = rectangular_patch(0.1, (3, 3), perturbation_factor=0.0) + buffer = TrixiParticles.SystemBuffer(nparticles(initial_condition), 7) + + ic_with_buffer = TrixiParticles.allocate_buffer(initial_condition, buffer) + + @test nparticles(initial_condition) + 7 == nparticles(ic_with_buffer) + + masses = initial_condition.mass[1] .* ones(nparticles(ic_with_buffer)) + @test masses == ic_with_buffer.mass + + densities = initial_condition.density[1] .* ones(nparticles(ic_with_buffer)) + @test densities == ic_with_buffer.density + + pressures = initial_condition.pressure[1] .* ones(nparticles(ic_with_buffer)) + @test pressures == ic_with_buffer.pressure + + @trixi_testset "Illegal Input" begin + ic = rectangular_patch(0.1, (3, 3)) + buffer = TrixiParticles.SystemBuffer(9, 7) + error_str = "`density` needs to be constant when using `SystemBuffer`" + @test_throws ArgumentError(error_str) TrixiParticles.allocate_buffer(ic, buffer) + end + end +end From bd5fe1d8dcb6cc2371e015641b85b4e92c086ebe Mon Sep 17 00:00:00 2001 From: LasNikas Date: Tue, 13 Feb 2024 23:06:38 +0100 Subject: [PATCH 026/107] cosmetic change in tests --- test/systems/open_boundary_system.jl | 75 ++++++++++++---------------- 1 file changed, 33 insertions(+), 42 deletions(-) diff --git a/test/systems/open_boundary_system.jl b/test/systems/open_boundary_system.jl index 0394f4df6..6a757f199 100644 --- a/test/systems/open_boundary_system.jl +++ b/test/systems/open_boundary_system.jl @@ -143,65 +143,56 @@ no_rectangular_plane = [[0.2, 0.3, -0.5], [-1.0, 1.5, 0.2], [-0.2, 2.0, -0.5]] flow_direction = [0.0, 0.0, 1.0] error_str = "the provided points do not span a rectangular plane" - @test_throws ArgumentError(error_str) system=OpenBoundarySPHSystem(no_rectangular_plane, - InFlow(), - 1.0; - flow_direction, - particle_spacing=0.1, - open_boundary_layers=2, - density=1.0) + @test_throws ArgumentError(error_str) OpenBoundarySPHSystem(no_rectangular_plane, + InFlow(), 1.0; + flow_direction, + particle_spacing=0.1, + open_boundary_layers=2, + density=1.0) rectangular_plane = [[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0]] flow_direction = [0.0, 1.0, 0.0] error_str = "flow direction and normal vector of " * "InFlow-plane do not correspond" - @test_throws ArgumentError(error_str) system=OpenBoundarySPHSystem(rectangular_plane, - InFlow(), - 1.0; - flow_direction, - particle_spacing=0.1, - open_boundary_layers=2, - density=1.0) - + @test_throws ArgumentError(error_str) OpenBoundarySPHSystem(rectangular_plane, + InFlow(), 1.0; + flow_direction, + particle_spacing=0.1, + open_boundary_layers=2, + density=1.0) + + plane = ([0.0, 0.0], [0.0, 1.0]) + flow_direction = (1.0, 0.0) error_str = "`reference_velocity` must be either a function mapping " * "each particle's coordinates and time to its velocity or a " * "vector of length 2 for a 2D problem" reference_velocity = 1.0 - @test_throws ArgumentError(error_str) system=OpenBoundarySPHSystem(([0.0, 0.0], - [0.0, 1.0]), - InFlow(), 1.0; - flow_direction=(1.0, - 0.0), - particle_spacing=0.1, - reference_velocity, - open_boundary_layers=2, - density=1.0) + @test_throws ArgumentError(error_str) OpenBoundarySPHSystem(plane, InFlow(), 1.0; + flow_direction, + particle_spacing=0.1, + reference_velocity, + open_boundary_layers=2, + density=1.0) error_str = "`reference_pressure` must be either a function mapping " * "each particle's coordinates and time to its pressure or a scalar" reference_pressure = [1.0, 1.0] - @test_throws ArgumentError(error_str) system=OpenBoundarySPHSystem(([0.0, 0.0], - [0.0, 1.0]), - InFlow(), 1.0; - flow_direction=(1.0, - 0.0), - particle_spacing=0.1, - reference_pressure, - open_boundary_layers=2, - density=1.0) + @test_throws ArgumentError(error_str) OpenBoundarySPHSystem(plane, InFlow(), 1.0; + flow_direction, + particle_spacing=0.1, + reference_pressure, + open_boundary_layers=2, + density=1.0) error_str = "`reference_density` must be either a function mapping " * "each particle's coordinates and time to its density or a scalar" reference_density = [1.0, 1.0] - @test_throws ArgumentError(error_str) system=OpenBoundarySPHSystem(([0.0, 0.0], - [0.0, 1.0]), - InFlow(), 1.0; - flow_direction=(1.0, - 0.0), - particle_spacing=0.1, - reference_density, - open_boundary_layers=2, - density=1.0) + @test_throws ArgumentError(error_str) OpenBoundarySPHSystem(plane, InFlow(), 1.0; + flow_direction, + particle_spacing=0.1, + reference_density, + open_boundary_layers=2, + density=1.0) end @testset "show" begin system = OpenBoundarySPHSystem(([0.0, 0.0], [0.0, 1.0]), InFlow(), 1.0; From 199678b9ebea4fcebf8e12d4a9c845fa5aefb1d1 Mon Sep 17 00:00:00 2001 From: LasNikas Date: Tue, 13 Feb 2024 23:07:26 +0100 Subject: [PATCH 027/107] change `round` to `isapprox` --- src/general/interpolation.jl | 2 +- src/setups/extrude_geometry.jl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/general/interpolation.jl b/src/general/interpolation.jl index 16e316c60..43a4cb1e8 100644 --- a/src/general/interpolation.jl +++ b/src/general/interpolation.jl @@ -119,7 +119,7 @@ function interpolate_plane_3d(point1, point2, point3, resolution, semi, ref_syst cut_off_bnd=true) coords, resolution_ = sample_plane((point1, point2, point3), resolution) - if round(resolution, digits=3) != round(resolution_, digits=3) + if !isapprox(resolution, resolution_, rtol=5e-2) @info "The desired plane size is not a multiple of the resolution $resolution." * "\nNew resolution is set to $resolution_." end diff --git a/src/setups/extrude_geometry.jl b/src/setups/extrude_geometry.jl index 8d6614050..6e74e59bd 100644 --- a/src/setups/extrude_geometry.jl +++ b/src/setups/extrude_geometry.jl @@ -71,7 +71,7 @@ function ExtrudeGeometry(geometry; particle_spacing, direction, n_extrude=1, face_coords, particle_spacing_ = sample_plane(geometry, particle_spacing) - if round(particle_spacing, digits=4) != round(particle_spacing_, digits=4) + if !isapprox(particle_spacing, particle_spacing_, rtol=5e-2) @info "The desired size is not a multiple of the particle spacing $particle_spacing." * "\nNew particle spacing is set to $particle_spacing_." end From 4d3ea4815408ecfd4012288141155737eecc9b1d Mon Sep 17 00:00:00 2001 From: LasNikas Date: Thu, 15 Feb 2024 07:58:08 +0100 Subject: [PATCH 028/107] add update callback --- src/callbacks/callbacks.jl | 1 + src/callbacks/update.jl | 65 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+) create mode 100644 src/callbacks/update.jl diff --git a/src/callbacks/callbacks.jl b/src/callbacks/callbacks.jl index 623479592..09b7f7437 100644 --- a/src/callbacks/callbacks.jl +++ b/src/callbacks/callbacks.jl @@ -8,3 +8,4 @@ end include("info.jl") include("solution_saving.jl") include("density_reinit.jl") +include("update.jl") diff --git a/src/callbacks/update.jl b/src/callbacks/update.jl new file mode 100644 index 000000000..84e0b1885 --- /dev/null +++ b/src/callbacks/update.jl @@ -0,0 +1,65 @@ +struct UpdateEachTimeStep + interval :: Int + update :: Bool +end + +function UpdateEachTimeStep(; update=true, interval::Integer=1) + update_each_dt! = UpdateEachTimeStep(interval, update) + + # Update each step + condition_ = (u, t, integrator) -> update + + return DiscreteCallback(condition_, update_each_dt!, initialize=initial_update!, + save_positions=(false, false)) +end + +function Base.show(io::IO, cb::DiscreteCallback{<:Any, <:UpdateEachTimeStep}) + @nospecialize cb # reduce precompilation time + print(io, "UpdateEachTimeStep()") +end + +function Base.show(io::IO, ::MIME"text/plain", + cb::DiscreteCallback{<:Any, <:UpdateEachTimeStep}) + @nospecialize cb # reduce precompilation time + + if get(io, :compact, false) + show(io, cb) + else + update_each_dt = cb.affect! + setup = [ + "interval" => update_each_dt.interval, + "update" => update_each_dt.update ? "yes" : "no", + ] + summary_box(io, "UpdateEachTimeStep", setup) + end +end + +# initialize +initial_update!(cb, u, t, integrator) = cb.affect!(integrator) + +# condition +function (update_each_dt!::UpdateEachTimeStep)(u, t, integrator) + (; interval, update) = solution_callback + + # With error-based step size control, some steps can be rejected. Thus, + # `integrator.iter >= integrator.stats.naccept` + # (total #steps) (#accepted steps) + # We need to check the number of accepted steps since callbacks are not + # activated after a rejected step. + return update && integrator.stats.naccept % interval == 0 +end + +# affect +function (update_each_dt!::UpdateEachTimeStep)(integrator) + semi = integrator.p + v_ode, u_ode = integrator.u.x + + foreach_system(semi) do system + update_open_boundary_eachstep!(system, v_ode, u_ode, semi, integrator.t) + end + + # Tell OrdinaryDiffEq that u has been modified + u_modified!(integrator, true) + + return integrator +end From a5f3149e7d07f686bcf93495f3370c4714002958 Mon Sep 17 00:00:00 2001 From: LasNikas Date: Thu, 15 Feb 2024 18:09:57 +0100 Subject: [PATCH 029/107] add `UpdateCallback` --- src/TrixiParticles.jl | 2 +- src/callbacks/update.jl | 119 +++++++++++++++++++++++++++++---------- test/callbacks/update.jl | 65 +++++++++++++++++++++ 3 files changed, 154 insertions(+), 32 deletions(-) create mode 100644 test/callbacks/update.jl diff --git a/src/TrixiParticles.jl b/src/TrixiParticles.jl index 3347fb4ee..0186a1b9e 100644 --- a/src/TrixiParticles.jl +++ b/src/TrixiParticles.jl @@ -40,7 +40,7 @@ export Semidiscretization, semidiscretize, restart_with! export InitialCondition export WeaklyCompressibleSPHSystem, EntropicallyDampedSPHSystem, TotalLagrangianSPHSystem, BoundarySPHSystem, OpenBoundarySPHSystem, InFlow, OutFlow -export InfoCallback, SolutionSavingCallback, DensityReinitializationCallback +export InfoCallback, SolutionSavingCallback, DensityReinitializationCallback, UpdateCallback export ContinuityDensity, SummationDensity export PenaltyForceGanzenmueller export SchoenbergCubicSplineKernel, SchoenbergQuarticSplineKernel, diff --git a/src/callbacks/update.jl b/src/callbacks/update.jl index 84e0b1885..8472eb5df 100644 --- a/src/callbacks/update.jl +++ b/src/callbacks/update.jl @@ -1,61 +1,73 @@ -struct UpdateEachTimeStep - interval :: Int +struct UpdateCallback{I} + interval :: I update :: Bool end -function UpdateEachTimeStep(; update=true, interval::Integer=1) - update_each_dt! = UpdateEachTimeStep(interval, update) +function UpdateCallback(; update=true, interval::Integer=0, dt=0.0) + if dt > 0 && interval > 0 + throw(ArgumentError("Setting both interval and dt is not supported!")) + end - # Update each step - condition_ = (u, t, integrator) -> update + # Update in intervals in terms of simulation time + if dt > 0 + interval = Float64(dt) - return DiscreteCallback(condition_, update_each_dt!, initialize=initial_update!, - save_positions=(false, false)) -end + # Update every time step (default) + elseif update && interval == 0 + interval = 1 + end -function Base.show(io::IO, cb::DiscreteCallback{<:Any, <:UpdateEachTimeStep}) - @nospecialize cb # reduce precompilation time - print(io, "UpdateEachTimeStep()") -end + update_callback! = UpdateCallback(interval, update) -function Base.show(io::IO, ::MIME"text/plain", - cb::DiscreteCallback{<:Any, <:UpdateEachTimeStep}) - @nospecialize cb # reduce precompilation time - - if get(io, :compact, false) - show(io, cb) + if dt > 0 && update + # Add a `tstop` every `dt`, and save the final solution. + return PeriodicCallback(update_callback!, dt, + initialize=initial_update!, + save_positions=(false, false)) else - update_each_dt = cb.affect! - setup = [ - "interval" => update_each_dt.interval, - "update" => update_each_dt.update ? "yes" : "no", - ] - summary_box(io, "UpdateEachTimeStep", setup) + # The first one is the condition, the second the affect! + return DiscreteCallback(update_callback!, update_callback!, + initialize=initial_update!, + save_positions=(false, false)) end end # initialize -initial_update!(cb, u, t, integrator) = cb.affect!(integrator) +function initial_update!(cb, u, t, integrator) + # The `UpdateCallback` is either `cb.affect!` (with `DiscreteCallback`) + # or `cb.affect!.affect!` (with `PeriodicCallback`). + # Let recursive dispatch handle this. + + initial_update!(cb.affect!, u, t, integrator) +end + +initial_update!(cb::UpdateCallback, u, t, integrator) = cb.update && cb(integrator) # condition -function (update_each_dt!::UpdateEachTimeStep)(u, t, integrator) - (; interval, update) = solution_callback +function (update_callback!::UpdateCallback)(u, t, integrator) + (; interval, update) = update_callback! # With error-based step size control, some steps can be rejected. Thus, # `integrator.iter >= integrator.stats.naccept` # (total #steps) (#accepted steps) # We need to check the number of accepted steps since callbacks are not # activated after a rejected step. - return update && integrator.stats.naccept % interval == 0 + return update && (integrator.stats.naccept % interval == 0) end # affect -function (update_each_dt!::UpdateEachTimeStep)(integrator) +function (update_callback!::UpdateCallback)(integrator) + t = integrator.t semi = integrator.p v_ode, u_ode = integrator.u.x + # Update quantities that are stored in the systems. These quantities (e.g. pressure) + # still have the values from the last stage of the previous step if not updated here. + update_systems_and_nhs(v_ode, u_ode, semi, t) + + # Other updates might be added here later (e.g. Transport Velocity Formulation). foreach_system(semi) do system - update_open_boundary_eachstep!(system, v_ode, u_ode, semi, integrator.t) + update_open_boundary_eachstep!(system, v_ode, u_ode, semi, t) end # Tell OrdinaryDiffEq that u has been modified @@ -63,3 +75,48 @@ function (update_each_dt!::UpdateEachTimeStep)(integrator) return integrator end + +function Base.show(io::IO, cb::DiscreteCallback{<:Any, <:UpdateCallback}) + @nospecialize cb # reduce precompilation time + print(io, "UpdateCallback(interval=", cb.affect!.interval, ")") +end + +function Base.show(io::IO, + cb::DiscreteCallback{<:Any, + <:PeriodicCallbackAffect{<:UpdateCallback}}) + @nospecialize cb # reduce precompilation time + print(io, "UpdateCallback(dt=", cb.affect!.affect!.interval, ")") +end + +function Base.show(io::IO, ::MIME"text/plain", + cb::DiscreteCallback{<:Any, <:UpdateCallback}) + @nospecialize cb # reduce precompilation time + + if get(io, :compact, false) + show(io, cb) + else + update_cb = cb.affect! + setup = [ + "interval" => update_cb.interval, + "update" => update_cb.update ? "yes" : "no", + ] + summary_box(io, "UpdateCallback", setup) + end +end + +function Base.show(io::IO, ::MIME"text/plain", + cb::DiscreteCallback{<:Any, + <:PeriodicCallbackAffect{<:UpdateCallback}}) + @nospecialize cb # reduce precompilation time + + if get(io, :compact, false) + show(io, cb) + else + update_cb = cb.affect!.affect! + setup = [ + "dt" => update_cb.interval, + "update" => update_cb.update ? "yes" : "no", + ] + summary_box(io, "UpdateCallback", setup) + end +end diff --git a/test/callbacks/update.jl b/test/callbacks/update.jl new file mode 100644 index 000000000..22231340e --- /dev/null +++ b/test/callbacks/update.jl @@ -0,0 +1,65 @@ +@testset verbose=true "UpdateCallback" begin + @testset verbose=true "show" begin + # Default + callback0 = UpdateCallback() + + show_compact = "UpdateCallback(interval=1)" + @test repr(callback0) == show_compact + + show_box = """ + ┌──────────────────────────────────────────────────────────────────────────────────────────────────┐ + │ UpdateCallback │ + │ ══════════════ │ + │ interval: ……………………………………………………… 1 │ + │ update: …………………………………………………………… yes │ + └──────────────────────────────────────────────────────────────────────────────────────────────────┘""" + @test repr("text/plain", callback0) == show_box + + callback1 = UpdateCallback(interval=11) + + show_compact = "UpdateCallback(interval=11)" + @test repr(callback1) == show_compact + + show_box = """ + ┌──────────────────────────────────────────────────────────────────────────────────────────────────┐ + │ UpdateCallback │ + │ ══════════════ │ + │ interval: ……………………………………………………… 11 │ + │ update: …………………………………………………………… yes │ + └──────────────────────────────────────────────────────────────────────────────────────────────────┘""" + @test repr("text/plain", callback1) == show_box + + callback2 = UpdateCallback(dt=1.2) + + show_compact = "UpdateCallback(dt=1.2)" + @test repr(callback2) == show_compact + + show_box = """ + ┌──────────────────────────────────────────────────────────────────────────────────────────────────┐ + │ UpdateCallback │ + │ ══════════════ │ + │ dt: ……………………………………………………………………… 1.2 │ + │ update: …………………………………………………………… yes │ + └──────────────────────────────────────────────────────────────────────────────────────────────────┘""" + @test repr("text/plain", callback2) == show_box + + callback3 = UpdateCallback(update=false) + + show_compact = "UpdateCallback(interval=0)" + @test repr(callback3) == show_compact + + show_box = """ + ┌──────────────────────────────────────────────────────────────────────────────────────────────────┐ + │ UpdateCallback │ + │ ══════════════ │ + │ interval: ……………………………………………………… 0 │ + │ update: …………………………………………………………… no │ + └──────────────────────────────────────────────────────────────────────────────────────────────────┘""" + @test repr("text/plain", callback3) == show_box + end + + @testset "Illegal Input" begin + error_str = "Setting both interval and dt is not supported!" + @test_throws ArgumentError(error_str) UpdateCallback(dt=0.1, interval=1) + end +end From 68fadad987d1732f4897a33f2166ef4fff5da2a3 Mon Sep 17 00:00:00 2001 From: LasNikas Date: Thu, 15 Feb 2024 19:09:59 +0100 Subject: [PATCH 030/107] add `update_open_boundaries` --- src/general/density_calculators.jl | 10 ++ src/general/system.jl | 6 + src/schemes/boundary/open_boundary/system.jl | 140 ++++++++++++++++-- src/schemes/boundary/rhs.jl | 3 +- .../fluid/entropically_damped_sph/system.jl | 5 + src/schemes/fluid/fluid.jl | 2 + .../fluid/weakly_compressible_sph/system.jl | 5 + 7 files changed, 161 insertions(+), 10 deletions(-) diff --git a/src/general/density_calculators.jl b/src/general/density_calculators.jl index ee89c92a6..d35d0ae0f 100644 --- a/src/general/density_calculators.jl +++ b/src/general/density_calculators.jl @@ -35,6 +35,16 @@ end return v[end, particle] end +# *Note* that these functions are intended to internally set the density for buffer particles +# and density correction. It cannot be used to set up an initial condition, +# as the particle density depends on the particle positions. + +@inline set_particle_density(particle, v, ::SummationDensity, system, density) = system + +@inline function set_particle_density(particle, v, ::ContinuityDensity, system, density) + v[end, particle] = density +end + function summation_density!(system, semi, u, u_ode, density; particles=each_moving_particle(system)) set_zero!(density) diff --git a/src/general/system.jl b/src/general/system.jl index abec7e349..083e612a2 100644 --- a/src/general/system.jl +++ b/src/general/system.jl @@ -67,6 +67,10 @@ end return SVector(ntuple(_ -> 0.0, Val(ndims(system)))) end +@inline set_particle_density(particle, v, system, density) = system + +@inline set_particle_pressure(particle, v, system, pressure) = system + @inline function smoothing_kernel(system, distance) (; smoothing_kernel, smoothing_length) = system return kernel(smoothing_kernel, distance, smoothing_length) @@ -108,3 +112,5 @@ end function update_final!(system, v, u, v_ode, u_ode, semi, t) return system end + +update_system_buffer!(system) = system diff --git a/src/schemes/boundary/open_boundary/system.jl b/src/schemes/boundary/open_boundary/system.jl index 797018b9b..0c722f7aa 100644 --- a/src/schemes/boundary/open_boundary/system.jl +++ b/src/schemes/boundary/open_boundary/system.jl @@ -178,10 +178,6 @@ end return system.pressure[particle] end -@inline set_particle_density(particle, v, system::OpenBoundarySPHSystem, density) = system - -@inline set_particle_pressure(particle, v, system, pressure) = system - function spanning_vectors(plane_points, zone_width) # Convert to tuple @@ -235,6 +231,24 @@ function update_final!(system::OpenBoundarySPHSystem, v, u, v_ode, u_ode, semi, evaluate_characteristics!(system, v, u, v_ode, u_ode, semi, t) end +update_open_boundary_eachstep!(system, v_ode, u_ode, semi, t) = system + +function update_open_boundary_eachstep!(system::OpenBoundarySPHSystem, v_ode, u_ode, + semi, t) + u = wrap_u(u_ode, system, semi) + v = wrap_v(v_ode, system, semi) + + update_quantities!(system, v, u, t) + + check_domain!(system, v, u, v_ode, u_ode, semi) + + foreach_system(semi) do system + update_system_buffer!(system) + end +end + +update_system_buffer!(system::OpenBoundarySPHSystem) = update!(system.buffer) + # ==== Characteristics # J1: Associated with convection and entropy and propagates at flow velocity. # J2: Propagates downstream to the local flow @@ -256,16 +270,16 @@ function evaluate_characteristics!(system, v, u, v_ode, u_ode, semi, t) evaluate_characteristics!(system, neighbor_system, v, u, v_ode, u_ode, semi, t) end - # Only some of the in-/outlet particles are in the influence of the interior particles. + # Only some of the in-/outlet particles are in the influence of the fluid particles. # Thus, we find the characteristics for the particle which are outside the influence # using the average of the values of the previous time step. @threaded for particle in each_moving_particle(system) - # Particle is outside of the influence of interior particles + # Particle is outside of the influence of fluid particles if isapprox(volume[particle], 0.0) # Using the average of the values at the previous time step for particles which - # are outside of the influence of interior particles. + # are outside of the influence of fluid particles. avg_J1 = 0.0 avg_J2 = 0.0 avg_J3 = 0.0 @@ -273,7 +287,7 @@ function evaluate_characteristics!(system, v, u, v_ode, u_ode, semi, t) for neighbor in each_moving_particle(system) # Make sure that only neighbors in the influence of - # the interior particles are used. + # the fluid particles are used. if volume[neighbor] > sqrt(eps()) avg_J1 += previous_characteristics[1, neighbor] avg_J2 += previous_characteristics[2, neighbor] @@ -311,7 +325,7 @@ function evaluate_characteristics!(system, neighbor_system::FluidSystem, system_coords = current_coordinates(u, system) neighbor_coords = current_coordinates(u_neighbor_system, neighbor_system) - # Loop over all interior neighbors within the kernel cutoff. + # Loop over all flud neighbors within the kernel cutoff. for_particle_neighbor(system, neighbor_system, system_coords, neighbor_coords, nhs) do particle, neighbor, pos_diff, distance neighbor_position = current_coords(u_neighbor_system, neighbor_system, neighbor) @@ -389,6 +403,109 @@ end return system end +function check_domain!(system, v, u, v_ode, u_ode, semi) + @threaded for particle in each_moving_particle(system) + foreach_system(semi) do fluid_system + check_fluid_domain!(system, fluid_system, particle, v, u, v_ode, u_ode, semi) + end + end +end + +function check_fluid_domain!(system, neighbor_system::OpenBoundarySPHSystem, particle, + v, u, v_ode, u_ode, semi) + return system +end + +function check_fluid_domain!(system, fluid_system, particle, v, u, v_ode, u_ode, semi) + (; boundary_zone) = system + + particle_coords = current_coords(u, system, particle) + + u_fluid = wrap_u(u_ode, fluid_system, semi) + v_fluid = wrap_v(v_ode, fluid_system, semi) + + neighborhood_search = get_neighborhood_search(system, fluid_system, semi) + + # Check if the particle position is outside the boundary zone. + if !within_boundary_zone(particle_coords, system) + transform_particle!(system, fluid_system, boundary_zone, particle, + v, u, v_fluid, u_fluid) + end + + # Check fluid neighbors + for neighbor in eachneighbor(particle_coords, neighborhood_search) + fluid_coords = current_coords(u_fluid, fluid_system, neighbor) + + # Check if neighbor position is in boundary zone + if within_boundary_zone(fluid_coords, system) + transform_particle!(fluid_system, system, boundary_zone, neighbor, + v, u, v_fluid, u_fluid) + end + end + + return system +end + +# Outflow particle is outside the boundary zone +@inline function transform_particle!(system::OpenBoundarySPHSystem, fluid_system, + ::OutFlow, particle, v, u, v_fluid, u_fluid) + deactivate_particle!(system, particle, u) + + return system +end + +# Inflow particle is outside the boundary zone +@inline function transform_particle!(system::OpenBoundarySPHSystem, fluid_system, + ::InFlow, particle, v, u, v_fluid, u_fluid) + (; spanning_set) = system + + # Activate a new particle in simulation domain + activate_particle!(fluid_system, system, particle, v_fluid, u_fluid, v, u) + + # Reset position of boundary particle + for dim in 1:ndims(system) + u[dim, particle] += spanning_set[1][dim] + end + + return system +end + +# Flud particle is in boundary zone +@inline function transform_particle!(fluid_system::FluidSystem, system, + boundary_zone, particle, v, u, v_fluid, u_fluid) + # Activate particle in boundary zone + activate_particle!(system, fluid_system, particle, v, u, v_fluid, u_fluid) + + # Deactivate particle in interior domain + deactivate_particle!(fluid_system, particle, u_flud) + + return fluid_system +end + +@inline function activate_particle!(system_new, system_old, particle_old, + v_new, u_new, v_old, u_old) + particle_new = available_particle(system_new) + + # Exchange densities + density = particle_density(v_old, system_old, particle_old) + set_particle_density(particle_new, v_new, system_new, density) + + # Exchange pressure + pressure = particle_pressure(v_old, system_old, particle_old) + set_particle_pressure(particle_new, v_new, system_new, pressure) + + # Exchange position and velocity + for dim in 1:ndims(system_new) + u_new[dim, particle_new] = u_old[dim, particle_old] + v_new[dim, particle_new] = v_old[dim, particle_old] + end + + # Only when using TVF + set_transport_velocity!(system_new, particle_new, particle_old, v_new, v_old) + + return system_new +end + function write_v0!(v0, system::OpenBoundarySPHSystem) (; initial_condition) = system @@ -428,3 +545,8 @@ end function wrap_reference_function(constant_vector, ::Val{NDIMS}) where {NDIMS} return (coords, t) -> SVector{NDIMS}(constant_vector) end + +function set_transport_velocity!(system::OpenBoundarySPHSystem, + particle, particle_old, v, v_old) + return system +end diff --git a/src/schemes/boundary/rhs.jl b/src/schemes/boundary/rhs.jl index 965e55062..e800adf40 100644 --- a/src/schemes/boundary/rhs.jl +++ b/src/schemes/boundary/rhs.jl @@ -1,7 +1,8 @@ # Interaction of boundary with other systems function interact!(dv, v_particle_system, u_particle_system, v_neighbor_system, u_neighbor_system, neighborhood_search, - particle_system::BoundarySPHSystem, neighbor_system) + particle_system::Union{BoundarySPHSystem, OpenBoundarySPHSystem}, + neighbor_system) # TODO Solids and moving boundaries should be considered in the continuity equation return dv end diff --git a/src/schemes/fluid/entropically_damped_sph/system.jl b/src/schemes/fluid/entropically_damped_sph/system.jl index 6980d85ce..593fc4c82 100644 --- a/src/schemes/fluid/entropically_damped_sph/system.jl +++ b/src/schemes/fluid/entropically_damped_sph/system.jl @@ -124,6 +124,11 @@ end return v[end, particle] end +@inline function set_particle_pressure(particle, v, system::EntropicallyDampedSPHSystem, + pressure) + return v[end, particle] = pressure +end + @inline v_nvariables(system::EntropicallyDampedSPHSystem) = ndims(system) + 1 function update_quantities!(system::EntropicallyDampedSPHSystem, v, u, diff --git a/src/schemes/fluid/fluid.jl b/src/schemes/fluid/fluid.jl index c49261645..6c001c076 100644 --- a/src/schemes/fluid/fluid.jl +++ b/src/schemes/fluid/fluid.jl @@ -8,6 +8,8 @@ end return active_coordinates(u, system, system.buffer) end +update_system_buffer!(system::FluidSystem) = update!(system.buffer) + @inline hydrodynamic_mass(system::FluidSystem, particle) = system.mass[particle] function write_u0!(u0, system::FluidSystem) diff --git a/src/schemes/fluid/weakly_compressible_sph/system.jl b/src/schemes/fluid/weakly_compressible_sph/system.jl index 75bb08386..1166d7242 100644 --- a/src/schemes/fluid/weakly_compressible_sph/system.jl +++ b/src/schemes/fluid/weakly_compressible_sph/system.jl @@ -209,6 +209,11 @@ end return system.pressure[particle] end +@inline function set_particle_density(particle, v, system::WeaklyCompressibleSPHSystem, + density) + set_particle_density(particle, v, system.density_calculator, system, density) +end + # Nothing to initialize for this system initialize!(system::WeaklyCompressibleSPHSystem, neighborhood_search) = system From 5be7af8340faf6998139e8674836b234f34d4945 Mon Sep 17 00:00:00 2001 From: LasNikas Date: Thu, 15 Feb 2024 20:34:28 +0100 Subject: [PATCH 031/107] fix bugs --- src/general/buffer.jl | 6 ++--- src/general/semidiscretization.jl | 28 ++++++++++++++++++++ src/general/system.jl | 2 ++ src/schemes/boundary/open_boundary/system.jl | 18 +++++-------- src/schemes/fluid/fluid.jl | 4 +-- src/visualization/write2vtk.jl | 4 +-- 6 files changed, 43 insertions(+), 19 deletions(-) diff --git a/src/general/buffer.jl b/src/general/buffer.jl index 1a08b2d0d..5db956f82 100644 --- a/src/general/buffer.jl +++ b/src/general/buffer.jl @@ -56,10 +56,6 @@ end return buffer end -@inline eachparticle(system, ::Nothing) = Base.OneTo(nparticles(system)) - -@inline eachparticle(system, buffer) = buffer.eachparticle - @inline each_moving_particle(system, ::Nothing) = Base.OneTo(n_moving_particles(system)) @inline each_moving_particle(system, buffer) = buffer.eachparticle @@ -68,6 +64,8 @@ end @inline active_coordinates(u, system, buffer) = view(u, :, buffer.active_particle) +@inline active_particles(system, buffer) = buffer.eachparticle + @inline function available_particle(system) (; active_particle) = system.buffer diff --git a/src/general/semidiscretization.jl b/src/general/semidiscretization.jl index 33fa841f3..0ae932663 100644 --- a/src/general/semidiscretization.jl +++ b/src/general/semidiscretization.jl @@ -535,6 +535,16 @@ function nhs_coords(system::FluidSystem, return current_coordinates(u, neighbor) end +function nhs_coords(system::FluidSystem, + neighbor::OpenBoundarySPHSystem, u) + return current_coordinates(u, neighbor) +end + +function nhs_coords(system::OpenBoundarySPHSystem, + neighbor::FluidSystem, u) + return current_coordinates(u, neighbor) +end + function nhs_coords(system::FluidSystem, neighbor::TotalLagrangianSPHSystem, u) return current_coordinates(u, neighbor) @@ -594,6 +604,24 @@ function nhs_coords(system::BoundarySPHSystem, return nothing end +function nhs_coords(system::BoundarySPHSystem, + neighbor::OpenBoundarySPHSystem, u) + # Don't update + return nothing +end + +function nhs_coords(system::OpenBoundarySPHSystem, + neighbor::OpenBoundarySPHSystem, u) + # Don't update + return nothing +end + +function nhs_coords(system::OpenBoundarySPHSystem, + neighbor::BoundarySPHSystem, u) + # Don't update + return nothing +end + function check_configuration(systems) foreach_system(systems) do system check_configuration(system, systems) diff --git a/src/general/system.jl b/src/general/system.jl index 083e612a2..b590ba5b8 100644 --- a/src/general/system.jl +++ b/src/general/system.jl @@ -19,6 +19,8 @@ initialize!(system, neighborhood_search) = system @inline eachparticle(system) = Base.OneTo(nparticles(system)) @inline each_moving_particle(system) = Base.OneTo(n_moving_particles(system)) +@inline active_particles(system) = eachparticle(system) + # This should not be dispatched by system type. We always expect to get a column of `A`. @inline function extract_svector(A, system, i) extract_svector(A, Val(ndims(system)), i) diff --git a/src/schemes/boundary/open_boundary/system.jl b/src/schemes/boundary/open_boundary/system.jl index 0c722f7aa..0911af8f9 100644 --- a/src/schemes/boundary/open_boundary/system.jl +++ b/src/schemes/boundary/open_boundary/system.jl @@ -154,8 +154,6 @@ function Base.show(io::IO, ::MIME"text/plain", system::OpenBoundarySPHSystem) end end -@inline eachparticle(system::OpenBoundarySPHSystem) = eachparticle(system, system.buffer) - @inline function each_moving_particle(system::OpenBoundarySPHSystem) return each_moving_particle(system, system.buffer) end @@ -164,6 +162,9 @@ end return active_coordinates(u, system, system.buffer) end +@inline active_particles(system::OpenBoundarySPHSystem) = active_particles(system, + system.buffer) + @inline viscosity_model(system, neighbor_system::OpenBoundarySPHSystem) = system.viscosity @inline source_terms(system::OpenBoundarySPHSystem) = nothing @@ -404,7 +405,8 @@ end end function check_domain!(system, v, u, v_ode, u_ode, semi) - @threaded for particle in each_moving_particle(system) + # TODO: Is a thread supported version possible? + for particle in each_moving_particle(system) foreach_system(semi) do fluid_system check_fluid_domain!(system, fluid_system, particle, v, u, v_ode, u_ode, semi) end @@ -477,7 +479,7 @@ end activate_particle!(system, fluid_system, particle, v, u, v_fluid, u_fluid) # Deactivate particle in interior domain - deactivate_particle!(fluid_system, particle, u_flud) + deactivate_particle!(fluid_system, particle, u_fluid) return fluid_system end @@ -500,8 +502,7 @@ end v_new[dim, particle_new] = v_old[dim, particle_old] end - # Only when using TVF - set_transport_velocity!(system_new, particle_new, particle_old, v_new, v_old) + # TODO: Only when using TVF: set tvf return system_new end @@ -545,8 +546,3 @@ end function wrap_reference_function(constant_vector, ::Val{NDIMS}) where {NDIMS} return (coords, t) -> SVector{NDIMS}(constant_vector) end - -function set_transport_velocity!(system::OpenBoundarySPHSystem, - particle, particle_old, v, v_old) - return system -end diff --git a/src/schemes/fluid/fluid.jl b/src/schemes/fluid/fluid.jl index 6c001c076..44010984e 100644 --- a/src/schemes/fluid/fluid.jl +++ b/src/schemes/fluid/fluid.jl @@ -1,5 +1,3 @@ -@inline eachparticle(system::FluidSystem) = eachparticle(system, system.buffer) - @inline function each_moving_particle(system::FluidSystem) return each_moving_particle(system, system.buffer) end @@ -8,6 +6,8 @@ end return active_coordinates(u, system, system.buffer) end +@inline active_particles(system::FluidSystem) = active_particles(system, system.buffer) + update_system_buffer!(system::FluidSystem) = update!(system.buffer) @inline hydrodynamic_mass(system::FluidSystem, particle) = system.mass[particle] diff --git a/src/visualization/write2vtk.jl b/src/visualization/write2vtk.jl index f476e8839..5331b1f7b 100644 --- a/src/visualization/write2vtk.jl +++ b/src/visualization/write2vtk.jl @@ -92,7 +92,7 @@ function trixi2vtk(v, u, t, system, periodic_box; output_directory="out", prefix write2vtk!(vtk, v, u, t, system, write_meta_data=write_meta_data) # Store particle index - vtk["index"] = eachparticle(system) + vtk["index"] = active_particles(system) vtk["time"] = t # Extract custom quantities for this system @@ -252,7 +252,7 @@ function write2vtk!(vtk, v, u, t, system::OpenBoundarySPHSystem; write_meta_data if write_meta_data vtk["boundary_zone"] = type2string(system.boundary_zone) vtk["sound_speed"] = system.sound_speed - vtk["open_boundary_layers"] = system.open_boundary_layers + vtk["width"] = round(norm(system.spanning_set[1]), digits=3) vtk["flow_direction"] = system.flow_direction end From b1fac9d0a25c986d6fe27332f653762379d56a2e Mon Sep 17 00:00:00 2001 From: LasNikas Date: Thu, 15 Feb 2024 23:07:09 +0100 Subject: [PATCH 032/107] add timers --- src/callbacks/update.jl | 2 +- src/schemes/boundary/open_boundary/system.jl | 12 +++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/callbacks/update.jl b/src/callbacks/update.jl index 8472eb5df..baffe86e7 100644 --- a/src/callbacks/update.jl +++ b/src/callbacks/update.jl @@ -66,7 +66,7 @@ function (update_callback!::UpdateCallback)(integrator) update_systems_and_nhs(v_ode, u_ode, semi, t) # Other updates might be added here later (e.g. Transport Velocity Formulation). - foreach_system(semi) do system + @trixi_timeit timer() "update open boundary" foreach_system(semi) do system update_open_boundary_eachstep!(system, v_ode, u_ode, semi, t) end diff --git a/src/schemes/boundary/open_boundary/system.jl b/src/schemes/boundary/open_boundary/system.jl index 0911af8f9..3632b28fe 100644 --- a/src/schemes/boundary/open_boundary/system.jl +++ b/src/schemes/boundary/open_boundary/system.jl @@ -229,7 +229,9 @@ end end function update_final!(system::OpenBoundarySPHSystem, v, u, v_ode, u_ode, semi, t) - evaluate_characteristics!(system, v, u, v_ode, u_ode, semi, t) + @trixi_timeit timer() "Evaluate Characteristics" evaluate_characteristics!(system, v, u, + v_ode, u_ode, + semi, t) end update_open_boundary_eachstep!(system, v_ode, u_ode, semi, t) = system @@ -239,11 +241,11 @@ function update_open_boundary_eachstep!(system::OpenBoundarySPHSystem, v_ode, u_ u = wrap_u(u_ode, system, semi) v = wrap_v(v_ode, system, semi) - update_quantities!(system, v, u, t) + @trixi_timeit timer() "update quantities" update_quantities!(system, v, u, t) - check_domain!(system, v, u, v_ode, u_ode, semi) + @trixi_timeit timer() "check domain" check_domain!(system, v, u, v_ode, u_ode, semi) - foreach_system(semi) do system + @trixi_timeit timer() "update buffer" foreach_system(semi) do system update_system_buffer!(system) end end @@ -267,7 +269,7 @@ function evaluate_characteristics!(system, v, u, v_ode, u_ode, semi, t) set_zero!(volume) # Use all other systems for the characteristics - @trixi_timeit timer() "Evaluate Characteristics" foreach_system(semi) do neighbor_system + foreach_system(semi) do neighbor_system evaluate_characteristics!(system, neighbor_system, v, u, v_ode, u_ode, semi, t) end From 8ed09667fc90ea4ea9012a3e6ad833297cb3529b Mon Sep 17 00:00:00 2001 From: LasNikas Date: Fri, 16 Feb 2024 10:14:34 +0100 Subject: [PATCH 033/107] write prescribed quantities --- src/schemes/boundary/open_boundary/system.jl | 15 ++++++++++----- src/visualization/write2vtk.jl | 13 +++++++++++++ test/general/buffer.jl | 6 ------ test/systems/open_boundary_system.jl | 3 +++ 4 files changed, 26 insertions(+), 11 deletions(-) diff --git a/src/schemes/boundary/open_boundary/system.jl b/src/schemes/boundary/open_boundary/system.jl index 3632b28fe..e360a5eb9 100644 --- a/src/schemes/boundary/open_boundary/system.jl +++ b/src/schemes/boundary/open_boundary/system.jl @@ -149,6 +149,9 @@ function Base.show(io::IO, ::MIME"text/plain", system::OpenBoundarySPHSystem) end summary_line(io, "boundary", system.boundary_zone) summary_line(io, "flow direction", system.flow_direction) + summary_line(io, "prescribed velocity", string(nameof(system.reference_velocity))) + summary_line(io, "prescribed pressure", string(nameof(system.reference_pressure))) + summary_line(io, "prescribed density", string(nameof(system.reference_density))) summary_line(io, "width", round(norm(system.spanning_set[1]), digits=3)) summary_footer(io) end @@ -229,7 +232,7 @@ end end function update_final!(system::OpenBoundarySPHSystem, v, u, v_ode, u_ode, semi, t) - @trixi_timeit timer() "Evaluate Characteristics" evaluate_characteristics!(system, v, u, + @trixi_timeit timer() "evaluate characteristics" evaluate_characteristics!(system, v, u, v_ode, u_ode, semi, t) end @@ -540,11 +543,13 @@ function wrap_reference_function(function_::Function, ::Val) return function_ end -function wrap_reference_function(constant_scalar::Number, ::Val) - return (coords, t) -> constant_scalar +# Name the function so that the summary box does know which kind of function this is +function wrap_reference_function(constant_scalar_::Number, ::Val) + return constant_scalar(coords, t) = constant_scalar_ end # For vectors and tuples -function wrap_reference_function(constant_vector, ::Val{NDIMS}) where {NDIMS} - return (coords, t) -> SVector{NDIMS}(constant_vector) +# Name the function so that the summary box does know which kind of function this is +function wrap_reference_function(constant_vector_, ::Val{NDIMS}) where {NDIMS} + return constant_vector(coords, t) = SVector{NDIMS}(constant_vector_) end diff --git a/src/visualization/write2vtk.jl b/src/visualization/write2vtk.jl index 5331b1f7b..69fe06fac 100644 --- a/src/visualization/write2vtk.jl +++ b/src/visualization/write2vtk.jl @@ -242,6 +242,8 @@ function write2vtk!(vtk, v, u, t, system::TotalLagrangianSPHSystem; write_meta_d end function write2vtk!(vtk, v, u, t, system::OpenBoundarySPHSystem; write_meta_data=true) + (; reference_velocity, reference_pressure, reference_density) = system + vtk["velocity"] = [current_velocity(v, system, particle) for particle in each_moving_particle(system)] vtk["density"] = [particle_density(v, system, particle) @@ -249,11 +251,22 @@ function write2vtk!(vtk, v, u, t, system::OpenBoundarySPHSystem; write_meta_data vtk["pressure"] = [particle_pressure(v, system, particle) for particle in each_moving_particle(system)] + NDIMS = ndims(system) + ELTYPE = eltype(system) + coords = reinterpret(reshape, SVector{NDIMS, ELTYPE}, active_coordinates(u, system)) + + vtk["prescribed_velocity"] = stack(reference_velocity.(coords, t)) + vtk["prescribed_density"] = reference_density.(coords, t) + vtk["prescribed_pressure"] = reference_pressure.(coords, t) + if write_meta_data vtk["boundary_zone"] = type2string(system.boundary_zone) vtk["sound_speed"] = system.sound_speed vtk["width"] = round(norm(system.spanning_set[1]), digits=3) vtk["flow_direction"] = system.flow_direction + vtk["velocity_function"] = string(nameof(system.reference_velocity)) + vtk["pressure_function"] = string(nameof(system.reference_pressure)) + vtk["density_function"] = string(nameof(system.reference_density)) end return vtk diff --git a/test/general/buffer.jl b/test/general/buffer.jl index 69bc897b8..05e1f5bc8 100644 --- a/test/general/buffer.jl +++ b/test/general/buffer.jl @@ -9,17 +9,14 @@ n_particles = nparticles(system) @testset "Iterators" begin - @test Base.OneTo(n_particles) == TrixiParticles.eachparticle(system) @test Base.OneTo(n_particles) == TrixiParticles.each_moving_particle(system) - @test Base.OneTo(n_particles) == TrixiParticles.eachparticle(system_buffer) @test Base.OneTo(n_particles) == TrixiParticles.each_moving_particle(system_buffer) particle_ID = TrixiParticles.available_particle(system_buffer) TrixiParticles.update!(system_buffer.buffer) - @test Base.OneTo(n_particles + 1) == TrixiParticles.eachparticle(system_buffer) @test Base.OneTo(n_particles + 1) == TrixiParticles.each_moving_particle(system_buffer) @@ -28,7 +25,6 @@ TrixiParticles.update!(system_buffer.buffer) - @test Base.OneTo(n_particles) == TrixiParticles.eachparticle(system_buffer) @test Base.OneTo(n_particles) == TrixiParticles.each_moving_particle(system_buffer) particle_ID = 5 @@ -37,8 +33,6 @@ TrixiParticles.update!(system_buffer.buffer) - @test setdiff(Base.OneTo(n_particles), particle_ID) == - TrixiParticles.eachparticle(system_buffer) @test setdiff(Base.OneTo(n_particles), particle_ID) == TrixiParticles.each_moving_particle(system_buffer) end diff --git a/test/systems/open_boundary_system.jl b/test/systems/open_boundary_system.jl index 6a757f199..d8b48d620 100644 --- a/test/systems/open_boundary_system.jl +++ b/test/systems/open_boundary_system.jl @@ -208,6 +208,9 @@ │ #particles: ………………………………………………… 80 │ │ boundary: ……………………………………………………… InFlow() │ │ flow direction: ……………………………………… [1.0, 0.0] │ + │ prescribed velocity: ………………………… constant_vector │ + │ prescribed pressure: ………………………… constant_scalar │ + │ prescribed density: …………………………… constant_scalar │ │ width: ……………………………………………………………… 0.2 │ └──────────────────────────────────────────────────────────────────────────────────────────────────┘""" @test repr("text/plain", system) == show_box From faad37781cdc40558a45b76ba85e3292a29c77aa Mon Sep 17 00:00:00 2001 From: LasNikas Date: Fri, 16 Feb 2024 14:53:36 +0100 Subject: [PATCH 034/107] improve dispatching --- src/general/semidiscretization.jl | 22 ++------------------ src/schemes/boundary/open_boundary/system.jl | 6 +++--- src/schemes/fluid/fluid.jl | 2 +- 3 files changed, 6 insertions(+), 24 deletions(-) diff --git a/src/general/semidiscretization.jl b/src/general/semidiscretization.jl index 20a6e3714..678666b11 100644 --- a/src/general/semidiscretization.jl +++ b/src/general/semidiscretization.jl @@ -604,26 +604,8 @@ function nhs_coords(system::BoundarySPHSystem, return nothing end -function nhs_coords(system::BoundarySPHSystem, - neighbor::BoundarySPHSystem, u) - # Don't update - return nothing -end - -function nhs_coords(system::BoundarySPHSystem, - neighbor::OpenBoundarySPHSystem, u) - # Don't update - return nothing -end - -function nhs_coords(system::OpenBoundarySPHSystem, - neighbor::OpenBoundarySPHSystem, u) - # Don't update - return nothing -end - -function nhs_coords(system::OpenBoundarySPHSystem, - neighbor::BoundarySPHSystem, u) +function nhs_coords(system::Union{BoundarySPHSystem, OpenBoundarySPHSystem}, + neighbor::Union{BoundarySPHSystem, OpenBoundarySPHSystem}, u) # Don't update return nothing end diff --git a/src/schemes/boundary/open_boundary/system.jl b/src/schemes/boundary/open_boundary/system.jl index e360a5eb9..f15ccd1b1 100644 --- a/src/schemes/boundary/open_boundary/system.jl +++ b/src/schemes/boundary/open_boundary/system.jl @@ -418,12 +418,12 @@ function check_domain!(system, v, u, v_ode, u_ode, semi) end end -function check_fluid_domain!(system, neighbor_system::OpenBoundarySPHSystem, particle, - v, u, v_ode, u_ode, semi) +function check_fluid_domain!(system, neighbor_system, particle, v, u, v_ode, u_ode, semi) return system end -function check_fluid_domain!(system, fluid_system, particle, v, u, v_ode, u_ode, semi) +function check_fluid_domain!(system, fluid_system::FluidSystem, particle, + v, u, v_ode, u_ode, semi) (; boundary_zone) = system particle_coords = current_coords(u, system, particle) diff --git a/src/schemes/fluid/fluid.jl b/src/schemes/fluid/fluid.jl index 055a3fe2c..bef8a90e4 100644 --- a/src/schemes/fluid/fluid.jl +++ b/src/schemes/fluid/fluid.jl @@ -6,7 +6,7 @@ end return active_coordinates(u, system, system.buffer) end -@inline active_particles(system::FluidSystem) = active_particles(system, system.buffer) +@inline active_particles(system::FluidSystem) = active_particles(system, system.buffer) update_system_buffer!(system::FluidSystem) = update!(system.buffer) From c656604919e783f9e5517bc3fded88b8ef6a4486 Mon Sep 17 00:00:00 2001 From: LasNikas Date: Fri, 16 Feb 2024 14:53:52 +0100 Subject: [PATCH 035/107] add example `pipe_flow_2d.jl` --- examples/fluid/pipe_flow_2d.jl | 120 +++++++++++++++++++++++++++++++++ 1 file changed, 120 insertions(+) create mode 100644 examples/fluid/pipe_flow_2d.jl diff --git a/examples/fluid/pipe_flow_2d.jl b/examples/fluid/pipe_flow_2d.jl new file mode 100644 index 000000000..6514638b2 --- /dev/null +++ b/examples/fluid/pipe_flow_2d.jl @@ -0,0 +1,120 @@ +# TODO: Description +using TrixiParticles +using OrdinaryDiffEq + +# ========================================================================================== +# ==== Resolution +domain_length_factor = 0.05 + +# Change spacing ratio to 3 and boundary layers to 1 when using Monaghan-Kajtar boundary model +boundary_layers = 4 +spacing_ratio = 1 + +open_boundary_layers = 6 + +# ========================================================================================== +# ==== Experiment Setup +tspan = (0.0, 2.0) + +# Boundary geometry and initial fluid particle positions +domain_size = (1.0, 0.4) + +flow_direction = [1.0, 0.0] +reynolds_number = 100 +prescribed_velocity = 2.0 + +particle_spacing = domain_length_factor * domain_size[1] + +boundary_size = (domain_size[1] + 2 * particle_spacing * open_boundary_layers, + domain_size[2]) + +fluid_density = 1000.0 +pressure = 1000.0 + +sound_speed = 10 * prescribed_velocity + +state_equation = StateEquationCole(; sound_speed, reference_density=fluid_density, + exponent=7, background_pressure=pressure) + +pipe = RectangularTank(particle_spacing, domain_size, boundary_size, fluid_density, + pressure=pressure, n_layers=boundary_layers, spacing_ratio=1, + faces=(false, false, true, true)) + +# Shift pipe walls in negative x-direction for the inflow +pipe.boundary.coordinates[1, :] .-= particle_spacing * open_boundary_layers + +n_buffer_particles = 4 * pipe.n_particles_per_dimension[2] + +# ========================================================================================== +# ==== Fluid +smoothing_length = 3.0 * particle_spacing +smoothing_kernel = WendlandC2Kernel{2}() + +nu = prescribed_velocity * domain_size[2] / reynolds_number +alpha = 8 * nu / (smoothing_length * sound_speed) + +fluid_density_calculator = ContinuityDensity() +viscosity = ArtificialViscosityMonaghan(; alpha, beta=0.0) + +fluid_system = WeaklyCompressibleSPHSystem(pipe.fluid, fluid_density_calculator, + state_equation, smoothing_kernel, + smoothing_length, viscosity=viscosity, + buffer=n_buffer_particles) + +# ========================================================================================== +# ==== Open Boundary +velocity_function(pos, t) = [0.5prescribed_velocity * sin(2pi * t) + prescribed_velocity, 0] + +open_boundary_in = OpenBoundarySPHSystem(([0.0, 0.0], [0.0, domain_size[2]]), InFlow(), + sound_speed; particle_spacing, + flow_direction, open_boundary_layers, + density=fluid_density, buffer=n_buffer_particles, + pressure, reference_velocity=velocity_function) + +open_boundary_out = OpenBoundarySPHSystem(([domain_size[1], 0.0], + [domain_size[1], domain_size[2]]), OutFlow(), + sound_speed; particle_spacing, + flow_direction, open_boundary_layers, + density=fluid_density, buffer=n_buffer_particles, + pressure, reference_velocity=velocity_function) + +# ========================================================================================== +# ==== Boundary + +boundary_model = BoundaryModelDummyParticles(pipe.boundary.density, pipe.boundary.mass, + AdamiPressureExtrapolation(), + state_equation=state_equation, + #viscosity=ViscosityAdami(nu=1e-4), + smoothing_kernel, smoothing_length) + +boundary_system = BoundarySPHSystem(pipe.boundary, boundary_model) + +# ========================================================================================== +# ==== Simulation +semi = Semidiscretization(fluid_system, + open_boundary_in, + open_boundary_out, + boundary_system, + neighborhood_search=GridNeighborhoodSearch) + +ode = semidiscretize(semi, tspan) + +info_callback = InfoCallback(interval=100) +saving_callback = SolutionSavingCallback(dt=0.02, prefix="") + +callbacks = CallbackSet(info_callback, saving_callback, UpdateCallback()) + +# Use a Runge-Kutta method with automatic (error based) time step size control. +# Enable threading of the RK method for better performance on multiple threads. +# Limiting of the maximum stepsize is necessary to prevent crashing. +# When particles are approaching a wall in a uniform way, they can be advanced +# with large time steps. Close to the wall, the stepsize has to be reduced drastically. +# Sometimes, the method fails to do so with Monaghan-Kajtar BC because forces +# become extremely large when fluid particles are very close to boundary particles, +# and the time integration method interprets this as an instability. + +sol = solve(ode, RDPK3SpFSAL49(), + abstol=1e-5, # Default abstol is 1e-6 (may need to be tuned to prevent boundary penetration) + reltol=1e-3, # Default reltol is 1e-3 (may need to be tuned to prevent boundary penetration) + dtmax=1e-2, # Limit stepsize to prevent crashing + save_everystep=false, callback=callbacks); From b19577f45ba33a3a12067bbfe3ae2dda3f1f3aa1 Mon Sep 17 00:00:00 2001 From: LasNikas Date: Fri, 16 Feb 2024 15:22:34 +0100 Subject: [PATCH 036/107] add docs `UpdateCallback` --- src/callbacks/update.jl | 21 ++++++++++++++++----- test/callbacks/update.jl | 4 ++-- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/src/callbacks/update.jl b/src/callbacks/update.jl index baffe86e7..47058cb18 100644 --- a/src/callbacks/update.jl +++ b/src/callbacks/update.jl @@ -3,8 +3,19 @@ struct UpdateCallback{I} update :: Bool end -function UpdateCallback(; update=true, interval::Integer=0, dt=0.0) - if dt > 0 && interval > 0 +""" + UpdateCallback(; update=true, interval::Integer, dt=0.0) + +Callback to update quantities either at the end of every `interval` integration step or at +regular intervals at `dt` in terms of integration time. + +# Keywords +- `update`: Callback is only applied when `true` (default) +- `interval`: Update quantities at the end of every `interval` time steps (default `inverval=1`) +- `dt`: Update quantitiesat in regular intervals of `dt` in terms of integration time +""" +function UpdateCallback(; update=true, interval::Integer=-1, dt=0.0) + if dt > 0 && interval !== -1 throw(ArgumentError("Setting both interval and dt is not supported!")) end @@ -13,7 +24,7 @@ function UpdateCallback(; update=true, interval::Integer=0, dt=0.0) interval = Float64(dt) # Update every time step (default) - elseif update && interval == 0 + elseif update && interval == -1 interval = 1 end @@ -78,7 +89,7 @@ end function Base.show(io::IO, cb::DiscreteCallback{<:Any, <:UpdateCallback}) @nospecialize cb # reduce precompilation time - print(io, "UpdateCallback(interval=", cb.affect!.interval, ")") + print(io, "UpdateCallback(interval=", (cb.affect!.update ? cb.affect!.interval : "-"), ")") end function Base.show(io::IO, @@ -97,7 +108,7 @@ function Base.show(io::IO, ::MIME"text/plain", else update_cb = cb.affect! setup = [ - "interval" => update_cb.interval, + "interval" => update_cb.update ? update_cb.interval : "-", "update" => update_cb.update ? "yes" : "no", ] summary_box(io, "UpdateCallback", setup) diff --git a/test/callbacks/update.jl b/test/callbacks/update.jl index 22231340e..5515b94a6 100644 --- a/test/callbacks/update.jl +++ b/test/callbacks/update.jl @@ -45,14 +45,14 @@ callback3 = UpdateCallback(update=false) - show_compact = "UpdateCallback(interval=0)" + show_compact = "UpdateCallback(interval=-)" @test repr(callback3) == show_compact show_box = """ ┌──────────────────────────────────────────────────────────────────────────────────────────────────┐ │ UpdateCallback │ │ ══════════════ │ - │ interval: ……………………………………………………… 0 │ + │ interval: ……………………………………………………… - │ │ update: …………………………………………………………… no │ └──────────────────────────────────────────────────────────────────────────────────────────────────┘""" @test repr("text/plain", callback3) == show_box From 38902d9df68cd671b56128e0b88b8565ef520a0f Mon Sep 17 00:00:00 2001 From: LasNikas Date: Thu, 22 Feb 2024 11:05:59 +0100 Subject: [PATCH 037/107] add `UpdateCallback` --- src/TrixiParticles.jl | 2 +- src/callbacks/callbacks.jl | 1 + src/callbacks/update.jl | 139 ++++++++++++++++++++++++++++++++++++ test/callbacks/callbacks.jl | 1 + test/callbacks/update.jl | 65 +++++++++++++++++ 5 files changed, 207 insertions(+), 1 deletion(-) create mode 100644 src/callbacks/update.jl create mode 100644 test/callbacks/update.jl diff --git a/src/TrixiParticles.jl b/src/TrixiParticles.jl index 3aa241248..d8fb0fe31 100644 --- a/src/TrixiParticles.jl +++ b/src/TrixiParticles.jl @@ -44,7 +44,7 @@ export InitialCondition export WeaklyCompressibleSPHSystem, EntropicallyDampedSPHSystem, TotalLagrangianSPHSystem, BoundarySPHSystem export InfoCallback, SolutionSavingCallback, DensityReinitializationCallback, - PostprocessCallback, StepsizeCallback + PostprocessCallback, StepsizeCallback, UpdateCallback export ContinuityDensity, SummationDensity export PenaltyForceGanzenmueller export SchoenbergCubicSplineKernel, SchoenbergQuarticSplineKernel, diff --git a/src/callbacks/callbacks.jl b/src/callbacks/callbacks.jl index 7cc580038..62b6c106c 100644 --- a/src/callbacks/callbacks.jl +++ b/src/callbacks/callbacks.jl @@ -31,3 +31,4 @@ include("solution_saving.jl") include("density_reinit.jl") include("post_process.jl") include("stepsize.jl") +include("update.jl") diff --git a/src/callbacks/update.jl b/src/callbacks/update.jl new file mode 100644 index 000000000..6bb1b7736 --- /dev/null +++ b/src/callbacks/update.jl @@ -0,0 +1,139 @@ +struct UpdateCallback{I} + interval :: I + update :: Bool +end + +""" + UpdateCallback(; update=true, interval::Integer, dt=0.0) + +Callback to update quantities either at the end of every `interval` integration step or at +regular intervals at `dt` in terms of integration time. + +# Keywords +- `update`: Callback is only applied when `true` (default) +- `interval`: Update quantities at the end of every `interval` time steps (default `inverval=1`) +- `dt`: Update quantities in regular intervals of `dt` in terms of integration time +""" +function UpdateCallback(; update=true, interval::Integer=-1, dt=0.0) + if dt > 0 && interval !== -1 + throw(ArgumentError("Setting both interval and dt is not supported!")) + end + + # Update in intervals in terms of simulation time + if dt > 0 + interval = Float64(dt) + + # Update every time step (default) + elseif update && interval == -1 + interval = 1 + end + + update_callback! = UpdateCallback(interval, update) + + if dt > 0 && update + # Add a `tstop` every `dt`, and save the final solution. + return PeriodicCallback(update_callback!, dt, + initialize=initial_update!, + save_positions=(false, false)) + else + # The first one is the condition, the second the affect! + return DiscreteCallback(update_callback!, update_callback!, + initialize=initial_update!, + save_positions=(false, false)) + end +end + +# initialize +function initial_update!(cb, u, t, integrator) + # The `UpdateCallback` is either `cb.affect!` (with `DiscreteCallback`) + # or `cb.affect!.affect!` (with `PeriodicCallback`). + # Let recursive dispatch handle this. + + initial_update!(cb.affect!, u, t, integrator) +end + +initial_update!(cb::UpdateCallback, u, t, integrator) = cb.update && cb(integrator) + +# condition +function (update_callback!::UpdateCallback)(u, t, integrator) + (; interval, update) = update_callback! + + # With error-based step size control, some steps can be rejected. Thus, + # `integrator.iter >= integrator.stats.naccept` + # (total #steps) (#accepted steps) + # We need to check the number of accepted steps since callbacks are not + # activated after a rejected step. + return update && (integrator.stats.naccept % interval == 0) +end + +# affect +function (update_callback!::UpdateCallback)(integrator) + t = integrator.t + semi = integrator.p + v_ode, u_ode = integrator.u.x + + # Update quantities that are stored in the systems. These quantities (e.g. pressure) + # still have the values from the last stage of the previous step if not updated here. + update_systems_and_nhs(v_ode, u_ode, semi, t) + + # Other updates might be added here later (e.g. Transport Velocity Formulation). + # @trixi_timeit timer() "update open boundary" foreach_system(semi) do system + # update_open_boundary_eachstep!(system, v_ode, u_ode, semi, t) + # end + # + # @trixi_timeit timer() "update TVF" foreach_system(semi) do system + # update_transport_velocity_eachstep!(system, v_ode, u_ode, semi, t) + # end + + + # Tell OrdinaryDiffEq that u has been modified + u_modified!(integrator, true) + + return integrator +end + +function Base.show(io::IO, cb::DiscreteCallback{<:Any, <:UpdateCallback}) + @nospecialize cb # reduce precompilation time + print(io, "UpdateCallback(interval=", (cb.affect!.update ? cb.affect!.interval : "-"), + ")") +end + +function Base.show(io::IO, + cb::DiscreteCallback{<:Any, + <:PeriodicCallbackAffect{<:UpdateCallback}}) + @nospecialize cb # reduce precompilation time + print(io, "UpdateCallback(dt=", cb.affect!.affect!.interval, ")") +end + +function Base.show(io::IO, ::MIME"text/plain", + cb::DiscreteCallback{<:Any, <:UpdateCallback}) + @nospecialize cb # reduce precompilation time + + if get(io, :compact, false) + show(io, cb) + else + update_cb = cb.affect! + setup = [ + "interval" => update_cb.update ? update_cb.interval : "-", + "update" => update_cb.update ? "yes" : "no", + ] + summary_box(io, "UpdateCallback", setup) + end +end + +function Base.show(io::IO, ::MIME"text/plain", + cb::DiscreteCallback{<:Any, + <:PeriodicCallbackAffect{<:UpdateCallback}}) + @nospecialize cb # reduce precompilation time + + if get(io, :compact, false) + show(io, cb) + else + update_cb = cb.affect!.affect! + setup = [ + "dt" => update_cb.interval, + "update" => update_cb.update ? "yes" : "no", + ] + summary_box(io, "UpdateCallback", setup) + end +end diff --git a/test/callbacks/callbacks.jl b/test/callbacks/callbacks.jl index 3076b9274..3acaa93b5 100644 --- a/test/callbacks/callbacks.jl +++ b/test/callbacks/callbacks.jl @@ -2,4 +2,5 @@ include("info.jl") include("stepsize.jl") include("postprocess.jl") + include("update.jl") end diff --git a/test/callbacks/update.jl b/test/callbacks/update.jl new file mode 100644 index 000000000..5515b94a6 --- /dev/null +++ b/test/callbacks/update.jl @@ -0,0 +1,65 @@ +@testset verbose=true "UpdateCallback" begin + @testset verbose=true "show" begin + # Default + callback0 = UpdateCallback() + + show_compact = "UpdateCallback(interval=1)" + @test repr(callback0) == show_compact + + show_box = """ + ┌──────────────────────────────────────────────────────────────────────────────────────────────────┐ + │ UpdateCallback │ + │ ══════════════ │ + │ interval: ……………………………………………………… 1 │ + │ update: …………………………………………………………… yes │ + └──────────────────────────────────────────────────────────────────────────────────────────────────┘""" + @test repr("text/plain", callback0) == show_box + + callback1 = UpdateCallback(interval=11) + + show_compact = "UpdateCallback(interval=11)" + @test repr(callback1) == show_compact + + show_box = """ + ┌──────────────────────────────────────────────────────────────────────────────────────────────────┐ + │ UpdateCallback │ + │ ══════════════ │ + │ interval: ……………………………………………………… 11 │ + │ update: …………………………………………………………… yes │ + └──────────────────────────────────────────────────────────────────────────────────────────────────┘""" + @test repr("text/plain", callback1) == show_box + + callback2 = UpdateCallback(dt=1.2) + + show_compact = "UpdateCallback(dt=1.2)" + @test repr(callback2) == show_compact + + show_box = """ + ┌──────────────────────────────────────────────────────────────────────────────────────────────────┐ + │ UpdateCallback │ + │ ══════════════ │ + │ dt: ……………………………………………………………………… 1.2 │ + │ update: …………………………………………………………… yes │ + └──────────────────────────────────────────────────────────────────────────────────────────────────┘""" + @test repr("text/plain", callback2) == show_box + + callback3 = UpdateCallback(update=false) + + show_compact = "UpdateCallback(interval=-)" + @test repr(callback3) == show_compact + + show_box = """ + ┌──────────────────────────────────────────────────────────────────────────────────────────────────┐ + │ UpdateCallback │ + │ ══════════════ │ + │ interval: ……………………………………………………… - │ + │ update: …………………………………………………………… no │ + └──────────────────────────────────────────────────────────────────────────────────────────────────┘""" + @test repr("text/plain", callback3) == show_box + end + + @testset "Illegal Input" begin + error_str = "Setting both interval and dt is not supported!" + @test_throws ArgumentError(error_str) UpdateCallback(dt=0.1, interval=1) + end +end From cc3477cd3968505ddd016af48b8c3cd2c66bcf47 Mon Sep 17 00:00:00 2001 From: LasNikas Date: Thu, 22 Feb 2024 11:07:45 +0100 Subject: [PATCH 038/107] fix typo --- src/callbacks/update.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/callbacks/update.jl b/src/callbacks/update.jl index 6bb1b7736..875fe63e2 100644 --- a/src/callbacks/update.jl +++ b/src/callbacks/update.jl @@ -11,7 +11,7 @@ regular intervals at `dt` in terms of integration time. # Keywords - `update`: Callback is only applied when `true` (default) -- `interval`: Update quantities at the end of every `interval` time steps (default `inverval=1`) +- `interval`: Update quantities at the end of every `interval` time steps (default `interval=1`) - `dt`: Update quantities in regular intervals of `dt` in terms of integration time """ function UpdateCallback(; update=true, interval::Integer=-1, dt=0.0) From c6c0b1146d1e13d3939cfb34c19a5dfdb1d38ba5 Mon Sep 17 00:00:00 2001 From: LasNikas Date: Tue, 5 Mar 2024 19:00:15 +0100 Subject: [PATCH 039/107] apply formatter --- src/callbacks/update.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/src/callbacks/update.jl b/src/callbacks/update.jl index 875fe63e2..5bbf6fe9d 100644 --- a/src/callbacks/update.jl +++ b/src/callbacks/update.jl @@ -85,7 +85,6 @@ function (update_callback!::UpdateCallback)(integrator) # update_transport_velocity_eachstep!(system, v_ode, u_ode, semi, t) # end - # Tell OrdinaryDiffEq that u has been modified u_modified!(integrator, true) From 862a8176895d6901728fb3fefbad8fd90dc97eef Mon Sep 17 00:00:00 2001 From: LasNikas Date: Thu, 7 Mar 2024 08:57:34 +0100 Subject: [PATCH 040/107] modify system buffer --- src/general/buffer.jl | 9 ++------- src/general/general.jl | 2 +- src/general/system.jl | 16 +++++++++------- src/schemes/boundary/boundary.jl | 1 - src/schemes/boundary/open_boundary/system.jl | 14 +------------- src/schemes/boundary/system.jl | 3 ++- src/schemes/fluid/fluid.jl | 12 ------------ src/schemes/schemes.jl | 4 ++++ src/schemes/solid/total_lagrangian_sph/system.jl | 3 ++- 9 files changed, 21 insertions(+), 43 deletions(-) diff --git a/src/general/buffer.jl b/src/general/buffer.jl index 5db956f82..021b7f783 100644 --- a/src/general/buffer.jl +++ b/src/general/buffer.jl @@ -19,7 +19,6 @@ allocate_buffer(initial_condition, buffer) = initial_condition function allocate_buffer(initial_condition, buffer::SystemBuffer) (; buffer_size) = buffer - NDIMS = ndims(initial_condition) # Initialize particles far away from simulation domain coordinates = inv(eps()) * ones(ndims(initial_condition), buffer_size) @@ -37,7 +36,7 @@ function allocate_buffer(initial_condition, buffer::SystemBuffer) return union(initial_condition, buffer_ic) end -@inline update!(buffer::Nothing) = buffer +@inline update_system_buffer!(buffer::Nothing) = buffer # `view(eachindex(buffer.active_particle), buffer.active_particle)` is a allocation # (but thread supporting) version of: @@ -45,7 +44,7 @@ end # TODO: Find a non-allocation version # This is also a allocation version but only in every `update!(buffer)` call -@inline function update!(buffer::SystemBuffer) +@inline function update_system_buffer!(buffer::SystemBuffer) (; active_particle) = buffer new_eachparticle = [i for i in eachindex(active_particle) if active_particle[i]] @@ -56,12 +55,8 @@ end return buffer end -@inline each_moving_particle(system, ::Nothing) = Base.OneTo(n_moving_particles(system)) - @inline each_moving_particle(system, buffer) = buffer.eachparticle -@inline active_coordinates(u, system, ::Nothing) = current_coordinates(u, system) - @inline active_coordinates(u, system, buffer) = view(u, :, buffer.active_particle) @inline active_particles(system, buffer) = buffer.eachparticle diff --git a/src/general/general.jl b/src/general/general.jl index 1278c2ce9..5585b85f6 100644 --- a/src/general/general.jl +++ b/src/general/general.jl @@ -22,8 +22,8 @@ include("density_calculators.jl") include("corrections.jl") include("smoothing_kernels.jl") include("initial_condition.jl") +include("buffer.jl") include("system.jl") include("interpolation.jl") -include("buffer.jl") include("file_system.jl") include("custom_quantities.jl") diff --git a/src/general/system.jl b/src/general/system.jl index 959662dfc..cff6cff32 100644 --- a/src/general/system.jl +++ b/src/general/system.jl @@ -17,9 +17,16 @@ initialize!(system, neighborhood_search) = system @inline n_moving_particles(system) = nparticles(system) @inline eachparticle(system) = Base.OneTo(nparticles(system)) -@inline each_moving_particle(system) = Base.OneTo(n_moving_particles(system)) -@inline active_particles(system) = eachparticle(system) +# Wrapper for systems with `SystemBuffer` +@inline each_moving_particle(system) = each_moving_particle(system, system.buffer) +@inline each_moving_particle(system, ::Nothing) = Base.OneTo(n_moving_particles(system)) + +@inline active_coordinates(u, system) = active_coordinates(u, system, system.buffer) +@inline active_coordinates(u, system, ::Nothing) = current_coordinates(u, system) + +@inline active_particles(system) = active_particles(system, system.buffer) +@inline active_particles(system, ::Nothing) = eachparticle(system) # This should not be dispatched by system type. We always expect to get a column of `A`. @inline function extract_svector(A, system, i) @@ -51,9 +58,6 @@ end # are stored in u, for others in the system itself. By default, try to extract them from u. @inline current_coordinates(u, system) = u -# This can be dispatched when using a `SystemBuffer`. -@inline active_coordinates(u, system) = current_coordinates(u, system) - # Specifically get the initial coordinates of a particle for all system types. @inline function initial_coords(system, particle) return extract_svector(initial_coordinates(system), system, particle) @@ -115,5 +119,3 @@ end function update_final!(system, v, u, v_ode, u_ode, semi, t) return system end - -update_system_buffer!(system) = system diff --git a/src/schemes/boundary/boundary.jl b/src/schemes/boundary/boundary.jl index 6ce7b6677..25d9dfb93 100644 --- a/src/schemes/boundary/boundary.jl +++ b/src/schemes/boundary/boundary.jl @@ -1,5 +1,4 @@ include("dummy_particles/dummy_particles.jl") -include("open_boundary/system.jl") include("system.jl") # Monaghan-Kajtar repulsive boundary particles require the `BoundarySPHSystem` # and the `TotalLagrangianSPHSystem` and are therefore included later. diff --git a/src/schemes/boundary/open_boundary/system.jl b/src/schemes/boundary/open_boundary/system.jl index e1b607d83..3027f915f 100644 --- a/src/schemes/boundary/open_boundary/system.jl +++ b/src/schemes/boundary/open_boundary/system.jl @@ -158,17 +158,6 @@ function Base.show(io::IO, ::MIME"text/plain", system::OpenBoundarySPHSystem) end end -@inline function each_moving_particle(system::OpenBoundarySPHSystem) - return each_moving_particle(system, system.buffer) -end - -@inline function active_coordinates(u, system::OpenBoundarySPHSystem) - return active_coordinates(u, system, system.buffer) -end - -@inline active_particles(system::OpenBoundarySPHSystem) = active_particles(system, - system.buffer) - @inline source_terms(system::OpenBoundarySPHSystem) = nothing @inline hydrodynamic_mass(system::OpenBoundarySPHSystem, particle) = system.mass[particle] @@ -248,11 +237,10 @@ function update_open_boundary_eachstep!(system::OpenBoundarySPHSystem, v_ode, u_ @trixi_timeit timer() "check domain" check_domain!(system, v, u, v_ode, u_ode, semi) @trixi_timeit timer() "update buffer" foreach_system(semi) do system - update_system_buffer!(system) + update_system_buffer!(system.buffer) end end -update_system_buffer!(system::OpenBoundarySPHSystem) = update!(system.buffer) # ==== Characteristics # J1: Associated with convection and entropy and propagates at flow velocity. diff --git a/src/schemes/boundary/system.jl b/src/schemes/boundary/system.jl index 6cb5b7bd0..a26d1fb73 100644 --- a/src/schemes/boundary/system.jl +++ b/src/schemes/boundary/system.jl @@ -18,6 +18,7 @@ struct BoundarySPHSystem{BM, NDIMS, ELTYPE <: Real, M, C} <: BoundarySystem{NDIM movement :: M ismoving :: Vector{Bool} cache :: C + buffer :: Nothing function BoundarySPHSystem(initial_condition, model; movement=nothing) coordinates = copy(initial_condition.coordinates) @@ -35,7 +36,7 @@ struct BoundarySPHSystem{BM, NDIMS, ELTYPE <: Real, M, C} <: BoundarySystem{NDIM return new{typeof(model), NDIMS, eltype(coordinates), typeof(movement), typeof(cache)}(initial_condition, coordinates, model, movement, - ismoving, cache) + ismoving, cache, nothing) end end diff --git a/src/schemes/fluid/fluid.jl b/src/schemes/fluid/fluid.jl index 90681c379..bbd15deb3 100644 --- a/src/schemes/fluid/fluid.jl +++ b/src/schemes/fluid/fluid.jl @@ -1,15 +1,3 @@ -@inline function each_moving_particle(system::FluidSystem) - return each_moving_particle(system, system.buffer) -end - -@inline function active_coordinates(u, system::FluidSystem) - return active_coordinates(u, system, system.buffer) -end - -@inline active_particles(system::FluidSystem) = active_particles(system, system.buffer) - -update_system_buffer!(system::FluidSystem) = update!(system.buffer) - @inline function set_particle_density(particle, v, system::FluidSystem, density) set_particle_density(particle, v, system.density_calculator, system, density) diff --git a/src/schemes/schemes.jl b/src/schemes/schemes.jl index 5eabef80e..548ceaea1 100644 --- a/src/schemes/schemes.jl +++ b/src/schemes/schemes.jl @@ -1,3 +1,7 @@ +# Include open boundary system first, +# since this system should not depend on specific systems. +include("boundary/open_boundary/system.jl") + # Include all schemes without rhs first. The rhs depends on the systems to define # interactions between the different system types. include("fluid/fluid.jl") diff --git a/src/schemes/solid/total_lagrangian_sph/system.jl b/src/schemes/solid/total_lagrangian_sph/system.jl index 452a74506..4c56d9df6 100644 --- a/src/schemes/solid/total_lagrangian_sph/system.jl +++ b/src/schemes/solid/total_lagrangian_sph/system.jl @@ -68,6 +68,7 @@ struct TotalLagrangianSPHSystem{BM, NDIMS, ELTYPE <: Real, K, PF, ST} <: SolidSy boundary_model :: BM penalty_force :: PF source_terms :: ST + buffer :: Nothing function TotalLagrangianSPHSystem(initial_condition, smoothing_kernel, smoothing_length, @@ -113,7 +114,7 @@ struct TotalLagrangianSPHSystem{BM, NDIMS, ELTYPE <: Real, K, PF, ST} <: SolidSy n_moving_particles, young_modulus, poisson_ratio, lame_lambda, lame_mu, smoothing_kernel, smoothing_length, acceleration_, boundary_model, - penalty_force, source_terms) + penalty_force, source_terms, nothing) end end From d55eb272e78afdfbe955019fc3ddf493a19037a5 Mon Sep 17 00:00:00 2001 From: LasNikas Date: Thu, 7 Mar 2024 11:00:33 +0100 Subject: [PATCH 041/107] add docstring --- src/schemes/boundary/open_boundary/system.jl | 103 ++++++++++++++++--- 1 file changed, 86 insertions(+), 17 deletions(-) diff --git a/src/schemes/boundary/open_boundary/system.jl b/src/schemes/boundary/open_boundary/system.jl index 3027f915f..7aaa03567 100644 --- a/src/schemes/boundary/open_boundary/system.jl +++ b/src/schemes/boundary/open_boundary/system.jl @@ -1,7 +1,84 @@ +""" + InFlow + +Inflow boundary zone for [`OpenBoundarySPHSystem`](@ref) +""" struct InFlow end +""" + OutFlow + +Outflow boundary zone for [`OpenBoundarySPHSystem`](@ref) +""" struct OutFlow end +""" + OpenBoundarySPHSystem(plane_points, boundary_zone::Union{InFlow, OutFlow}, + sound_speed; + sample_geometry=plane_points, particle_spacing, + flow_direction, open_boundary_layers::Integer=0, density, + buffer=nothing, reference_velocity=zero(flow_direction), + reference_pressure=0.0, reference_density=density) +Open boundary system for in- and outflow particles. +These open boundaries use the characteristic variables to propagate the appropiate values +to the outlet or inlet and has been proposed by Lastiwka et al (2009). For more information +about the method see [Open Boundary System](@ref open_boundary). + +# Arguments +- `plane_points`: Points defining the boundary zones front plane. + The points must either span a rectangular plane in 3D or a line in 2D. + See description above for more information. +- `boundary_zone`: Use [`InFlow`](@ref) for an inflow and [`OutFlow`](@ref) for an outflow boundary. +- `sound_speed`: Speed of sound. + +# Keywords +- `sample_plane`: For customized particle sampling in the boundary zone, this can be either + points defining a 3D plane (2D line), particle coordinates defining a specific + shape or a specific [`InitialCondition`](@ref) type. + The geometry will be extruded in upstream direction with [`ExtrudeGeometry`](@ref). + Default is `plane_points` which fully samples the boundary zone with particles. +- `particle_spacing`: The spacing between the particles in the boundary zone. +- `flow_direction`: Vector defining the flow direction. +- `open_boundary_layers`: Number of particle layers in upstream direction. +- `density`: Density of each particle to define the mass of each particle (see [`InitialCondition`](@ref)). +- `buffer`: Number of buffer particles. +- `reference_velocity`: Reference velocity is either a function mapping each particle's coordinates + and time to its velocity, an array where the ``i``-th column holds + the velocity of particle ``i`` or, for a constant fluid velocity, + a vector holding this velocity. Velocity is constant zero by default. +- `reference_pressure`: Reference pressure is either a function mapping each particle's coordinates + and time to its pressure, a vector holding the pressure of each particle, + or a scalar for a constant pressure over all particles. + Pressure is constant zero by default. +- `reference_density`: Reference density is either a function mapping each particle's coordinates + and time to its density, a vector holding the density of each particle, + or a scalar for a constant density over all particles. + Density is constant zero by default. + +# Examples +```jldoctest; output = false +# 2D inflow +plane_points = ([0.0, 0.0], [0.0, 1.0]) +flow_direction=[1.0, 0.0] + +system = OpenBoundarySPHSystem(plane_points, InFlow(), 10.0; particle_spacing=0.1, + open_boundary_layers=4, density=1.0, flow_direction) + +# 3D outflow +plane_points = ([0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0]) +flow_direction=[0.0, 0.0, 1.0] + +system = OpenBoundarySPHSystem(plane_points, OutFlow(), 10.0; particle_spacing=0.1, + open_boundary_layers=4, density=1.0, flow_direction) + +# 3D particles sampled as cylinder +circle = SphereShape(0.1, 0.5, (0.5, 0.5), 1.0, sphere_type=RoundSphere()) + +system = OpenBoundarySPHSystem(plane_points, InFlow(), 10.0; particle_spacing=0.1, + sample_geometry=circle, + open_boundary_layers=4, density=1.0, flow_direction) +``` +""" struct OpenBoundarySPHSystem{BZ, NDIMS, ELTYPE <: Real, S, RV, RP, RD, B} <: System{NDIMS} initial_condition :: InitialCondition{ELTYPE} mass :: Array{ELTYPE, 1} # [particle] @@ -20,20 +97,13 @@ struct OpenBoundarySPHSystem{BZ, NDIMS, ELTYPE <: Real, S, RV, RP, RD, B} <: Sys reference_density :: RD buffer :: B - function OpenBoundarySPHSystem(plane_points, boundary_zone, sound_speed; + function OpenBoundarySPHSystem(plane_points, boundary_zone::Union{InFlow, OutFlow}, + sound_speed; sample_geometry=plane_points, particle_spacing, - flow_direction, open_boundary_layers=0, density, - velocity=zeros(length(flow_direction)), mass=nothing, - pressure=0.0, buffer=nothing, - reference_velocity=velocity, reference_pressure=pressure, - reference_density=density) - if !((boundary_zone isa InFlow) || (boundary_zone isa OutFlow)) - throw(ArgumentError("`boundary_zone` must either be of type InFlow or OutFlow")) - end - - if !(open_boundary_layers isa Int) - throw(ArgumentError("`open_boundary_layers` must be of type Int")) - elseif open_boundary_layers < sqrt(eps()) + flow_direction, open_boundary_layers::Integer=0, density, + buffer=nothing, reference_velocity=zero(flow_direction), + reference_pressure=0.0, reference_density=density) + if open_boundary_layers < sqrt(eps()) throw(ArgumentError("`open_boundary_layers` must be positive and greater than zero")) end @@ -46,8 +116,7 @@ struct OpenBoundarySPHSystem{BZ, NDIMS, ELTYPE <: Real, S, RV, RP, RD, B} <: Sys # Sample particles in boundary zone. initial_condition = ExtrudeGeometry(sample_geometry; particle_spacing, direction, - n_extrude=open_boundary_layers, velocity, mass, - density, pressure) + n_extrude=open_boundary_layers, density) (buffer ≠ nothing) && (buffer = SystemBuffer(nparticles(initial_condition), buffer)) initial_condition = allocate_buffer(initial_condition, buffer) @@ -106,7 +175,8 @@ struct OpenBoundarySPHSystem{BZ, NDIMS, ELTYPE <: Real, S, RV, RP, RD, B} <: Sys zone_origin = SVector(plane_points[1]...) mass = copy(initial_condition.mass) - pressure = copy(initial_condition.pressure) + pressure = [reference_pressure_(initial_condition.coordinates[:, i], 0.0) + for i in eachparticle(initial_condition)] density = copy(initial_condition.density) volume = similar(initial_condition.density) @@ -241,7 +311,6 @@ function update_open_boundary_eachstep!(system::OpenBoundarySPHSystem, v_ode, u_ end end - # ==== Characteristics # J1: Associated with convection and entropy and propagates at flow velocity. # J2: Propagates downstream to the local flow From d6d80ff1f17e56aad857db1dfbdd166a19866fcb Mon Sep 17 00:00:00 2001 From: LasNikas Date: Thu, 7 Mar 2024 14:39:39 +0100 Subject: [PATCH 042/107] add docs --- docs/src/systems/open_boundary.md | 79 ++++++++++++++++++++ examples/fluid/pipe_flow_2d.jl | 6 +- src/schemes/boundary/open_boundary/system.jl | 1 + 3 files changed, 84 insertions(+), 2 deletions(-) create mode 100644 docs/src/systems/open_boundary.md diff --git a/docs/src/systems/open_boundary.md b/docs/src/systems/open_boundary.md new file mode 100644 index 000000000..7af9fe068 --- /dev/null +++ b/docs/src/systems/open_boundary.md @@ -0,0 +1,79 @@ +# [Open Boundary System](@id open_boundary) +The difficulty in non-reflecting boundary conditions, also called open boundaries, is to determine +the appropriate boundary values of the exact characteristics of the Euler equations. +Giles (1990) derived three characteristic variables which are constant along curves in ``x``-``t`` plane +defined by +```math +\underbrace{\frac{\partial x}{\partial t} = v + c_s, \quad \frac{\partial x}{\partial t} = v}_{\text{downstream-running}}, + \quad + \text{and} \underbrace{\frac{\partial x}{\partial t} = v - c_s}_{\text{upstream-running (for subsonic + flow)}} +``` +and can be interpreted as the trajectories of the sound waves and material particles that carry constant values of the +characteristic variables. + +The characteristic variables based on a linearized set of governing equations are given as +```math +J_1 = -c_s^2 (\rho - \rho_{\text{ref}}) + (p - p_{\text{ref}}) +``` +```math +J_2 = \rho c_s (v - v_{\text{ref}}) + (p - p_{\text{ref}}) +``` +```math +J_3 = - \rho c_s (v - v_{\text{ref}}) + (p - p_{\text{ref}}) +``` +where the subscript "ref" denotes the reference flow near the boundaries, which can be prescribed. + +Specifying the reference variables is **not** equivalent to prescription of ``\rho``, ``v`` and ``p`` +directly, since the perturbation from the reference flow is allowed. + +Lastiwka et al (2009) applied the method of characteristic to SPH and determine the number of variables that should be +**prescribed** at the boundary and the number which should be **propagated** from the fluid domain to the boundary: + +Flow enters the domain through an +- **inflow** boundary: + - Prescribe *downstream*-running characteristics ``J_1`` and ``J_2`` + - Transmit ``J_3`` from the fluid domain (allow ``J_3`` to propagate upstream to the boundary). + +- **outflow** boundary: + - Prescribe *upstream*-running characteristic ``J_3`` + - Transmit ``J_1`` and ``J_2`` from the fluid domain. + +Prescribing is done by simply setting the characteristics to zero. To transmit the characteristics from the fluid +domain, or in other words, to carry the information of the fluid to the boundaries, Negi (2020) use a Shepard Interpolation +```math +f_i = \frac{\sum_j^N f_j W_{ij}}{\sum_j^N W_{ij}}, +``` +where the ``i``th particle is a boundary particle, ``f`` is either ``J_1``, ``J_2`` or ``J_3`` and ``N`` is the set of +neighboring fluid particles. + +To express pressure ``p``, density ``\rho`` and velocity ``v`` as functions of the characteristic variables, the system of equations +from the characteristic variables is inverted and gives +```math + \rho - \rho_{\text{ref}} = \frac{1}{c_s^2} \left( -J_1 + \frac{1}{2} J_2 + \frac{1}{2} J_3 \right), +``` +```math +u - u_{\text{ref}}= \frac{1}{2\rho c_s} \left( J_2 - J_3 \right), +``` +```math +p - p_{\text{ref}} = \frac{1}{2} \left( J_2 + J_3 \right). +``` +Thus, determined ``J_1``, ``J_2`` and ``J_3``, we can easily solve for the actual variables for each particle. + +```@autodocs +Modules = [TrixiParticles] +Pages = [joinpath("schemes", "boundary", "open_boundary", "system.jl")] +``` + +## References +- M. B. Giles "Nonreflecting boundary conditions for Euler equation calculations". + In: AIAA Journal , Vol. 28, No. 12 pages 2050--2058 + [doi: 10.2514/3.10521](https://doi.org/10.2514/3.10521) +- M. Lastiwka, M. Basa, N. J. Quinlan. + "Permeable and non-reflecting boundary conditions in SPH". + In: International Journal for Numerical Methods in Fluids 61, (2009), pages 709--724. + [doi: 10.1002/fld.1971](https://doi.org/10.1002/fld.1971) +- P. Negi, P. Ramachandran, A. Haftu. + "An improved non-reflecting outlet boundary condition for weakly-compressible SPH". + In: Computer Methods in Applied Mechanics and Engineering 367, (2020), pages 113119. + [doi: 10.1016/j.cma.2020.113119](https://doi.org/10.1016/j.cma.2020.113119) diff --git a/examples/fluid/pipe_flow_2d.jl b/examples/fluid/pipe_flow_2d.jl index 6514638b2..a638e4674 100644 --- a/examples/fluid/pipe_flow_2d.jl +++ b/examples/fluid/pipe_flow_2d.jl @@ -69,14 +69,16 @@ open_boundary_in = OpenBoundarySPHSystem(([0.0, 0.0], [0.0, domain_size[2]]), In sound_speed; particle_spacing, flow_direction, open_boundary_layers, density=fluid_density, buffer=n_buffer_particles, - pressure, reference_velocity=velocity_function) + reference_pressure=pressure, + reference_velocity=velocity_function) open_boundary_out = OpenBoundarySPHSystem(([domain_size[1], 0.0], [domain_size[1], domain_size[2]]), OutFlow(), sound_speed; particle_spacing, flow_direction, open_boundary_layers, density=fluid_density, buffer=n_buffer_particles, - pressure, reference_velocity=velocity_function) + reference_pressure=pressure, + reference_velocity=velocity_function) # ========================================================================================== # ==== Boundary diff --git a/src/schemes/boundary/open_boundary/system.jl b/src/schemes/boundary/open_boundary/system.jl index 7aaa03567..eb28344d0 100644 --- a/src/schemes/boundary/open_boundary/system.jl +++ b/src/schemes/boundary/open_boundary/system.jl @@ -335,6 +335,7 @@ function evaluate_characteristics!(system, v, u, v_ode, u_ode, semi, t) # Only some of the in-/outlet particles are in the influence of the fluid particles. # Thus, we find the characteristics for the particle which are outside the influence # using the average of the values of the previous time step. + # Negi (2020) https://doi.org/10.1016/j.cma.2020.113119 @threaded for particle in each_moving_particle(system) # Particle is outside of the influence of fluid particles From 5eeecd5d610207fb78ae4f279e17072cb9c7285d Mon Sep 17 00:00:00 2001 From: LasNikas Date: Thu, 7 Mar 2024 14:59:20 +0100 Subject: [PATCH 043/107] fix tests --- examples/fluid/pipe_flow_2d.jl | 6 ++++-- src/schemes/boundary/open_boundary/system.jl | 3 ++- src/schemes/fluid/entropically_damped_sph/system.jl | 4 ++-- test/examples/examples.jl | 8 ++++++++ 4 files changed, 16 insertions(+), 5 deletions(-) diff --git a/examples/fluid/pipe_flow_2d.jl b/examples/fluid/pipe_flow_2d.jl index a638e4674..dbbc3aa17 100644 --- a/examples/fluid/pipe_flow_2d.jl +++ b/examples/fluid/pipe_flow_2d.jl @@ -21,7 +21,7 @@ domain_size = (1.0, 0.4) flow_direction = [1.0, 0.0] reynolds_number = 100 -prescribed_velocity = 2.0 +const prescribed_velocity = 2.0 particle_spacing = domain_length_factor * domain_size[1] @@ -63,7 +63,9 @@ fluid_system = WeaklyCompressibleSPHSystem(pipe.fluid, fluid_density_calculator, # ========================================================================================== # ==== Open Boundary -velocity_function(pos, t) = [0.5prescribed_velocity * sin(2pi * t) + prescribed_velocity, 0] +function velocity_function(pos, t) + return SVector(0.5prescribed_velocity * sin(2pi * t) + prescribed_velocity, 0) +end open_boundary_in = OpenBoundarySPHSystem(([0.0, 0.0], [0.0, domain_size[2]]), InFlow(), sound_speed; particle_spacing, diff --git a/src/schemes/boundary/open_boundary/system.jl b/src/schemes/boundary/open_boundary/system.jl index eb28344d0..a2b8c2fa3 100644 --- a/src/schemes/boundary/open_boundary/system.jl +++ b/src/schemes/boundary/open_boundary/system.jl @@ -101,7 +101,8 @@ struct OpenBoundarySPHSystem{BZ, NDIMS, ELTYPE <: Real, S, RV, RP, RD, B} <: Sys sound_speed; sample_geometry=plane_points, particle_spacing, flow_direction, open_boundary_layers::Integer=0, density, - buffer=nothing, reference_velocity=zero(flow_direction), + buffer=nothing, + reference_velocity=zeros(length(flow_direction)), reference_pressure=0.0, reference_density=density) if open_boundary_layers < sqrt(eps()) throw(ArgumentError("`open_boundary_layers` must be positive and greater than zero")) diff --git a/src/schemes/fluid/entropically_damped_sph/system.jl b/src/schemes/fluid/entropically_damped_sph/system.jl index b4e0b8f42..d12c7b9e0 100644 --- a/src/schemes/fluid/entropically_damped_sph/system.jl +++ b/src/schemes/fluid/entropically_damped_sph/system.jl @@ -92,8 +92,8 @@ struct EntropicallyDampedSPHSystem{NDIMS, ELTYPE <: Real, DC, K, V, new{NDIMS, ELTYPE, typeof(density_calculator), typeof(smoothing_kernel), typeof(viscosity), typeof(pressure_acceleration), typeof(source_terms), - typeof(cache), - typeof(buffer)}(initial_condition, mass, density_calculator, smoothing_kernel, + typeof(buffer), + typeof(cache)}(initial_condition, mass, density_calculator, smoothing_kernel, smoothing_length, sound_speed, viscosity, nu_edac, acceleration_, nothing, pressure_acceleration, source_terms, buffer, cache) diff --git a/test/examples/examples.jl b/test/examples/examples.jl index 63d78cbb0..f0e7d2dbf 100644 --- a/test/examples/examples.jl +++ b/test/examples/examples.jl @@ -120,6 +120,14 @@ @test count_rhs_allocations(sol, semi) == 0 end + @trixi_testset "fluid/pipe_flow_2d.jl" begin + @test_nowarn_mod trixi_include(@__MODULE__, tspan=(0.0, 0.5), + joinpath(examples_dir(), "fluid", + "pipe_flow_2d.jl")) + @test sol.retcode == ReturnCode.Success + @test count_rhs_allocations(sol, semi) == 0 + end + include("dam_break_2d_corrections.jl") end From cba3cff070769cc7c4c6a2c6512468bc3b16c608 Mon Sep 17 00:00:00 2001 From: LasNikas Date: Thu, 7 Mar 2024 15:04:41 +0100 Subject: [PATCH 044/107] fix typos --- src/callbacks/update.jl | 2 +- src/schemes/boundary/open_boundary/system.jl | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/callbacks/update.jl b/src/callbacks/update.jl index 8ec2d2f5b..0cb5d7c09 100644 --- a/src/callbacks/update.jl +++ b/src/callbacks/update.jl @@ -11,7 +11,7 @@ regular intervals at `dt` in terms of integration time. # Keywords - `update`: Callback is only applied when `true` (default) -- `interval`: Update quantities at the end of every `interval` time steps (default `inverval=1`) +- `interval`: Update quantities at the end of every `interval` time steps (default `interval=1`) - `dt`: Update quantities in regular intervals of `dt` in terms of integration time """ function UpdateCallback(; update=true, interval::Integer=-1, dt=0.0) diff --git a/src/schemes/boundary/open_boundary/system.jl b/src/schemes/boundary/open_boundary/system.jl index a2b8c2fa3..a93c75058 100644 --- a/src/schemes/boundary/open_boundary/system.jl +++ b/src/schemes/boundary/open_boundary/system.jl @@ -20,7 +20,7 @@ struct OutFlow end buffer=nothing, reference_velocity=zero(flow_direction), reference_pressure=0.0, reference_density=density) Open boundary system for in- and outflow particles. -These open boundaries use the characteristic variables to propagate the appropiate values +These open boundaries use the characteristic variables to propagate the appropriate values to the outlet or inlet and has been proposed by Lastiwka et al (2009). For more information about the method see [Open Boundary System](@ref open_boundary). @@ -56,7 +56,7 @@ about the method see [Open Boundary System](@ref open_boundary). Density is constant zero by default. # Examples -```jldoctest; output = false +```julia # 2D inflow plane_points = ([0.0, 0.0], [0.0, 1.0]) flow_direction=[1.0, 0.0] @@ -273,13 +273,13 @@ end @inline function within_boundary_zone(particle_coords, system) (; zone_origin, spanning_set) = system - particle_positon = particle_coords - zone_origin + particle_position = particle_coords - zone_origin for dim in 1:ndims(system) span_dim = spanning_set[dim] # Checks whether the projection of the particle position # falls within the range of the zone. - if !(0 <= dot(particle_positon, span_dim) <= dot(span_dim, span_dim)) + if !(0 <= dot(particle_position, span_dim) <= dot(span_dim, span_dim)) # Particle is not in boundary zone. return false @@ -389,7 +389,7 @@ function evaluate_characteristics!(system, neighbor_system::FluidSystem, system_coords = current_coordinates(u, system) neighbor_coords = current_coordinates(u_neighbor_system, neighbor_system) - # Loop over all flud neighbors within the kernel cutoff. + # Loop over all fluid neighbors within the kernel cutoff. for_particle_neighbor(system, neighbor_system, system_coords, neighbor_coords, nhs) do particle, neighbor, pos_diff, distance neighbor_position = current_coords(u_neighbor_system, neighbor_system, neighbor) @@ -535,7 +535,7 @@ end return system end -# Flud particle is in boundary zone +# Fluid particle is in boundary zone @inline function transform_particle!(fluid_system::FluidSystem, system, boundary_zone, particle, v, u, v_fluid, u_fluid) # Activate particle in boundary zone From 9f52875a05fbbd87ade82f8e4a9a5cbe2dadf97b Mon Sep 17 00:00:00 2001 From: LasNikas Date: Thu, 7 Mar 2024 15:05:21 +0100 Subject: [PATCH 045/107] apply formatter --- src/schemes/fluid/entropically_damped_sph/system.jl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/schemes/fluid/entropically_damped_sph/system.jl b/src/schemes/fluid/entropically_damped_sph/system.jl index d12c7b9e0..87abc1925 100644 --- a/src/schemes/fluid/entropically_damped_sph/system.jl +++ b/src/schemes/fluid/entropically_damped_sph/system.jl @@ -94,9 +94,9 @@ struct EntropicallyDampedSPHSystem{NDIMS, ELTYPE <: Real, DC, K, V, typeof(viscosity), typeof(pressure_acceleration), typeof(source_terms), typeof(buffer), typeof(cache)}(initial_condition, mass, density_calculator, smoothing_kernel, - smoothing_length, sound_speed, viscosity, nu_edac, - acceleration_, nothing, pressure_acceleration, source_terms, - buffer, cache) + smoothing_length, sound_speed, viscosity, nu_edac, + acceleration_, nothing, pressure_acceleration, source_terms, + buffer, cache) end end From 96b15c6ddeb1702e023455646994e8a37e153dec Mon Sep 17 00:00:00 2001 From: LasNikas Date: Thu, 7 Mar 2024 16:37:40 +0100 Subject: [PATCH 046/107] fix tests --- test/general/buffer.jl | 6 +++--- test/general/semidiscretization.jl | 3 +++ .../boundary/open_boundary/characteristic_variables.jl | 1 + 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/test/general/buffer.jl b/test/general/buffer.jl index 05e1f5bc8..36d83aeca 100644 --- a/test/general/buffer.jl +++ b/test/general/buffer.jl @@ -15,7 +15,7 @@ particle_ID = TrixiParticles.available_particle(system_buffer) - TrixiParticles.update!(system_buffer.buffer) + TrixiParticles.update_system_buffer!(system_buffer.buffer) @test Base.OneTo(n_particles + 1) == TrixiParticles.each_moving_particle(system_buffer) @@ -23,7 +23,7 @@ TrixiParticles.deactivate_particle!(system_buffer, particle_ID, ones(2, particle_ID)) - TrixiParticles.update!(system_buffer.buffer) + TrixiParticles.update_system_buffer!(system_buffer.buffer) @test Base.OneTo(n_particles) == TrixiParticles.each_moving_particle(system_buffer) @@ -31,7 +31,7 @@ TrixiParticles.deactivate_particle!(system_buffer, particle_ID, ones(2, particle_ID)) - TrixiParticles.update!(system_buffer.buffer) + TrixiParticles.update_system_buffer!(system_buffer.buffer) @test setdiff(Base.OneTo(n_particles), particle_ID) == TrixiParticles.each_moving_particle(system_buffer) diff --git a/test/general/semidiscretization.jl b/test/general/semidiscretization.jl index ac0f34300..899e12a35 100644 --- a/test/general/semidiscretization.jl +++ b/test/general/semidiscretization.jl @@ -131,6 +131,9 @@ v2 = zeros(4 * 3) v_ode = vcat(vec(v1), v2) + # Avoid `SystemBuffer` barrier + TrixiParticles.each_moving_particle(system::Union{System1, System2}) = TrixiParticles.eachparticle(system) + TrixiParticles.add_source_terms!(dv_ode, v_ode, u_ode, semi) dv1 = TrixiParticles.wrap_v(dv_ode, system1, semi) diff --git a/test/schemes/boundary/open_boundary/characteristic_variables.jl b/test/schemes/boundary/open_boundary/characteristic_variables.jl index ee8f4a4b4..7a243a1a9 100644 --- a/test/schemes/boundary/open_boundary/characteristic_variables.jl +++ b/test/schemes/boundary/open_boundary/characteristic_variables.jl @@ -49,6 +49,7 @@ direction=(sign_ * flow_direction)) fluid_system = EntropicallyDampedSPHSystem(fluid, smoothing_kernel, + density_calculator=ContinuityDensity(), smoothing_length, sound_speed) semi = Semidiscretization(fluid_system, inlet_system) From 84d5828ddb5a3a5dcedc5efdd1baa8b37e1aeb33 Mon Sep 17 00:00:00 2001 From: LasNikas Date: Thu, 7 Mar 2024 16:42:43 +0100 Subject: [PATCH 047/107] add comment --- test/schemes/boundary/open_boundary/characteristic_variables.jl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/schemes/boundary/open_boundary/characteristic_variables.jl b/test/schemes/boundary/open_boundary/characteristic_variables.jl index 7a243a1a9..6644045a7 100644 --- a/test/schemes/boundary/open_boundary/characteristic_variables.jl +++ b/test/schemes/boundary/open_boundary/characteristic_variables.jl @@ -80,6 +80,7 @@ end # First evaluation + # Particles not influenced by the fluid have zero values t1 = 2.0 TrixiParticles.evaluate_characteristics!(inlet_system, v, u, v0_ode, u0_ode, semi, t1) @@ -99,6 +100,7 @@ end # Second evaluation + # Particles not influenced by the fluid have previous values t2 = 3.0 TrixiParticles.evaluate_characteristics!(inlet_system, v, u, v0_ode, u0_ode, semi, t2) From ed9c86cf010a44b88feda7211925fed79c9eac83 Mon Sep 17 00:00:00 2001 From: LasNikas Date: Fri, 8 Mar 2024 11:41:32 +0100 Subject: [PATCH 048/107] fix tests --- examples/n_body/n_body_system.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/n_body/n_body_system.jl b/examples/n_body/n_body_system.jl index 068eae953..d6b38900a 100644 --- a/examples/n_body/n_body_system.jl +++ b/examples/n_body/n_body_system.jl @@ -5,12 +5,13 @@ struct NBodySystem{NDIMS, ELTYPE <: Real} <: TrixiParticles.System{NDIMS} initial_condition :: InitialCondition{ELTYPE} mass :: Array{ELTYPE, 1} # [particle] G :: ELTYPE + buffer :: Nothing function NBodySystem(initial_condition, G) mass = copy(initial_condition.mass) new{size(initial_condition.coordinates, 1), - eltype(mass)}(initial_condition, mass, G) + eltype(mass)}(initial_condition, mass, G, nothing) end end From 08b47f2bedeb9cd488322e2295d4cba38e4e0fab Mon Sep 17 00:00:00 2001 From: LasNikas Date: Fri, 19 Apr 2024 12:20:01 +0200 Subject: [PATCH 049/107] remove update bool --- src/callbacks/update.jl | 24 ++++++++++-------------- test/callbacks/update.jl | 17 ----------------- 2 files changed, 10 insertions(+), 31 deletions(-) diff --git a/src/callbacks/update.jl b/src/callbacks/update.jl index 5bbf6fe9d..d370783b7 100644 --- a/src/callbacks/update.jl +++ b/src/callbacks/update.jl @@ -1,6 +1,5 @@ struct UpdateCallback{I} - interval :: I - update :: Bool + interval::I end """ @@ -14,7 +13,7 @@ regular intervals at `dt` in terms of integration time. - `interval`: Update quantities at the end of every `interval` time steps (default `interval=1`) - `dt`: Update quantities in regular intervals of `dt` in terms of integration time """ -function UpdateCallback(; update=true, interval::Integer=-1, dt=0.0) +function UpdateCallback(; interval::Integer=-1, dt=0.0) if dt > 0 && interval !== -1 throw(ArgumentError("Setting both interval and dt is not supported!")) end @@ -24,13 +23,13 @@ function UpdateCallback(; update=true, interval::Integer=-1, dt=0.0) interval = Float64(dt) # Update every time step (default) - elseif update && interval == -1 + elseif interval == -1 interval = 1 end - update_callback! = UpdateCallback(interval, update) + update_callback! = UpdateCallback(interval) - if dt > 0 && update + if dt > 0 # Add a `tstop` every `dt`, and save the final solution. return PeriodicCallback(update_callback!, dt, initialize=initial_update!, @@ -52,18 +51,18 @@ function initial_update!(cb, u, t, integrator) initial_update!(cb.affect!, u, t, integrator) end -initial_update!(cb::UpdateCallback, u, t, integrator) = cb.update && cb(integrator) +initial_update!(cb::UpdateCallback, u, t, integrator) = cb(integrator) # condition function (update_callback!::UpdateCallback)(u, t, integrator) - (; interval, update) = update_callback! + (; interval) = update_callback! # With error-based step size control, some steps can be rejected. Thus, # `integrator.iter >= integrator.stats.naccept` # (total #steps) (#accepted steps) # We need to check the number of accepted steps since callbacks are not # activated after a rejected step. - return update && (integrator.stats.naccept % interval == 0) + return integrator.stats.naccept % interval == 0 end # affect @@ -93,8 +92,7 @@ end function Base.show(io::IO, cb::DiscreteCallback{<:Any, <:UpdateCallback}) @nospecialize cb # reduce precompilation time - print(io, "UpdateCallback(interval=", (cb.affect!.update ? cb.affect!.interval : "-"), - ")") + print(io, "UpdateCallback(interval=", cb.affect!.interval, ")") end function Base.show(io::IO, @@ -113,8 +111,7 @@ function Base.show(io::IO, ::MIME"text/plain", else update_cb = cb.affect! setup = [ - "interval" => update_cb.update ? update_cb.interval : "-", - "update" => update_cb.update ? "yes" : "no", + "interval" => update_cb.interval, ] summary_box(io, "UpdateCallback", setup) end @@ -131,7 +128,6 @@ function Base.show(io::IO, ::MIME"text/plain", update_cb = cb.affect!.affect! setup = [ "dt" => update_cb.interval, - "update" => update_cb.update ? "yes" : "no", ] summary_box(io, "UpdateCallback", setup) end diff --git a/test/callbacks/update.jl b/test/callbacks/update.jl index 5515b94a6..180f0bb97 100644 --- a/test/callbacks/update.jl +++ b/test/callbacks/update.jl @@ -11,7 +11,6 @@ │ UpdateCallback │ │ ══════════════ │ │ interval: ……………………………………………………… 1 │ - │ update: …………………………………………………………… yes │ └──────────────────────────────────────────────────────────────────────────────────────────────────┘""" @test repr("text/plain", callback0) == show_box @@ -25,7 +24,6 @@ │ UpdateCallback │ │ ══════════════ │ │ interval: ……………………………………………………… 11 │ - │ update: …………………………………………………………… yes │ └──────────────────────────────────────────────────────────────────────────────────────────────────┘""" @test repr("text/plain", callback1) == show_box @@ -39,23 +37,8 @@ │ UpdateCallback │ │ ══════════════ │ │ dt: ……………………………………………………………………… 1.2 │ - │ update: …………………………………………………………… yes │ └──────────────────────────────────────────────────────────────────────────────────────────────────┘""" @test repr("text/plain", callback2) == show_box - - callback3 = UpdateCallback(update=false) - - show_compact = "UpdateCallback(interval=-)" - @test repr(callback3) == show_compact - - show_box = """ - ┌──────────────────────────────────────────────────────────────────────────────────────────────────┐ - │ UpdateCallback │ - │ ══════════════ │ - │ interval: ……………………………………………………… - │ - │ update: …………………………………………………………… no │ - └──────────────────────────────────────────────────────────────────────────────────────────────────┘""" - @test repr("text/plain", callback3) == show_box end @testset "Illegal Input" begin From c240b47ec32376c495862d61d4ead1dece4845c5 Mon Sep 17 00:00:00 2001 From: LasNikas Date: Fri, 19 Apr 2024 12:25:01 +0200 Subject: [PATCH 050/107] adapt docstring --- src/callbacks/update.jl | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/callbacks/update.jl b/src/callbacks/update.jl index d370783b7..ca9c05307 100644 --- a/src/callbacks/update.jl +++ b/src/callbacks/update.jl @@ -3,13 +3,12 @@ struct UpdateCallback{I} end """ - UpdateCallback(; update=true, interval::Integer, dt=0.0) + UpdateCallback(; interval::Integer, dt=0.0) Callback to update quantities either at the end of every `interval` integration step or at regular intervals at `dt` in terms of integration time. # Keywords -- `update`: Callback is only applied when `true` (default) - `interval`: Update quantities at the end of every `interval` time steps (default `interval=1`) - `dt`: Update quantities in regular intervals of `dt` in terms of integration time """ From 896bcf4b9399b71639d149534b48ff669e43d6e9 Mon Sep 17 00:00:00 2001 From: LasNikas Date: Fri, 26 Apr 2024 11:37:59 +0200 Subject: [PATCH 051/107] implement suggestions --- src/callbacks/update.jl | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/callbacks/update.jl b/src/callbacks/update.jl index ca9c05307..71576adf2 100644 --- a/src/callbacks/update.jl +++ b/src/callbacks/update.jl @@ -5,12 +5,14 @@ end """ UpdateCallback(; interval::Integer, dt=0.0) -Callback to update quantities either at the end of every `interval` integration step or at -regular intervals at `dt` in terms of integration time. +Callback to update quantities either at the end of every `interval` time steps or +in intervals of `dt` in terms of integration time by adding additional `tstops` +(note that this may change the solution). # Keywords -- `interval`: Update quantities at the end of every `interval` time steps (default `interval=1`) +- `interval=1`: Update quantities at the end of every `interval` time steps. - `dt`: Update quantities in regular intervals of `dt` in terms of integration time + by adding additional `tstops` (note that this may change the solution). """ function UpdateCallback(; interval::Integer=-1, dt=0.0) if dt > 0 && interval !== -1 @@ -34,14 +36,14 @@ function UpdateCallback(; interval::Integer=-1, dt=0.0) initialize=initial_update!, save_positions=(false, false)) else - # The first one is the condition, the second the affect! + # The first one is the `condition`, the second the `affect!` return DiscreteCallback(update_callback!, update_callback!, initialize=initial_update!, save_positions=(false, false)) end end -# initialize +# `initialize` function initial_update!(cb, u, t, integrator) # The `UpdateCallback` is either `cb.affect!` (with `DiscreteCallback`) # or `cb.affect!.affect!` (with `PeriodicCallback`). @@ -52,7 +54,7 @@ end initial_update!(cb::UpdateCallback, u, t, integrator) = cb(integrator) -# condition +# `condition` function (update_callback!::UpdateCallback)(u, t, integrator) (; interval) = update_callback! @@ -61,10 +63,10 @@ function (update_callback!::UpdateCallback)(u, t, integrator) # (total #steps) (#accepted steps) # We need to check the number of accepted steps since callbacks are not # activated after a rejected step. - return integrator.stats.naccept % interval == 0 + return condition_integrator_interval(integrator, interval) end -# affect +# `affect!` function (update_callback!::UpdateCallback)(integrator) t = integrator.t semi = integrator.p @@ -83,7 +85,7 @@ function (update_callback!::UpdateCallback)(integrator) # update_transport_velocity_eachstep!(system, v_ode, u_ode, semi, t) # end - # Tell OrdinaryDiffEq that u has been modified + # Tell OrdinaryDiffEq that `u` has been modified u_modified!(integrator, true) return integrator From d15ba7a34b21058c78d3706f7edf20c100297ad5 Mon Sep 17 00:00:00 2001 From: LasNikas Date: Mon, 6 May 2024 17:32:55 +0200 Subject: [PATCH 052/107] fix test --- src/schemes/boundary/rhs.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/schemes/boundary/rhs.jl b/src/schemes/boundary/rhs.jl index e800adf40..a114935f8 100644 --- a/src/schemes/boundary/rhs.jl +++ b/src/schemes/boundary/rhs.jl @@ -1,7 +1,7 @@ # Interaction of boundary with other systems function interact!(dv, v_particle_system, u_particle_system, v_neighbor_system, u_neighbor_system, neighborhood_search, - particle_system::Union{BoundarySPHSystem, OpenBoundarySPHSystem}, + particle_system::Union{BoundarySystem, OpenBoundarySPHSystem}, neighbor_system) # TODO Solids and moving boundaries should be considered in the continuity equation return dv From fac85ad9662a697c7d115076251e45d6d9d01836 Mon Sep 17 00:00:00 2001 From: LasNikas Date: Tue, 14 May 2024 16:12:14 +0200 Subject: [PATCH 053/107] add check if callback is used --- src/callbacks/update.jl | 13 ++++++++++++- src/schemes/boundary/open_boundary/system.jl | 9 ++++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/callbacks/update.jl b/src/callbacks/update.jl index bac3ebaba..9c919265c 100644 --- a/src/callbacks/update.jl +++ b/src/callbacks/update.jl @@ -52,7 +52,16 @@ function initial_update!(cb, u, t, integrator) initial_update!(cb.affect!, u, t, integrator) end -initial_update!(cb::UpdateCallback, u, t, integrator) = cb(integrator) +function initial_update!(cb::UpdateCallback, u, t, integrator) + semi = integrator.p + + # Tell systems that `UpdateCallback` is used + foreach_system(semi) do system + callback_used!(system) + end + + return cb(integrator) +end # `condition` function (update_callback!::UpdateCallback)(u, t, integrator) @@ -124,3 +133,5 @@ function Base.show(io::IO, ::MIME"text/plain", summary_box(io, "UpdateCallback", setup) end end + +callback_used!(system) = system diff --git a/src/schemes/boundary/open_boundary/system.jl b/src/schemes/boundary/open_boundary/system.jl index d20014521..ea16bf91c 100644 --- a/src/schemes/boundary/open_boundary/system.jl +++ b/src/schemes/boundary/open_boundary/system.jl @@ -96,6 +96,7 @@ struct OpenBoundarySPHSystem{BZ, NDIMS, ELTYPE <: Real, S, RV, RP, RD, B} <: Sys reference_pressure :: RP reference_density :: RD buffer :: B + callback_used :: Ref{Bool} function OpenBoundarySPHSystem(plane_points, boundary_zone::Union{InFlow, OutFlow}, sound_speed; @@ -191,7 +192,7 @@ struct OpenBoundarySPHSystem{BZ, NDIMS, ELTYPE <: Real, S, RV, RP, RD, B} <: Sys characteristics, previous_characteristics, sound_speed, boundary_zone, flow_direction_, zone_origin, spanning_set_, reference_velocity_, reference_pressure_, - reference_density_, buffer) + reference_density_, buffer, false) end end @@ -229,6 +230,8 @@ function Base.show(io::IO, ::MIME"text/plain", system::OpenBoundarySPHSystem) end end +callback_used!(system::OpenBoundarySPHSystem) = system.callback_used[] = true + @inline source_terms(system::OpenBoundarySPHSystem) = nothing @inline hydrodynamic_mass(system::OpenBoundarySPHSystem, particle) = system.mass[particle] @@ -291,6 +294,10 @@ end end function update_final!(system::OpenBoundarySPHSystem, v, u, v_ode, u_ode, semi, t) + if t > 0.0 && !(system.callback_used[]) + throw(ArgumentError("`UpdateCallback` is required when using `OpenBoundarySPHSystem`")) + end + @trixi_timeit timer() "evaluate characteristics" evaluate_characteristics!(system, v, u, v_ode, u_ode, semi, t) From 92d2fe9072d9b4a3efbfc4dde90c33c504e120a1 Mon Sep 17 00:00:00 2001 From: LasNikas Date: Tue, 14 May 2024 16:19:52 +0200 Subject: [PATCH 054/107] add comments in example file --- examples/fluid/pipe_flow_2d.jl | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/examples/fluid/pipe_flow_2d.jl b/examples/fluid/pipe_flow_2d.jl index 9e62bd691..20ef2abee 100644 --- a/examples/fluid/pipe_flow_2d.jl +++ b/examples/fluid/pipe_flow_2d.jl @@ -6,10 +6,13 @@ using OrdinaryDiffEq # ==== Resolution domain_length_factor = 0.05 -# Change spacing ratio to 3 and boundary layers to 1 when using Monaghan-Kajtar boundary model +# Make sure that the kernel support of fluid particles at a boundary is always fully sampled boundary_layers = 4 -spacing_ratio = 1 +# Make sure that the kernel support of fluid particles at an open boundary is always +# fully sampled. +# Due to the dynamics at the inlets and outlets, it is recommended to use +# `open_boundary_layers > boundary_layers` open_boundary_layers = 6 # ========================================================================================== @@ -37,7 +40,7 @@ state_equation = StateEquationCole(; sound_speed, reference_density=fluid_densit exponent=7, background_pressure=pressure) pipe = RectangularTank(particle_spacing, domain_size, boundary_size, fluid_density, - pressure=pressure, n_layers=boundary_layers, spacing_ratio=1, + pressure=pressure, n_layers=boundary_layers, faces=(false, false, true, true)) # Shift pipe walls in negative x-direction for the inflow @@ -108,16 +111,7 @@ saving_callback = SolutionSavingCallback(dt=0.02, prefix="") callbacks = CallbackSet(info_callback, saving_callback, UpdateCallback()) -# Use a Runge-Kutta method with automatic (error based) time step size control. -# Enable threading of the RK method for better performance on multiple threads. -# Limiting of the maximum stepsize is necessary to prevent crashing. -# When particles are approaching a wall in a uniform way, they can be advanced -# with large time steps. Close to the wall, the stepsize has to be reduced drastically. -# Sometimes, the method fails to do so with Monaghan-Kajtar BC because forces -# become extremely large when fluid particles are very close to boundary particles, -# and the time integration method interprets this as an instability. - -sol = solve(ode, RDPK3SpFSAL49(), +sol = solve(ode, RDPK3SpFSAL35(), abstol=1e-5, # Default abstol is 1e-6 (may need to be tuned to prevent boundary penetration) reltol=1e-3, # Default reltol is 1e-3 (may need to be tuned to prevent boundary penetration) dtmax=1e-2, # Limit stepsize to prevent crashing From 3adbb7bbaf2f80b92c28b04aff5e49f7bb0309fa Mon Sep 17 00:00:00 2001 From: LasNikas Date: Tue, 14 May 2024 16:33:56 +0200 Subject: [PATCH 055/107] generic types --- src/schemes/boundary/open_boundary/system.jl | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/schemes/boundary/open_boundary/system.jl b/src/schemes/boundary/open_boundary/system.jl index ea16bf91c..bbdd6b606 100644 --- a/src/schemes/boundary/open_boundary/system.jl +++ b/src/schemes/boundary/open_boundary/system.jl @@ -79,14 +79,15 @@ system = OpenBoundarySPHSystem(plane_points, InFlow(), 10.0; particle_spacing=0. open_boundary_layers=4, density=1.0, flow_direction) ``` """ -struct OpenBoundarySPHSystem{BZ, NDIMS, ELTYPE <: Real, S, RV, RP, RD, B} <: System{NDIMS} - initial_condition :: InitialCondition{ELTYPE} - mass :: Array{ELTYPE, 1} # [particle] - density :: Array{ELTYPE, 1} # [particle] - volume :: Array{ELTYPE, 1} # [particle] - pressure :: Array{ELTYPE, 1} # [particle] - characteristics :: Array{ELTYPE, 2} # [characteristics, particle] - previous_characteristics :: Array{ELTYPE, 2} # [characteristics, particle] +struct OpenBoundarySPHSystem{BZ, NDIMS, ELTYPE <: Real, IC, ARRAY1D, ARRAY2D, S, RV, RP, + RD, B} <: System{NDIMS} + initial_condition :: IC + mass :: ARRAY1D # Array{ELTYPE, 1}: [particle] + density :: ARRAY1D # Array{ELTYPE, 1}: [particle] + volume :: ARRAY1D # Array{ELTYPE, 1}: [particle] + pressure :: ARRAY1D # Array{ELTYPE, 1}: [particle] + characteristics :: ARRAY2D # Array{ELTYPE, 2}: [characteristics, particle] + previous_characteristics :: ARRAY2D # Array{ELTYPE, 2}: [characteristics, particle] sound_speed :: ELTYPE boundary_zone :: BZ flow_direction :: SVector{NDIMS, ELTYPE} @@ -185,7 +186,8 @@ struct OpenBoundarySPHSystem{BZ, NDIMS, ELTYPE <: Real, S, RV, RP, RD, B} <: Sys characteristics = zeros(ELTYPE, 3, length(mass)) previous_characteristics = zeros(ELTYPE, 3, length(mass)) - return new{typeof(boundary_zone), NDIMS, ELTYPE, typeof(spanning_set_), + return new{typeof(boundary_zone), NDIMS, ELTYPE, typeof(initial_condition), + typeof(mass), typeof(characteristics), typeof(spanning_set_), typeof(reference_velocity_), typeof(reference_pressure_), typeof(reference_density_), typeof(buffer)}(initial_condition, mass, density, volume, pressure, From 81e0875c332bd7fc8569fd5353ede70ecc6f4002 Mon Sep 17 00:00:00 2001 From: LasNikas Date: Tue, 21 May 2024 16:00:41 +0200 Subject: [PATCH 056/107] merge main --- .github/workflows/Documenter.yml | 2 + Project.toml | 6 +- docs/src/general/neighborhood_search.md | 46 +- examples/n_body/n_body_system.jl | 9 +- src/TrixiParticles.jl | 6 +- src/callbacks/post_process.jl | 6 +- src/general/general.jl | 1 + src/general/initial_condition.jl | 5 +- src/general/interpolation.jl | 13 +- src/general/neighborhood_search.jl | 11 + src/general/semidiscretization.jl | 257 +++++++---- src/neighborhood_search/grid_nhs.jl | 423 ------------------ .../neighborhood_search.jl | 110 ----- src/neighborhood_search/trivial_nhs.jl | 97 ---- src/schemes/boundary/open_boundary/system.jl | 2 +- src/visualization/write2vtk.jl | 3 +- test/Project.toml | 2 +- test/count_allocations.jl | 6 +- test/neighborhood_search/grid_nhs.jl | 272 ----------- .../neighborhood_search.jl | 2 - test/neighborhood_search/trivial_nhs.jl | 10 - .../schemes/solid/total_lagrangian_sph/rhs.jl | 2 +- test/systems/solid_system.jl | 2 +- test/unittest.jl | 1 - 24 files changed, 249 insertions(+), 1045 deletions(-) create mode 100644 src/general/neighborhood_search.jl delete mode 100644 src/neighborhood_search/grid_nhs.jl delete mode 100644 src/neighborhood_search/neighborhood_search.jl delete mode 100644 src/neighborhood_search/trivial_nhs.jl delete mode 100644 test/neighborhood_search/grid_nhs.jl delete mode 100644 test/neighborhood_search/neighborhood_search.jl delete mode 100644 test/neighborhood_search/trivial_nhs.jl diff --git a/.github/workflows/Documenter.yml b/.github/workflows/Documenter.yml index 941fef735..4cc31a611 100644 --- a/.github/workflows/Documenter.yml +++ b/.github/workflows/Documenter.yml @@ -8,10 +8,12 @@ on: paths-ignore: - '.github/workflows/ci.yml' - '.github/workflows/CompatHelper.yml' + - '.github/workflows/TagBot.yml' pull_request: paths-ignore: - '.github/workflows/ci.yml' - '.github/workflows/CompatHelper.yml' + - '.github/workflows/TagBot.yml' workflow_dispatch: concurrency: diff --git a/Project.toml b/Project.toml index f47a5b2c6..20b40306c 100644 --- a/Project.toml +++ b/Project.toml @@ -13,8 +13,8 @@ FastPow = "c0e83750-1142-43a8-81cf-6c956b72b4d1" ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210" JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" -Morton = "2a6d852e-3fac-5a38-885c-fe708af2d09e" MuladdMacro = "46d2c3a1-f734-5fdb-9937-b9b9aeba4221" +PointNeighbors = "1c4d5385-0a27-49de-8e2c-43b175c8985c" Polyester = "f517fe37-dbe3-4b94-8317-1923a5111588" Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7" RecipesBase = "3cdcf5f2-1ef4-517c-9805-6587b60abb01" @@ -22,7 +22,6 @@ Reexport = "189a3867-3050-52da-a836-e630ba90ab69" SciMLBase = "0bca4576-84f4-4d90-8ffe-ffa030f20462" StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" StrideArrays = "d1fa6d79-ef01-42a6-86c9-f7c551f8593b" -ThreadingUtilities = "8290d209-cae3-49c0-8002-c8c24d57dab5" TimerOutputs = "a759f4b9-e2f1-59dc-863e-4aeb61b1ea8f" TrixiBase = "9a0f1c46-06d5-4909-a5a3-ce25d3fa3284" WriteVTK = "64499a7a-5c06-52f2-abe2-ccb03c286192" @@ -35,7 +34,6 @@ DiffEqCallbacks = "2.25, 3" FastPow = "0.1" ForwardDiff = "0.10" JSON = "0.21" -Morton = "0.1" MuladdMacro = "0.2" Polyester = "0.7.5" RecipesBase = "1" @@ -43,8 +41,8 @@ Reexport = "1" SciMLBase = "1, 2" StaticArrays = "1" StrideArrays = "0.1" -ThreadingUtilities = "0.5" TimerOutputs = "0.5" TrixiBase = "0.1" +PointNeighbors = "0.2" WriteVTK = "1" julia = "1.9" diff --git a/docs/src/general/neighborhood_search.md b/docs/src/general/neighborhood_search.md index 5a1512b6d..e611f5350 100644 --- a/docs/src/general/neighborhood_search.md +++ b/docs/src/general/neighborhood_search.md @@ -1,6 +1,44 @@ # Neighborhood Search -```@autodocs -Modules = [TrixiParticles] -Pages = map(file -> joinpath("neighborhood_search", file), readdir(joinpath("..", "src", "neighborhood_search"))) -``` +The neighborhood search is the most essential component for performance. +We provide several implementations in the package +[PointNeighbors.jl](https://github.com/trixi-framework/PointNeighbors.jl). +See the docs of this package for an overview and a comparison of different implementations. + +!!! note "Usage" + To run a simulation with a neighborhood search implementation, just pass the type + to the constructor of the [`Semidiscretization`](@ref): + ```jldoctest semi_example; output=false, setup = :(using TrixiParticles; trixi_include(@__MODULE__, joinpath(examples_dir(), "fluid", "hydrostatic_water_column_2d.jl"), sol=nothing); system1 = fluid_system; system2 = boundary_system) + semi = Semidiscretization(system1, system2, + neighborhood_search=GridNeighborhoodSearch) + + # output + ┌──────────────────────────────────────────────────────────────────────────────────────────────────┐ + │ Semidiscretization │ + │ ══════════════════ │ + │ #spatial dimensions: ………………………… 2 │ + │ #systems: ……………………………………………………… 2 │ + │ neighborhood search: ………………………… GridNeighborhoodSearch │ + │ total #particles: ………………………………… 636 │ + └──────────────────────────────────────────────────────────────────────────────────────────────────┘ + ``` + The keyword arguments `periodic_box_min_corner` and `periodic_box_max_corner` mentioned + in the PointNeighbors.jl docs can also be passed to the + [`Semidiscretization`](@ref) and will internally be forwarded to the neighborhood search. + See the docs of [`Semidiscretization`](@ref) for more details. + ```jldoctest semi_example; output = false + semi = Semidiscretization(system1, system2, + neighborhood_search=GridNeighborhoodSearch, + periodic_box_min_corner=[0.0, -0.25], + periodic_box_max_corner=[1.0, 0.75]) + + # output + ┌──────────────────────────────────────────────────────────────────────────────────────────────────┐ + │ Semidiscretization │ + │ ══════════════════ │ + │ #spatial dimensions: ………………………… 2 │ + │ #systems: ……………………………………………………… 2 │ + │ neighborhood search: ………………………… GridNeighborhoodSearch │ + │ total #particles: ………………………………… 636 │ + └──────────────────────────────────────────────────────────────────────────────────────────────────┘ + ``` diff --git a/examples/n_body/n_body_system.jl b/examples/n_body/n_body_system.jl index d6b38900a..9745ae75c 100644 --- a/examples/n_body/n_body_system.jl +++ b/examples/n_body/n_body_system.jl @@ -32,9 +32,12 @@ function TrixiParticles.write_v0!(v0, system::NBodySystem) end # NHS update -function TrixiParticles.nhs_coords(system::NBodySystem, - neighbor::NBodySystem, u) - return u +function TrixiParticles.update_nhs!(neighborhood_search, + system::NBodySystem, neighbor::NBodySystem, + u_system, u_neighbor) + TrixiParticles.PointNeighbors.update!(neighborhood_search, + u_system, u_neighbor, + particles_moving=(true, true)) end function TrixiParticles.compact_support(system::NBodySystem, diff --git a/src/TrixiParticles.jl b/src/TrixiParticles.jl index e5fa76f82..36a769acc 100644 --- a/src/TrixiParticles.jl +++ b/src/TrixiParticles.jl @@ -11,7 +11,6 @@ using FastPow: @fastpow using ForwardDiff: ForwardDiff using JSON: JSON using LinearAlgebra: norm, dot, I, tr, inv, pinv, det -using Morton: cartesian2morton using MuladdMacro: @muladd using Polyester: Polyester, @batch using Printf: @printf, @sprintf @@ -21,16 +20,16 @@ using SciMLBase: CallbackSet, DiscreteCallback, DynamicalODEProblem, u_modified! @reexport using StaticArrays: SVector using StaticArrays: @SMatrix, SMatrix, setindex using StrideArrays: PtrArray, StaticInt -using ThreadingUtilities using TimerOutputs: TimerOutput, TimerOutputs, print_timer, reset_timer! using TrixiBase: trixi_include +@reexport using PointNeighbors: TrivialNeighborhoodSearch, GridNeighborhoodSearch +using PointNeighbors: PointNeighbors, for_particle_neighbor using WriteVTK: vtk_grid, MeshCell, VTKCellTypes, paraview_collection, vtk_save # util needs to be first because of macro @trixi_timeit include("util.jl") include("callbacks/callbacks.jl") include("general/general.jl") -include("neighborhood_search/neighborhood_search.jl") include("setups/setups.jl") include("schemes/schemes.jl") @@ -60,7 +59,6 @@ export DensityDiffusion, DensityDiffusionMolteniColagrossi, DensityDiffusionFerr export BoundaryModelMonaghanKajtar, BoundaryModelDummyParticles, AdamiPressureExtrapolation, PressureMirroring, PressureZeroing export BoundaryMovement -export GridNeighborhoodSearch, TrivialNeighborhoodSearch export examples_dir, validation_dir, trixi_include export trixi2vtk export RectangularTank, RectangularShape, SphereShape diff --git a/src/callbacks/post_process.jl b/src/callbacks/post_process.jl index 25a8d051b..e2e98a2a0 100644 --- a/src/callbacks/post_process.jl +++ b/src/callbacks/post_process.jl @@ -276,9 +276,9 @@ end # After the simulation has finished, this function is called to write the data to a JSON file function write_postprocess_callback(pp::PostprocessCallback) - if isempty(pp.data) - return - end + isempty(pp.data) && return + + mkpath(pp.output_directory) data = Dict{String, Any}() write_meta_data!(data) diff --git a/src/general/general.jl b/src/general/general.jl index 5585b85f6..77b71f94c 100644 --- a/src/general/general.jl +++ b/src/general/general.jl @@ -27,3 +27,4 @@ include("system.jl") include("interpolation.jl") include("file_system.jl") include("custom_quantities.jl") +include("neighborhood_search.jl") diff --git a/src/general/initial_condition.jl b/src/general/initial_condition.jl index 9ede75648..8e94b1615 100644 --- a/src/general/initial_condition.jl +++ b/src/general/initial_condition.jl @@ -291,11 +291,10 @@ function find_too_close_particles(coords1, coords2, max_distance) result = Int[] nhs = GridNeighborhoodSearch{NDIMS}(max_distance, size(coords2, 2)) - TrixiParticles.initialize!(nhs, coords2) + PointNeighbors.initialize!(nhs, coords1, coords2) # We are modifying the vector `result`, so this cannot be parallel - TrixiParticles.for_particle_neighbor(coords1, coords2, nhs, - parallel=false) do particle, _, _, _ + for_particle_neighbor(coords1, coords2, nhs, parallel=false) do particle, _, _, _ if !(particle in result) append!(result, particle) end diff --git a/src/general/interpolation.jl b/src/general/interpolation.jl index fb917f91a..80116a605 100644 --- a/src/general/interpolation.jl +++ b/src/general/interpolation.jl @@ -485,7 +485,7 @@ end function process_neighborhood_searches(semi, u_ode, ref_system, smoothing_length) if isapprox(smoothing_length, ref_system.smoothing_length) # Update existing NHS - update_nhs(u_ode, semi) + update_nhs!(semi, u_ode) neighborhood_searches = semi.neighborhood_searches[system_indices(ref_system, semi)] else ref_smoothing_kernel = ref_system.smoothing_kernel @@ -494,7 +494,8 @@ function process_neighborhood_searches(semi, u_ode, ref_system, smoothing_length u = wrap_u(u_ode, 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) + nhs = PointNeighbors.copy_neighborhood_search(old_nhs, search_radius, + system_coords, system_coords) return nhs end end @@ -534,13 +535,15 @@ end system_coords = current_coordinates(u, system) # This is basically `for_particle_neighbor` unrolled - for particle in eachneighbor(point_coords, nhs) + for particle in PointNeighbors.eachneighbor(point_coords, nhs) 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) + pos_diff, distance2 = PointNeighbors.compute_periodic_distance(pos_diff, + distance2, + search_radius, + periodic_box) if distance2 > search_radius^2 continue end diff --git a/src/general/neighborhood_search.jl b/src/general/neighborhood_search.jl new file mode 100644 index 000000000..0713f153d --- /dev/null +++ b/src/general/neighborhood_search.jl @@ -0,0 +1,11 @@ +# Loop over all pairs of particles and neighbors within the kernel cutoff. +# `f(particle, neighbor, pos_diff, distance)` is called for every particle-neighbor pair. +# By default, loop over `each_moving_particle(system)`. +function PointNeighbors.for_particle_neighbor(f, system, neighbor_system, + system_coords, neighbor_coords, + neighborhood_search; + particles=each_moving_particle(system), + parallel=true) + for_particle_neighbor(f, system_coords, neighbor_coords, neighborhood_search, + particles=particles, parallel=parallel) +end diff --git a/src/general/semidiscretization.jl b/src/general/semidiscretization.jl index ba7c83f34..1ae3a6a2e 100644 --- a/src/general/semidiscretization.jl +++ b/src/general/semidiscretization.jl @@ -13,8 +13,8 @@ the keyword argument `neighborhood_search`. A value of `nothing` means no neighb # Keywords - `neighborhood_search`: The type of neighborhood search to be used in the simulation. - By default, the [`GridNeighborhoodSearch`](@ref) is used. - Use [`TrivialNeighborhoodSearch`](@ref) or `nothing` to loop + By default, the `GridNeighborhoodSearch` is used. + Use `TrivialNeighborhoodSearch` or `nothing` to loop over all particles (no neighborhood search). - `periodic_box_min_corner`: In order to use a (rectangular) periodic domain, pass the coordinates of the domain corner in negative coordinate @@ -140,7 +140,8 @@ function create_neighborhood_search(system, neighbor, ::Val{GridNeighborhoodSear periodic_box_max_corner=periodic_box_max_corner, threaded_nhs_update=threaded_nhs_update) # Initialize neighborhood search - initialize!(search, initial_coordinates(neighbor)) + PointNeighbors.initialize!(search, initial_coordinates(system), + initial_coordinates(neighbor)) return search end @@ -155,16 +156,12 @@ end return compact_support(neighbor, system) end -@inline function compact_support(system::OpenBoundarySPHSystem, - neighbor::OpenBoundarySPHSystem) +@inline function compact_support(system::Union{BoundaryDEMSystem, OpenBoundarySPHSystem}, + neighbor::Union{BoundaryDEMSystem, OpenBoundarySPHSystem}) # This NHS is never used return 0.0 end -@inline function compact_support(system::BoundaryDEMSystem, neighbor::BoundaryDEMSystem) - return 0.0 -end - @inline function compact_support(system::BoundaryDEMSystem, neighbor::DEMSystem) # Use the compact support of the DEMSystem return compact_support(neighbor, system) @@ -448,7 +445,7 @@ function update_systems_and_nhs(v_ode, u_ode, semi, t) end # Update NHS - @trixi_timeit timer() "update nhs" update_nhs(u_ode, semi) + @trixi_timeit timer() "update nhs" update_nhs!(semi, u_ode) # Second update step. # This is used to calculate density and pressure of the fluid systems @@ -478,14 +475,16 @@ function update_systems_and_nhs(v_ode, u_ode, semi, t) end end -function update_nhs(u_ode, semi) +function update_nhs!(semi, u_ode) # Update NHS for each pair of systems foreach_system(semi) do system + u_system = wrap_u(u_ode, system, semi) + foreach_system(semi) do neighbor u_neighbor = wrap_u(u_ode, neighbor, semi) neighborhood_search = get_neighborhood_search(system, neighbor, semi) - update!(neighborhood_search, nhs_coords(system, neighbor, u_neighbor)) + update_nhs!(neighborhood_search, system, neighbor, u_system, u_neighbor) end end end @@ -615,92 +614,154 @@ end end # NHS updates -# To prevent hard to spot errors there is not default version - -function nhs_coords(system::DEMSystem, neighbor::DEMSystem, u) - return current_coordinates(u, neighbor) -end - -function nhs_coords(system::BoundaryDEMSystem, - neighbor::Union{BoundaryDEMSystem, DEMSystem}, u) - return nothing -end -function nhs_coords(system::DEMSystem, neighbor::BoundaryDEMSystem, u) - return nothing -end - -function nhs_coords(system::FluidSystem, - neighbor::FluidSystem, u) - return current_coordinates(u, neighbor) -end - -function nhs_coords(system::FluidSystem, - neighbor::OpenBoundarySPHSystem, u) - return current_coordinates(u, neighbor) -end - -function nhs_coords(system::OpenBoundarySPHSystem, - neighbor::FluidSystem, u) - return current_coordinates(u, neighbor) -end - -function nhs_coords(system::FluidSystem, - neighbor::TotalLagrangianSPHSystem, u) - return current_coordinates(u, neighbor) -end - -function nhs_coords(system::FluidSystem, - neighbor::BoundarySPHSystem, u) - if neighbor.ismoving[] - return current_coordinates(u, neighbor) - end - - # Don't update - return nothing -end - -function nhs_coords(system::TotalLagrangianSPHSystem, - neighbor::FluidSystem, u) - return current_coordinates(u, neighbor) -end - -function nhs_coords(system::TotalLagrangianSPHSystem, - neighbor::TotalLagrangianSPHSystem, u) - # Don't update - return nothing -end - -function nhs_coords(system::TotalLagrangianSPHSystem, - neighbor::BoundarySPHSystem, u) - if neighbor.ismoving[] - return current_coordinates(u, neighbor) - end - - # Don't update - return nothing -end - -function nhs_coords(system::BoundarySPHSystem, - neighbor::FluidSystem, u) - # Don't update - return nothing -end - -function nhs_coords(system::BoundarySPHSystem{<:BoundaryModelDummyParticles}, - neighbor::FluidSystem, u) - return current_coordinates(u, neighbor) -end - -function nhs_coords(system::BoundarySPHSystem, - neighbor::TotalLagrangianSPHSystem, u) - # Don't update - return nothing -end - -function nhs_coords(system::Union{BoundarySPHSystem, OpenBoundarySPHSystem}, - neighbor::Union{BoundarySPHSystem, OpenBoundarySPHSystem}, u) - # Don't update - return nothing +# To prevent hard-to-find bugs, there is not default version +function update_nhs!(neighborhood_search, + system::FluidSystem, + neighbor::Union{FluidSystem, TotalLagrangianSPHSystem}, + u_system, u_neighbor) + # The current coordinates of fluids and solids change over time + PointNeighbors.update!(neighborhood_search, + current_coordinates(u_system, system), + current_coordinates(u_neighbor, neighbor), + particles_moving=(true, true)) +end + +function update_nhs!(neighborhood_search, + system::FluidSystem, neighbor::BoundarySPHSystem, + u_system, u_neighbor) + # Boundary coordinates only change over time when `neighbor.ismoving[]` + PointNeighbors.update!(neighborhood_search, + current_coordinates(u_system, system), + current_coordinates(u_neighbor, neighbor), + particles_moving=(true, neighbor.ismoving[])) +end + +function update_nhs!(neighborhood_search, + system::FluidSystem, neighbor::OpenBoundarySPHSystem, + u_system, u_neighbor) + # The current coordinates of fluids and open boundaries change over time. + + # TODO: Update only `active_coordinates` of open boundaries. + # Problem: Removing inactive particles from neigboring lists is necessary. + PointNeighbors.update!(neighborhood_search, + current_coordinates(u_system, system), + current_coordinates(u_neighbor, neighbor), + particles_moving=(true, true)) +end + +function update_nhs!(neighborhood_search, + system::OpenBoundarySPHSystem, neighbor::FluidSystem, + u_system, u_neighbor) + # The current coordinates of open boundaries and fluids change over time. + + # TODO: Update only `active_coordinates` of open boundaries. + # Problem: Removing inactive particles from neigboring lists is necessary. + PointNeighbors.update!(neighborhood_search, + current_coordinates(u_system, system), + current_coordinates(u_neighbor, neighbor), + particles_moving=(true, true)) +end + +function update_nhs!(neighborhood_search, + system::TotalLagrangianSPHSystem, neighbor::FluidSystem, + u_system, u_neighbor) + # The current coordinates of fluids and solids change over time + PointNeighbors.update!(neighborhood_search, + current_coordinates(u_system, system), + current_coordinates(u_neighbor, neighbor), + particles_moving=(true, true)) +end + +function update_nhs!(neighborhood_search, + system::TotalLagrangianSPHSystem, neighbor::TotalLagrangianSPHSystem, + u_system, u_neighbor) + # Don't update. Neighborhood search works on the initial coordinates, which don't change. + return neighborhood_search +end + +function update_nhs!(neighborhood_search, + system::TotalLagrangianSPHSystem, neighbor::BoundarySPHSystem, + u_system, u_neighbor) + # The current coordinates of solids change over time. + # Boundary coordinates only change over time when `neighbor.ismoving[]`. + PointNeighbors.update!(neighborhood_search, + current_coordinates(u_system, system), + current_coordinates(u_neighbor, neighbor), + particles_moving=(true, neighbor.ismoving[])) +end + +function update_nhs!(neighborhood_search, + system::BoundarySPHSystem, + neighbor::Union{FluidSystem, TotalLagrangianSPHSystem, + BoundarySPHSystem}, + u_system, u_neighbor) + # Don't update. This NHS is never used. + return neighborhood_search +end + +function update_nhs!(neighborhood_search, + system::BoundarySPHSystem{<:BoundaryModelDummyParticles}, + neighbor::Union{FluidSystem, TotalLagrangianSPHSystem}, + u_system, u_neighbor) + # Depending on the density calculator of the boundary model, this NHS is used for + # - kernel summation (`SummationDensity`) + # - continuity equation (`ContinuityDensity`) + # - pressure extrapolation (`AdamiPressureExtrapolation`) + # + # Boundary coordinates only change over time when `neighbor.ismoving[]`. + # The current coordinates of fluids and solids change over time. + PointNeighbors.update!(neighborhood_search, + current_coordinates(u_system, system), + current_coordinates(u_neighbor, neighbor), + particles_moving=(system.ismoving[], true)) +end + +function update_nhs!(neighborhood_search, + system::BoundarySPHSystem{<:BoundaryModelDummyParticles}, + neighbor::BoundarySPHSystem, + u_system, u_neighbor) + # `system` coordinates only change over time when `system.ismoving[]`. + # `neighbor` coordinates only change over time when `neighbor.ismoving[]`. + PointNeighbors.update!(neighborhood_search, + current_coordinates(u_system, system), + current_coordinates(u_neighbor, neighbor), + particles_moving=(system.ismoving[], neighbor.ismoving[])) +end + +function update_nhs!(neighborhood_search, + system::DEMSystem, neighbor::DEMSystem, + u_system, u_neighbor) + # Both coordinates change over time + PointNeighbors.update!(neighborhood_search, + current_coordinates(u_system, system), + current_coordinates(u_neighbor, neighbor), + particles_moving=(true, true)) +end + +function update_nhs!(neighborhood_search, + system::DEMSystem, neighbor::BoundaryDEMSystem, + u_system, u_neighbor) + # DEM coordinates change over time, the boundary coordinates don't + PointNeighbors.update!(neighborhood_search, + current_coordinates(u_system, system), + current_coordinates(u_neighbor, neighbor), + particles_moving=(true, false)) +end + +function update_nhs!(neighborhood_search, + system::BoundaryDEMSystem, + neighbor::Union{DEMSystem, BoundaryDEMSystem}, + u_system, u_neighbor) + # Don't update. This NHS is never used. + return neighborhood_search +end + +function update_nhs!(neighborhood_search, + system::Union{BoundarySPHSystem, OpenBoundarySPHSystem}, + neighbor::Union{BoundarySPHSystem, OpenBoundarySPHSystem}, + u_system, u_neighbor) + # Don't update. This NHS is never used. + return neighborhood_search end function check_configuration(systems) diff --git a/src/neighborhood_search/grid_nhs.jl b/src/neighborhood_search/grid_nhs.jl deleted file mode 100644 index 82526a6b4..000000000 --- a/src/neighborhood_search/grid_nhs.jl +++ /dev/null @@ -1,423 +0,0 @@ -@doc raw""" - GridNeighborhoodSearch{NDIMS}(search_radius, n_particles; periodic_box_min_corner=nothing, - periodic_box_max_corner=nothing, threaded_nhs_update=true) - -Simple grid-based neighborhood search with uniform search radius. -The domain is divided into a regular grid. -For each (non-empty) grid cell, a list of particles in this cell is stored. -Instead of representing a finite domain by an array of cells, a potentially infinite domain -is represented by storing cell lists in a hash table (using Julia's `Dict` data structure), -indexed by the cell index tuple -```math -\left( \left\lfloor \frac{x}{d} \right\rfloor, \left\lfloor \frac{y}{d} \right\rfloor \right) \quad \text{or} \quad -\left( \left\lfloor \frac{x}{d} \right\rfloor, \left\lfloor \frac{y}{d} \right\rfloor, \left\lfloor \frac{z}{d} \right\rfloor \right), -``` -where ``x, y, z`` are the space coordinates and ``d`` is the search radius. - -To find particles within the search radius around a point, only particles in the neighboring -cells are considered. - -See also (Chalela et al., 2021), (Ihmsen et al. 2011, Section 4.4). - -As opposed to (Ihmsen et al. 2011), we do not sort the particles in any way, -since not sorting makes our implementation a lot faster (although less parallelizable). - -# Arguments -- `NDIMS`: Number of dimensions. -- `search_radius`: The uniform search radius. -- `n_particles`: Total number of particles. - -# Keywords -- `periodic_box_min_corner`: In order to use a (rectangular) periodic domain, pass the - coordinates of the domain corner in negative coordinate - directions. -- `periodic_box_max_corner`: In order to use a (rectangular) periodic domain, pass the - coordinates of the domain corner in positive coordinate - directions. -- `threaded_nhs_update=true`: Can be used to deactivate thread parallelization in the neighborhood search update. - This can be one of the largest sources of variations between simulations - with different thread numbers due to particle ordering changes. - -!!! warning "Internal use only" - Please note that this constructor is intended for internal use only. It is *not* part of - the public API of TrixiParticles.jl, and it thus can altered (or be removed) at any time - without it being considered a breaking change. - - To run a simulation with this neighborhood search, just pass the type to the constructor - of [`Semidiscretization`](@ref): - ```jldoctest semi_example; output=false, setup = :(trixi_include(@__MODULE__, joinpath(examples_dir(), "fluid", "hydrostatic_water_column_2d.jl"), sol=nothing); system1 = fluid_system; system2 = boundary_system) - semi = Semidiscretization(system1, system2, - neighborhood_search=GridNeighborhoodSearch) - - # output - ┌──────────────────────────────────────────────────────────────────────────────────────────────────┐ - │ Semidiscretization │ - │ ══════════════════ │ - │ #spatial dimensions: ………………………… 2 │ - │ #systems: ……………………………………………………… 2 │ - │ neighborhood search: ………………………… GridNeighborhoodSearch │ - │ total #particles: ………………………………… 636 │ - └──────────────────────────────────────────────────────────────────────────────────────────────────┘ - ``` - The keyword arguments `periodic_box_min_corner` and `periodic_box_max_corner` explained - above can also be passed to the [`Semidiscretization`](@ref) and will internally be - forwarded to the neighborhood search: - ```jldoctest semi_example; output = false - semi = Semidiscretization(system1, system2, - neighborhood_search=GridNeighborhoodSearch, - periodic_box_min_corner=[0.0, -0.25], - periodic_box_max_corner=[1.0, 0.75]) - - # output - ┌──────────────────────────────────────────────────────────────────────────────────────────────────┐ - │ Semidiscretization │ - │ ══════════════════ │ - │ #spatial dimensions: ………………………… 2 │ - │ #systems: ……………………………………………………… 2 │ - │ neighborhood search: ………………………… GridNeighborhoodSearch │ - │ total #particles: ………………………………… 636 │ - └──────────────────────────────────────────────────────────────────────────────────────────────────┘ - ``` - -## References -- M. Chalela, E. Sillero, L. Pereyra, M.A. Garcia, J.B. Cabral, M. Lares, M. Merchán. - "GriSPy: A Python package for fixed-radius nearest neighbors search". - In: Astronomy and Computing 34 (2021). - [doi: 10.1016/j.ascom.2020.100443](https://doi.org/10.1016/j.ascom.2020.100443) -- Markus Ihmsen, Nadir Akinci, Markus Becker, Matthias Teschner. - "A Parallel SPH Implementation on Multi-Core CPUs". - In: Computer Graphics Forum 30.1 (2011), pages 99–112. - [doi: 10.1111/J.1467-8659.2010.01832.X](https://doi.org/10.1111/J.1467-8659.2010.01832.X) -""" -struct GridNeighborhoodSearch{NDIMS, ELTYPE, PB} - hashtable :: Dict{NTuple{NDIMS, Int}, Vector{Int}} - search_radius :: ELTYPE - empty_vector :: Vector{Int} # Just an empty vector (used in `eachneighbor`) - cell_buffer :: Array{NTuple{NDIMS, Int}, 2} # Multithreaded buffer for `update!` - cell_buffer_indices :: Vector{Int} # Store which entries of `cell_buffer` are initialized - periodic_box :: PB - n_cells :: NTuple{NDIMS, Int} - cell_size :: NTuple{NDIMS, ELTYPE} - threaded_nhs_update :: Bool - - function GridNeighborhoodSearch{NDIMS}(search_radius, n_particles; - periodic_box_min_corner=nothing, - periodic_box_max_corner=nothing, - threaded_nhs_update=true) where {NDIMS} - ELTYPE = typeof(search_radius) - - hashtable = Dict{NTuple{NDIMS, Int}, Vector{Int}}() - empty_vector = Int[] - cell_buffer = Array{NTuple{NDIMS, Int}, 2}(undef, n_particles, Threads.nthreads()) - cell_buffer_indices = zeros(Int, Threads.nthreads()) - - if search_radius < eps() || - (periodic_box_min_corner === nothing && periodic_box_max_corner === nothing) - - # No periodicity - periodic_box = nothing - n_cells = ntuple(_ -> -1, Val(NDIMS)) - cell_size = ntuple(_ -> search_radius, Val(NDIMS)) - elseif periodic_box_min_corner !== nothing && periodic_box_max_corner !== nothing - periodic_box = PeriodicBox(periodic_box_min_corner, periodic_box_max_corner) - - # Round up search radius so that the grid fits exactly into the domain without - # splitting any cells. This might impact performance slightly, since larger - # cells mean that more potential neighbors are considered than necessary. - # Allow small tolerance to avoid inefficient larger cells due to machine - # rounding errors. - n_cells = Tuple(floor.(Int, (periodic_box.size .+ 10eps()) / search_radius)) - cell_size = Tuple(periodic_box.size ./ n_cells) - - if any(i -> i < 3, n_cells) - throw(ArgumentError("the `GridNeighborhoodSearch` needs at least 3 cells " * - "in each dimension when used with periodicity. " * - "Please use no NHS for very small problems.")) - end - else - throw(ArgumentError("`periodic_box_min_corner` and `periodic_box_max_corner` " * - "must either be both `nothing` or both an array or tuple")) - end - - new{NDIMS, ELTYPE, - typeof(periodic_box)}(hashtable, search_radius, empty_vector, - cell_buffer, cell_buffer_indices, - periodic_box, n_cells, cell_size, threaded_nhs_update) - end -end - -@inline Base.ndims(neighborhood_search::GridNeighborhoodSearch{NDIMS}) where {NDIMS} = NDIMS - -@inline function nparticles(neighborhood_search::GridNeighborhoodSearch) - return size(neighborhood_search.cell_buffer, 1) -end - -function initialize!(neighborhood_search::GridNeighborhoodSearch, ::Nothing) - # No particle coordinates function -> don't initialize. - return neighborhood_search -end - -function initialize!(neighborhood_search::GridNeighborhoodSearch{NDIMS}, - x::AbstractArray) where {NDIMS} - initialize!(neighborhood_search, i -> extract_svector(x, Val(NDIMS), i)) -end - -function initialize!(neighborhood_search::GridNeighborhoodSearch, coords_fun) - (; hashtable) = neighborhood_search - - empty!(hashtable) - - # This is needed to prevent lagging on macOS ARM. - # See https://github.com/JuliaSIMD/Polyester.jl/issues/89 - ThreadingUtilities.sleep_all_tasks() - - for particle in 1:nparticles(neighborhood_search) - # Get cell index of the particle's cell - cell = cell_coords(coords_fun(particle), neighborhood_search) - - # Add particle to corresponding cell or create cell if it does not exist - if haskey(hashtable, cell) - append!(hashtable[cell], particle) - else - hashtable[cell] = [particle] - end - end - - return neighborhood_search -end - -function update!(neighborhood_search::GridNeighborhoodSearch, ::Nothing) - # No particle coordinates function -> don't update. - return neighborhood_search -end - -function update!(neighborhood_search::GridNeighborhoodSearch{NDIMS}, - x::AbstractArray) where {NDIMS} - update!(neighborhood_search, i -> extract_svector(x, Val(NDIMS), i)) -end - -# Modify the existing hash table by moving particles into their new cells -function update!(neighborhood_search::GridNeighborhoodSearch, coords_fun) - (; hashtable, cell_buffer, cell_buffer_indices, threaded_nhs_update) = neighborhood_search - - # Reset `cell_buffer` by moving all pointers to the beginning. - cell_buffer_indices .= 0 - - # Find all cells containing particles that now belong to another cell. - # `collect` the keyset to be able to loop over it with `@threaded`. - mark_changed_cell!(neighborhood_search, hashtable, coords_fun, Val(threaded_nhs_update)) - - # This is needed to prevent lagging on macOS ARM. - # See https://github.com/JuliaSIMD/Polyester.jl/issues/89 - ThreadingUtilities.sleep_all_tasks() - - # Iterate over all marked cells and move the particles into their new cells. - for thread in 1:Threads.nthreads() - # Only the entries `1:cell_buffer_indices[thread]` are initialized for `thread`. - for i in 1:cell_buffer_indices[thread] - cell = cell_buffer[i, thread] - particles = hashtable[cell] - - # Find all particles whose coordinates do not match this cell - moved_particle_indices = (i for i in eachindex(particles) - if cell_coords(coords_fun(particles[i]), - neighborhood_search) != cell) - - # Add moved particles to new cell - for i in moved_particle_indices - particle = particles[i] - new_cell_coords = cell_coords(coords_fun(particle), neighborhood_search) - - # Add particle to corresponding cell or create cell if it does not exist - if haskey(hashtable, new_cell_coords) - append!(hashtable[new_cell_coords], particle) - else - hashtable[new_cell_coords] = [particle] - end - end - - # Remove moved particles from this cell or delete the cell if it is now empty - if count(_ -> true, moved_particle_indices) == length(particles) - delete!(hashtable, cell) - else - deleteat!(particles, moved_particle_indices) - end - end - end - - return neighborhood_search -end - -@inline function mark_changed_cell!(neighborhood_search, hashtable, coords_fun, - threaded_nhs_update::Val{true}) - @threaded for cell in collect(keys(hashtable)) - mark_changed_cell!(neighborhood_search, cell, coords_fun) - end -end - -@inline function mark_changed_cell!(neighborhood_search, hashtable, coords_fun, - threaded_nhs_update::Val{false}) - for cell in collect(keys(hashtable)) - mark_changed_cell!(neighborhood_search, cell, coords_fun) - end -end - -# Use this function barrier and unpack inside to avoid passing closures to Polyester.jl -# with `@batch` (`@threaded`). -# Otherwise, `@threaded` does not work here with Julia ARM on macOS. -# See https://github.com/JuliaSIMD/Polyester.jl/issues/88. -@inline function mark_changed_cell!(neighborhood_search, cell, coords_fun) - (; hashtable, cell_buffer, cell_buffer_indices) = neighborhood_search - - for particle in hashtable[cell] - if cell_coords(coords_fun(particle), neighborhood_search) != cell - # Mark this cell and continue with the next one. - # - # `cell_buffer` is preallocated, - # but only the entries 1:i are used for this thread. - i = cell_buffer_indices[Threads.threadid()] += 1 - cell_buffer[i, Threads.threadid()] = cell - break - end - end -end - -# 1D -@inline function eachneighbor(coords, neighborhood_search::GridNeighborhoodSearch{1}) - cell = cell_coords(coords, neighborhood_search) - x = cell[1] - # Generator of all neighboring cells to consider - neighboring_cells = ((x + i) for i in -1:1) - - # Merge all lists of particles in the neighboring cells into one iterator - Iterators.flatten(particles_in_cell(cell, neighborhood_search) - for cell in neighboring_cells) -end - -# 2D -@inline function eachneighbor(coords, neighborhood_search::GridNeighborhoodSearch{2}) - cell = cell_coords(coords, neighborhood_search) - x, y = cell - # Generator of all neighboring cells to consider - neighboring_cells = ((x + i, y + j) for i in -1:1, j in -1:1) - - # Merge all lists of particles in the neighboring cells into one iterator - Iterators.flatten(particles_in_cell(cell, neighborhood_search) - for cell in neighboring_cells) -end - -# 3D -@inline function eachneighbor(coords, neighborhood_search::GridNeighborhoodSearch{3}) - cell = cell_coords(coords, neighborhood_search) - x, y, z = cell - # Generator of all neighboring cells to consider - neighboring_cells = ((x + i, y + j, z + k) for i in -1:1, j in -1:1, k in -1:1) - - # Merge all lists of particles in the neighboring cells into one iterator - Iterators.flatten(particles_in_cell(cell, neighborhood_search) - for cell in neighboring_cells) -end - -@inline function particles_in_cell(cell_index, neighborhood_search) - (; hashtable, empty_vector) = neighborhood_search - - # Return an empty vector when `cell_index` is not a key of `hashtable` and - # reuse the empty vector to avoid allocations - return get(hashtable, periodic_cell_index(cell_index, neighborhood_search), - empty_vector) -end - -@inline function periodic_cell_index(cell_index, neighborhood_search) - (; n_cells, periodic_box) = neighborhood_search - - periodic_cell_index(cell_index, periodic_box, n_cells) -end - -@inline periodic_cell_index(cell_index, ::Nothing, n_cells) = cell_index - -@inline function periodic_cell_index(cell_index, periodic_box, n_cells) - return rem.(cell_index, n_cells, RoundDown) -end - -@inline function cell_coords(coords, neighborhood_search) - (; periodic_box, cell_size) = neighborhood_search - - return cell_coords(coords, periodic_box, cell_size) -end - -@inline function cell_coords(coords, periodic_box::Nothing, cell_size) - return Tuple(floor_to_int.(coords ./ cell_size)) -end - -@inline function cell_coords(coords, periodic_box, cell_size) - # Subtract `min_corner` to offset coordinates so that the min corner of the periodic - # box corresponds to the (0, 0) cell of the NHS. - # This way, there are no partial cells in the domain if the domain size is an integer - # multiple of the cell size (which is required, see the constructor). - offset_coords = periodic_coords(coords, periodic_box) .- periodic_box.min_corner - - return Tuple(floor_to_int.(offset_coords ./ cell_size)) -end - -# When particles end up with coordinates so big that the cell coordinates -# exceed the range of Int, then `floor(Int, i)` will fail with an InexactError. -# In this case, we can just use typemax(Int), since we can assume that particles -# that far away will not interact with anything, anyway. -# This usually indicates an instability, but we don't want the simulation to crash, -# since adaptive time integration methods may detect the instability and reject the -# time step. -# If we threw an error here, we would prevent the time integration method from -# retrying with a smaller time step, and we would thus crash perfectly fine simulations. -@inline function floor_to_int(i) - if isnan(i) || i > typemax(Int) - return typemax(Int) - elseif i < typemin(Int) - return typemin(Int) - end - - return floor(Int, i) -end - -# Sorting only really makes sense in longer simulations where particles -# end up very unordered. -# WARNING: This is currently unmaintained. -function z_index_sort!(coordinates, system) - (; mass, pressure, neighborhood_search) = system - - perm = sortperm(eachparticle(system), - by=(i -> cell_z_index(extract_svector(coordinates, system, i), - neighborhood_search))) - - permute!(mass, perm) - permute!(pressure, perm) - Base.permutecols!!(u, perm) - - return nothing -end - -@inline function cell_z_index(coords, neighborhood_search) - cell = cell_coords(coords, neighborhood_search.search_radius) .+ 1 - - return cartesian2morton(SVector(cell)) -end - -# Create a copy of a neighborhood search but with a different search radius -function copy_neighborhood_search(nhs::GridNeighborhoodSearch, search_radius, u) - if nhs.periodic_box === nothing - search = GridNeighborhoodSearch{ndims(nhs)}(search_radius, nparticles(nhs)) - else - search = GridNeighborhoodSearch{ndims(nhs)}(search_radius, nparticles(nhs), - periodic_box_min_corner=nhs.periodic_box.min_corner, - periodic_box_max_corner=nhs.periodic_box.max_corner) - end - - # Initialize neighborhood search - initialize!(search, u) - - return search -end - -# Create a copy of a neighborhood search but with a different search radius -function copy_neighborhood_search(nhs::TrivialNeighborhoodSearch, search_radius, u) - return nhs -end diff --git a/src/neighborhood_search/neighborhood_search.jl b/src/neighborhood_search/neighborhood_search.jl deleted file mode 100644 index e9062c5db..000000000 --- a/src/neighborhood_search/neighborhood_search.jl +++ /dev/null @@ -1,110 +0,0 @@ -struct PeriodicBox{NDIMS, ELTYPE} - min_corner :: SVector{NDIMS, ELTYPE} - max_corner :: SVector{NDIMS, ELTYPE} - size :: SVector{NDIMS, ELTYPE} - - function PeriodicBox(min_corner, max_corner) - new{length(min_corner), eltype(min_corner)}(min_corner, max_corner, - max_corner - min_corner) - end -end - -# Loop over all pairs of particles and neighbors within the kernel cutoff. -# `f(particle, neighbor, pos_diff, distance)` is called for every particle-neighbor pair. -# By default, loop over `each_moving_particle(system)`. -@inline function for_particle_neighbor(f, system, neighbor_system, - system_coords, neighbor_coords, neighborhood_search; - particles=each_moving_particle(system), - parallel=true) - for_particle_neighbor(f, system_coords, neighbor_coords, neighborhood_search, - particles=particles, parallel=parallel) -end - -@inline function for_particle_neighbor(f, system_coords, neighbor_coords, - neighborhood_search; - particles=axes(system_coords, 2), parallel=true) - for_particle_neighbor(f, system_coords, neighbor_coords, neighborhood_search, particles, - Val(parallel)) -end - -@inline function for_particle_neighbor(f, system_coords, neighbor_coords, - neighborhood_search, particles, parallel::Val{true}) - @threaded for particle in particles - for_particle_neighbor_inner(f, system_coords, neighbor_coords, neighborhood_search, - particle) - end - - return nothing -end - -@inline function for_particle_neighbor(f, system_coords, neighbor_coords, - neighborhood_search, particles, parallel::Val{false}) - for particle in particles - for_particle_neighbor_inner(f, system_coords, neighbor_coords, neighborhood_search, - particle) - end - - return nothing -end - -# Use this function barrier and unpack inside to avoid passing closures to Polyester.jl -# with `@batch` (`@threaded`). -# Otherwise, `@threaded` does not work here with Julia ARM on macOS. -# See https://github.com/JuliaSIMD/Polyester.jl/issues/88. -@inline function for_particle_neighbor_inner(f, system_coords, neighbor_system_coords, - neighborhood_search, particle) - (; search_radius, periodic_box) = neighborhood_search - - particle_coords = extract_svector(system_coords, Val(ndims(neighborhood_search)), - particle) - for neighbor in eachneighbor(particle_coords, neighborhood_search) - neighbor_coords = extract_svector(neighbor_system_coords, - Val(ndims(neighborhood_search)), neighbor) - - pos_diff = particle_coords - neighbor_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 - distance = sqrt(distance2) - - # Inline to avoid loss of performance - # compared to not using `for_particle_neighbor`. - @inline f(particle, neighbor, pos_diff, distance) - end - end -end - -@inline function compute_periodic_distance(pos_diff, distance2, search_radius, - periodic_box::Nothing) - return pos_diff, distance2 -end - -@inline function compute_periodic_distance(pos_diff, distance2, search_radius, - periodic_box) - if distance2 > search_radius^2 - # Use periodic `pos_diff` - pos_diff -= periodic_box.size .* round.(pos_diff ./ periodic_box.size) - distance2 = dot(pos_diff, pos_diff) - end - - return pos_diff, distance2 -end - -@inline function periodic_coords(coords, periodic_box) - (; min_corner, size) = periodic_box - - # Move coordinates into the periodic box - box_offset = floor.((coords .- min_corner) ./ size) - - return coords - box_offset .* size -end - -@inline function periodic_coords(coords, periodic_box::Nothing) - return coords -end - -include("trivial_nhs.jl") -include("grid_nhs.jl") diff --git a/src/neighborhood_search/trivial_nhs.jl b/src/neighborhood_search/trivial_nhs.jl deleted file mode 100644 index 3902f1d3f..000000000 --- a/src/neighborhood_search/trivial_nhs.jl +++ /dev/null @@ -1,97 +0,0 @@ -@doc raw""" - TrivialNeighborhoodSearch{NDIMS}(search_radius, eachparticle) - -Trivial neighborhood search that simply loops over all particles. -The search radius still needs to be passed in order to sort out particles outside the -search radius in the internal function `for_particle_neighbor`, but it's not used in the -internal function `eachneighbor`. - -# Arguments -- `NDIMS`: Number of dimensions. -- `search_radius`: The uniform search radius. -- `eachparticle`: `UnitRange` of all particle indices. Usually just `1:n_particles`. - -# Keywords -- `periodic_box_min_corner`: In order to use a (rectangular) periodic domain, pass the - coordinates of the domain corner in negative coordinate - directions. -- `periodic_box_max_corner`: In order to use a (rectangular) periodic domain, pass the - coordinates of the domain corner in positive coordinate - directions. - -!!! warning "Internal use only" - Please note that this constructor is intended for internal use only. It is *not* part of - the public API of TrixiParticles.jl, and it thus can altered (or be removed) at any time - without it being considered a breaking change. - - To run a simulation with this neighborhood search, just pass the type to the constructor - of [`Semidiscretization`](@ref): - ```jldoctest semi_example; output=false, setup = :(trixi_include(@__MODULE__, joinpath(examples_dir(), "fluid", "hydrostatic_water_column_2d.jl"), sol=nothing); system1 = fluid_system; system2 = boundary_system) - semi = Semidiscretization(system1, system2, - neighborhood_search=TrivialNeighborhoodSearch) - - # output - ┌──────────────────────────────────────────────────────────────────────────────────────────────────┐ - │ Semidiscretization │ - │ ══════════════════ │ - │ #spatial dimensions: ………………………… 2 │ - │ #systems: ……………………………………………………… 2 │ - │ neighborhood search: ………………………… TrivialNeighborhoodSearch │ - │ total #particles: ………………………………… 636 │ - └──────────────────────────────────────────────────────────────────────────────────────────────────┘ - ``` - The keyword arguments `periodic_box_min_corner` and `periodic_box_max_corner` explained - above can also be passed to the [`Semidiscretization`](@ref) and will internally be - forwarded to the neighborhood search: - ```jldoctest semi_example; output = false - semi = Semidiscretization(system1, system2, - neighborhood_search=TrivialNeighborhoodSearch, - periodic_box_min_corner=[0.0, -0.25], - periodic_box_max_corner=[1.0, 0.75]) - - # output - ┌──────────────────────────────────────────────────────────────────────────────────────────────────┐ - │ Semidiscretization │ - │ ══════════════════ │ - │ #spatial dimensions: ………………………… 2 │ - │ #systems: ……………………………………………………… 2 │ - │ neighborhood search: ………………………… TrivialNeighborhoodSearch │ - │ total #particles: ………………………………… 636 │ - └──────────────────────────────────────────────────────────────────────────────────────────────────┘ - ``` -""" -struct TrivialNeighborhoodSearch{NDIMS, ELTYPE, EP, PB} - search_radius :: ELTYPE - eachparticle :: EP - periodic_box :: PB - - function TrivialNeighborhoodSearch{NDIMS}(search_radius, eachparticle; - periodic_box_min_corner=nothing, - periodic_box_max_corner=nothing) where {NDIMS} - if search_radius < eps() || - (periodic_box_min_corner === nothing && periodic_box_max_corner === nothing) - - # No periodicity - periodic_box = nothing - elseif periodic_box_min_corner !== nothing && periodic_box_max_corner !== nothing - periodic_box = PeriodicBox(periodic_box_min_corner, periodic_box_max_corner) - else - throw(ArgumentError("`periodic_box_min_corner` and `periodic_box_max_corner` " * - "must either be both `nothing` or both an array or tuple")) - end - - new{NDIMS, typeof(search_radius), - typeof(eachparticle), typeof(periodic_box)}(search_radius, eachparticle, - periodic_box) - end -end - -@inline function Base.ndims(neighborhood_search::TrivialNeighborhoodSearch{NDIMS}) where { - NDIMS - } - return NDIMS -end - -@inline initialize!(search::TrivialNeighborhoodSearch, coords_fun) = search -@inline update!(search::TrivialNeighborhoodSearch, coords_fun) = search -@inline eachneighbor(coords, search::TrivialNeighborhoodSearch) = search.eachparticle diff --git a/src/schemes/boundary/open_boundary/system.jl b/src/schemes/boundary/open_boundary/system.jl index bbdd6b606..8a0d3d100 100644 --- a/src/schemes/boundary/open_boundary/system.jl +++ b/src/schemes/boundary/open_boundary/system.jl @@ -507,7 +507,7 @@ function check_fluid_domain!(system, fluid_system::FluidSystem, particle, end # Check fluid neighbors - for neighbor in eachneighbor(particle_coords, neighborhood_search) + for neighbor in PointNeighbors.eachneighbor(particle_coords, neighborhood_search) fluid_coords = current_coords(u_fluid, fluid_system, neighbor) # Check if neighbor position is in boundary zone diff --git a/src/visualization/write2vtk.jl b/src/visualization/write2vtk.jl index 6620c5119..e381a27d8 100644 --- a/src/visualization/write2vtk.jl +++ b/src/visualization/write2vtk.jl @@ -85,7 +85,8 @@ function trixi2vtk(v, u, t, system, periodic_box; output_directory="out", prefix # Reset the collection when the iteration is 0 pvd = paraview_collection(collection_file; append=iter > 0) - points = periodic_coords(active_coordinates(u, system), periodic_box) + points = PointNeighbors.periodic_coords(active_coordinates(u, system), + periodic_box) cells = [MeshCell(VTKCellTypes.VTK_VERTEX, (i,)) for i in axes(points, 2)] if abs(maximum(points)) > max_coordinates || abs(minimum(points)) > max_coordinates diff --git a/test/Project.toml b/test/Project.toml index a591c7415..ef78271e3 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -16,7 +16,7 @@ Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" [compat] CSV = "0.10" -CairoMakie = "0.11" +CairoMakie = "0.12" DataFrames = "1.6" GLM = "1.9" Glob = "1.3" diff --git a/test/count_allocations.jl b/test/count_allocations.jl index 6a87e9868..3b5110ba1 100644 --- a/test/count_allocations.jl +++ b/test/count_allocations.jl @@ -27,7 +27,11 @@ end end # No update -@inline TrixiParticles.update!(search::NoUpdateNeighborhoodSearch, coords_fun) = search +@inline function TrixiParticles.PointNeighbors.update!(search::NoUpdateNeighborhoodSearch, + x, y; + particles_moving=(true, true)) + return search +end # Count allocations of one call to the right-hand side (`kick!` + `drift!`) function count_rhs_allocations(sol, semi) diff --git a/test/neighborhood_search/grid_nhs.jl b/test/neighborhood_search/grid_nhs.jl deleted file mode 100644 index d686efc5b..000000000 --- a/test/neighborhood_search/grid_nhs.jl +++ /dev/null @@ -1,272 +0,0 @@ -@testset verbose=true "GridNeighborhoodSearch" begin - @testset "Coordinate Limits" begin - # Test the threshold for very large and very small coordinates. - coords1 = [Inf, -Inf] - coords2 = [NaN, 0] - coords3 = [typemax(Int) + 1.0, -typemax(Int) - 1.0] - - @test TrixiParticles.cell_coords(coords1, nothing, (1.0, 1.0)) == - (typemax(Int), typemin(Int)) - @test TrixiParticles.cell_coords(coords2, nothing, (1.0, 1.0)) == (typemax(Int), 0) - @test TrixiParticles.cell_coords(coords3, nothing, (1.0, 1.0)) == - (typemax(Int), typemin(Int)) - end - - @testset "Rectangular Point Cloud 2D" begin - #### Setup - # Rectangular filled with equidistant spaced particles - # from (x, y) = (-0.25, -0.25) to (x, y) = (0.35, 0.35) - range = -0.25:0.1:0.35 - coordinates1 = hcat(collect.(Iterators.product(range, range))...) - nparticles = size(coordinates1, 2) - - particle_position1 = [0.05, 0.05] - particle_spacing = 0.1 - radius = particle_spacing - - # Create neighborhood search - nhs1 = GridNeighborhoodSearch{2}(radius, nparticles) - - coords_fun(i) = coordinates1[:, i] - TrixiParticles.initialize!(nhs1, coords_fun) - - # Get each neighbor for `particle_position1` - neighbors1 = sort(collect(TrixiParticles.eachneighbor(particle_position1, nhs1))) - - # Move particles - coordinates2 = coordinates1 .+ [1.4, -3.5] - - # Update neighborhood search - coords_fun2(i) = coordinates2[:, i] - TrixiParticles.update!(nhs1, coords_fun2) - - # Get each neighbor for updated NHS - neighbors2 = sort(collect(TrixiParticles.eachneighbor(particle_position1, nhs1))) - - # Change position - particle_position2 = particle_position1 .+ [1.4, -3.5] - - # Get each neighbor for `particle_position2` - neighbors3 = sort(collect(TrixiParticles.eachneighbor(particle_position2, nhs1))) - - # Double search radius - nhs2 = GridNeighborhoodSearch{2}(2 * radius, size(coordinates1, 2)) - TrixiParticles.initialize!(nhs2, coords_fun) - - # Get each neighbor in double search radius - neighbors4 = sort(collect(TrixiParticles.eachneighbor(particle_position1, nhs2))) - - # Move particles - coordinates2 = coordinates1 .+ [0.4, -0.4] - - # Update neighborhood search - TrixiParticles.update!(nhs2, coords_fun2) - - # Get each neighbor in double search radius - neighbors5 = sort(collect(TrixiParticles.eachneighbor(particle_position1, nhs2))) - - #### Verification - @test neighbors1 == [17, 18, 19, 24, 25, 26, 31, 32, 33] - - @test neighbors2 == Int[] - - @test neighbors3 == [17, 18, 19, 24, 25, 26, 31, 32, 33] - - @test neighbors4 == [9, 10, 11, 12, 13, 14, 16, 17, 18, 19, 20, 21, 23, 24, 25, - 26, 27, 28, 30, 31, 32, 33, 34, 35, 37, 38, 39, 40, 41, 42, 44, 45, 46, 47, - 48, 49] - - @test neighbors5 == [36, 37, 38, 43, 44, 45] - end - - @testset "Rectangular Point Cloud 3D" begin - #### Setup - # Rectangular filled with equidistant spaced particles - # from (x, y, z) = (-0.25, -0.25, -0.25) to (x, y) = (0.35, 0.35, 0.35) - range = -0.25:0.1:0.35 - coordinates1 = hcat(collect.(Iterators.product(range, range, range))...) - nparticles = size(coordinates1, 2) - - particle_position1 = [0.05, 0.05, 0.05] - particle_spacing = 0.1 - radius = particle_spacing - - # Create neighborhood search - nhs1 = GridNeighborhoodSearch{3}(radius, nparticles) - - coords_fun(i) = coordinates1[:, i] - TrixiParticles.initialize!(nhs1, coords_fun) - - # Get each neighbor for `particle_position1` - neighbors1 = sort(collect(TrixiParticles.eachneighbor(particle_position1, nhs1))) - - # Move particles - coordinates2 = coordinates1 .+ [1.4, -3.5, 0.8] - - # Update neighborhood search - coords_fun2(i) = coordinates2[:, i] - TrixiParticles.update!(nhs1, coords_fun2) - - # Get each neighbor for updated NHS - neighbors2 = sort(collect(TrixiParticles.eachneighbor(particle_position1, nhs1))) - - # Change position - particle_position2 = particle_position1 .+ [1.4, -3.5, 0.8] - - # Get each neighbor for `particle_position2` - neighbors3 = sort(collect(TrixiParticles.eachneighbor(particle_position2, nhs1))) - - #### Verification - @test neighbors1 == - [115, 116, 117, 122, 123, 124, 129, 130, 131, 164, 165, 166, 171, 172, - 173, 178, 179, 180, 213, 214, 215, 220, 221, 222, 227, 228, 229] - - @test neighbors2 == Int[] - - @test neighbors3 == - [115, 116, 117, 122, 123, 124, 129, 130, 131, 164, 165, 166, 171, 172, - 173, 178, 179, 180, 213, 214, 215, 220, 221, 222, 227, 228, 229] - end - - @testset verbose=true "Periodicity 2D" begin - @testset "Simple Example" begin - coords = [-0.08 0.0 0.18 0.1 -0.08 - -0.12 -0.05 -0.09 0.15 0.39] - - # 3 x 6 cells - nhs = GridNeighborhoodSearch{2}(0.1, size(coords, 2), - periodic_box_min_corner=[-0.1, -0.2], - periodic_box_max_corner=[0.2, 0.4]) - - TrixiParticles.initialize!(nhs, coords) - - neighbors = [sort(collect(TrixiParticles.eachneighbor(coords[:, i], nhs))) - for i in 1:5] - - # Note that (1, 2) and (2, 3) are not neighbors, but they are in neighboring cells - @test neighbors[1] == [1, 2, 3, 5] - @test neighbors[2] == [1, 2, 3] - @test neighbors[3] == [1, 2, 3] - @test neighbors[4] == [4] - @test neighbors[5] == [1, 5] - - neighbors_loop = [Int[] for _ in axes(coords, 2)] - - TrixiParticles.for_particle_neighbor(nothing, nothing, - coords, coords, nhs, - particles=axes(coords, 2)) do particle, - neighbor, - pos_diff, - distance - append!(neighbors_loop[particle], neighbor) - end - - @test sort(neighbors_loop[1]) == [1, 3, 5] - @test sort(neighbors_loop[2]) == [2] - @test sort(neighbors_loop[3]) == [1, 3] - @test sort(neighbors_loop[4]) == [4] - @test sort(neighbors_loop[5]) == [1, 5] - end - - @testset "Rounding Up Cell Sizes" begin - coords = [-0.08 0.0 0.18 0.1 -0.08 - -0.12 -0.05 -0.09 0.15 0.42] - - # 3 x 6 cells - nhs = GridNeighborhoodSearch{2}(0.1, size(coords, 2), - periodic_box_min_corner=[-0.1, -0.2], - periodic_box_max_corner=[0.205, 0.43]) - - TrixiParticles.initialize!(nhs, coords) - - neighbors = [sort(collect(TrixiParticles.eachneighbor(coords[:, i], nhs))) - for i in 1:5] - - # Note that (1, 2) and (2, 3) are not neighbors, but they are in neighboring cells - @test neighbors[1] == [1, 2, 3, 5] - @test neighbors[2] == [1, 2, 3] - @test neighbors[3] == [1, 2, 3] - @test neighbors[4] == [4] - @test neighbors[5] == [1, 5] - - neighbors_loop = [Int[] for _ in axes(coords, 2)] - - TrixiParticles.for_particle_neighbor(nothing, nothing, - coords, coords, nhs, - particles=axes(coords, 2)) do particle, - neighbor, - pos_diff, - distance - append!(neighbors_loop[particle], neighbor) - end - - @test sort(neighbors_loop[1]) == [1, 3, 5] - @test sort(neighbors_loop[2]) == [2] - @test sort(neighbors_loop[3]) == [1, 3] - @test sort(neighbors_loop[4]) == [4] - @test sort(neighbors_loop[5]) == [1, 5] - end - - @testset "Offset Domain Triggering Split Cells" begin - # This used to trigger a "split cell bug", where the left and right boundary - # cells were only partially contained in the domain. - # The left particle was placed inside a ghost cells, which causes it to not - # see the right particle, even though it is within the search distance. - # The domain size is an integer multiple of the cell size, but the NHS did not - # offset the grid based on the domain position. - # See https://github.com/trixi-framework/TrixiParticles.jl/pull/211 for a more - # detailed explanation. - coords = [-1.4 1.9 - 0.0 0.0] - - # 5 x 1 cells - nhs = GridNeighborhoodSearch{2}(1.0, size(coords, 2), - periodic_box_min_corner=[-1.5, 0.0], - periodic_box_max_corner=[2.5, 3.0]) - - TrixiParticles.initialize!(nhs, coords) - - neighbors = [sort(unique(collect(TrixiParticles.eachneighbor(coords[:, i], nhs)))) - for i in 1:2] - - @test neighbors[1] == [1, 2] - @test neighbors[2] == [1, 2] - end - end - - @testset verbose=true "Periodicity 3D" begin - coords = [-0.08 0.0 0.18 0.1 -0.08 - -0.12 -0.05 -0.09 0.15 0.39 - 0.14 0.34 0.12 0.06 0.13] - - # 3 x 6 x 3 cells - nhs = GridNeighborhoodSearch{3}(0.1, size(coords, 2), - periodic_box_min_corner=[-0.1, -0.2, 0.05], - periodic_box_max_corner=[0.2, 0.4, 0.35]) - - TrixiParticles.initialize!(nhs, coords) - - neighbors = [sort(collect(TrixiParticles.eachneighbor(coords[:, i], nhs))) - for i in 1:5] - - # Note that (1, 2) and (2, 3) are not neighbors, but they are in neighboring cells - @test neighbors[1] == [1, 2, 3, 5] - @test neighbors[2] == [1, 2, 3] - @test neighbors[3] == [1, 2, 3] - @test neighbors[4] == [4] - @test neighbors[5] == [1, 5] - - neighbors_loop = [Int[] for _ in axes(coords, 2)] - - TrixiParticles.for_particle_neighbor(coords, coords, - nhs) do particle, neighbor, pos_diff, distance - append!(neighbors_loop[particle], neighbor) - end - - @test sort(neighbors_loop[1]) == [1, 3, 5] - @test sort(neighbors_loop[2]) == [2] - @test sort(neighbors_loop[3]) == [1, 3] - @test sort(neighbors_loop[4]) == [4] - @test sort(neighbors_loop[5]) == [1, 5] - end -end diff --git a/test/neighborhood_search/neighborhood_search.jl b/test/neighborhood_search/neighborhood_search.jl deleted file mode 100644 index 0c7270a7e..000000000 --- a/test/neighborhood_search/neighborhood_search.jl +++ /dev/null @@ -1,2 +0,0 @@ -include("trivial_nhs.jl") -include("grid_nhs.jl") diff --git a/test/neighborhood_search/trivial_nhs.jl b/test/neighborhood_search/trivial_nhs.jl deleted file mode 100644 index aa0b21846..000000000 --- a/test/neighborhood_search/trivial_nhs.jl +++ /dev/null @@ -1,10 +0,0 @@ -@testset verbose=true "TrivialNeighborhoodSearch" begin - # Setup with 5 particles - nhs = TrixiParticles.TrivialNeighborhoodSearch{2}(1.0, Base.OneTo(5)) - - # Get each neighbor for arbitrary coordinates - neighbors = collect(TrixiParticles.eachneighbor([1.0, 2.0], nhs)) - - #### Verification - @test neighbors == [1, 2, 3, 4, 5] -end diff --git a/test/schemes/solid/total_lagrangian_sph/rhs.jl b/test/schemes/solid/total_lagrangian_sph/rhs.jl index 6a4f6bce3..dfc9fc234 100644 --- a/test/schemes/solid/total_lagrangian_sph/rhs.jl +++ b/test/schemes/solid/total_lagrangian_sph/rhs.jl @@ -85,7 +85,7 @@ each_moving_particle end TrixiParticles.eachparticle(::Val{:mock_system_interact}) = eachparticle - TrixiParticles.eachneighbor(_, ::Val{:nhs}) = eachneighbor + TrixiParticles.PointNeighbors.eachneighbor(_, ::Val{:nhs}) = eachneighbor function Base.getproperty(::Val{:nhs}, f::Symbol) if f === :search_radius diff --git a/test/systems/solid_system.jl b/test/systems/solid_system.jl index 812493fa8..369022273 100644 --- a/test/systems/solid_system.jl +++ b/test/systems/solid_system.jl @@ -153,7 +153,7 @@ return Val(Symbol("mock_" * string(f))) end - TrixiParticles.eachneighbor(_, ::Val{:nhs}) = neighbors + TrixiParticles.PointNeighbors.eachneighbor(_, ::Val{:nhs}) = neighbors function Base.getproperty(::Val{:nhs}, f::Symbol) if f === :search_radius diff --git a/test/unittest.jl b/test/unittest.jl index 01308bd44..5c05924e1 100644 --- a/test/unittest.jl +++ b/test/unittest.jl @@ -3,7 +3,6 @@ @testset verbose=true "Unit Tests" begin include("callbacks/callbacks.jl") include("general/general.jl") - include("neighborhood_search/neighborhood_search.jl") include("setups/setups.jl") include("systems/systems.jl") include("schemes/schemes.jl") From 27e71abb4e205829c5f9cac548ef2da670fde897 Mon Sep 17 00:00:00 2001 From: LasNikas Date: Tue, 21 May 2024 16:19:50 +0200 Subject: [PATCH 057/107] undo combining compact support with DEM --- src/general/semidiscretization.jl | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/general/semidiscretization.jl b/src/general/semidiscretization.jl index 1ae3a6a2e..38259148a 100644 --- a/src/general/semidiscretization.jl +++ b/src/general/semidiscretization.jl @@ -156,8 +156,13 @@ end return compact_support(neighbor, system) end -@inline function compact_support(system::Union{BoundaryDEMSystem, OpenBoundarySPHSystem}, - neighbor::Union{BoundaryDEMSystem, OpenBoundarySPHSystem}) +@inline function compact_support(system::OpenBoundarySPHSystem, + neighbor::OpenBoundarySPHSystem) + # This NHS is never used + return 0.0 +end + +@inline function compact_support(system::BoundaryDEMSystem, neighbor::BoundaryDEMSystem) # This NHS is never used return 0.0 end From 0203a3a21a3700a4646a327c1d7eb137fa9bb43f Mon Sep 17 00:00:00 2001 From: LasNikas Date: Tue, 21 May 2024 16:20:45 +0200 Subject: [PATCH 058/107] remove density and pressure setter --- src/general/density_calculators.jl | 10 -------- src/general/system.jl | 4 --- src/schemes/boundary/open_boundary/system.jl | 25 ++++++------------- .../fluid/entropically_damped_sph/system.jl | 5 ---- src/schemes/fluid/fluid.jl | 5 ---- 5 files changed, 7 insertions(+), 42 deletions(-) diff --git a/src/general/density_calculators.jl b/src/general/density_calculators.jl index d35d0ae0f..ee89c92a6 100644 --- a/src/general/density_calculators.jl +++ b/src/general/density_calculators.jl @@ -35,16 +35,6 @@ end return v[end, particle] end -# *Note* that these functions are intended to internally set the density for buffer particles -# and density correction. It cannot be used to set up an initial condition, -# as the particle density depends on the particle positions. - -@inline set_particle_density(particle, v, ::SummationDensity, system, density) = system - -@inline function set_particle_density(particle, v, ::ContinuityDensity, system, density) - v[end, particle] = density -end - function summation_density!(system, semi, u, u_ode, density; particles=each_moving_particle(system)) set_zero!(density) diff --git a/src/general/system.jl b/src/general/system.jl index cff6cff32..bcca6949a 100644 --- a/src/general/system.jl +++ b/src/general/system.jl @@ -73,10 +73,6 @@ end return SVector(ntuple(_ -> 0.0, Val(ndims(system)))) end -@inline set_particle_density(particle, v, system, density) = system - -@inline set_particle_pressure(particle, v, system, pressure) = system - @inline function smoothing_kernel(system, distance) (; smoothing_kernel, smoothing_length) = system return kernel(smoothing_kernel, distance, smoothing_length) diff --git a/src/schemes/boundary/open_boundary/system.jl b/src/schemes/boundary/open_boundary/system.jl index 8a0d3d100..3ecb9cded 100644 --- a/src/schemes/boundary/open_boundary/system.jl +++ b/src/schemes/boundary/open_boundary/system.jl @@ -534,7 +534,7 @@ end (; spanning_set) = system # Activate a new particle in simulation domain - activate_particle!(fluid_system, system, particle, v_fluid, u_fluid, v, u) + activate_particle!(fluid_system, particle, v_fluid, u_fluid, v, u) # Reset position of boundary particle for dim in 1:ndims(system) @@ -548,7 +548,7 @@ end @inline function transform_particle!(fluid_system::FluidSystem, system, boundary_zone, particle, v, u, v_fluid, u_fluid) # Activate particle in boundary zone - activate_particle!(system, fluid_system, particle, v, u, v_fluid, u_fluid) + activate_particle!(system, particle, v, u, v_fluid, u_fluid) # Deactivate particle in interior domain deactivate_particle!(fluid_system, particle, u_fluid) @@ -556,26 +556,15 @@ end return fluid_system end -@inline function activate_particle!(system_new, system_old, particle_old, - v_new, u_new, v_old, u_old) +@inline function activate_particle!(system_new, particle_old, v_new, u_new, v_old, u_old) particle_new = available_particle(system_new) - # Exchange densities - density = particle_density(v_old, system_old, particle_old) - set_particle_density(particle_new, v_new, system_new, density) - - # Exchange pressure - pressure = particle_pressure(v_old, system_old, particle_old) - set_particle_pressure(particle_new, v_new, system_new, pressure) - - # Exchange position and velocity - for dim in 1:ndims(system_new) - u_new[dim, particle_new] = u_old[dim, particle_old] - v_new[dim, particle_new] = v_old[dim, particle_old] + # Exchange integrated quantities + for i in axes(u_new, 1) + u_new[i, particle_new] = u_old[i, particle_old] + v_new[i, particle_new] = v_old[i, particle_old] end - # TODO: Only when using TVF: set tvf - return system_new end diff --git a/src/schemes/fluid/entropically_damped_sph/system.jl b/src/schemes/fluid/entropically_damped_sph/system.jl index 1f8036be1..3b9a61ee7 100644 --- a/src/schemes/fluid/entropically_damped_sph/system.jl +++ b/src/schemes/fluid/entropically_damped_sph/system.jl @@ -156,11 +156,6 @@ end return v[end, particle] end -@inline function set_particle_pressure(particle, v, system::EntropicallyDampedSPHSystem, - pressure) - return v[end, particle] = pressure -end - @inline system_sound_speed(system::EntropicallyDampedSPHSystem) = system.sound_speed function update_quantities!(system::EntropicallyDampedSPHSystem, v, u, diff --git a/src/schemes/fluid/fluid.jl b/src/schemes/fluid/fluid.jl index 42727e391..e2f08444d 100644 --- a/src/schemes/fluid/fluid.jl +++ b/src/schemes/fluid/fluid.jl @@ -1,8 +1,3 @@ -@inline function set_particle_density(particle, v, system::FluidSystem, - density) - set_particle_density(particle, v, system.density_calculator, system, density) -end - function create_cache_density(initial_condition, ::SummationDensity) density = similar(initial_condition.density) From d8a06e75594382bf1e60d966c93460e1eab72796 Mon Sep 17 00:00:00 2001 From: LasNikas Date: Tue, 21 May 2024 17:05:48 +0200 Subject: [PATCH 059/107] implement suggestions --- src/callbacks/update.jl | 4 +- src/general/buffer.jl | 48 ++++++++++---------- src/general/semidiscretization.jl | 4 +- src/schemes/boundary/open_boundary/system.jl | 8 ++-- test/general/buffer.jl | 2 +- 5 files changed, 34 insertions(+), 32 deletions(-) diff --git a/src/callbacks/update.jl b/src/callbacks/update.jl index 9c919265c..b5f85b8fb 100644 --- a/src/callbacks/update.jl +++ b/src/callbacks/update.jl @@ -57,7 +57,7 @@ function initial_update!(cb::UpdateCallback, u, t, integrator) # Tell systems that `UpdateCallback` is used foreach_system(semi) do system - callback_used!(system) + update_callback_used!(system) end return cb(integrator) @@ -134,4 +134,4 @@ function Base.show(io::IO, ::MIME"text/plain", end end -callback_used!(system) = system +update_callback_used!(system) = system diff --git a/src/general/buffer.jl b/src/general/buffer.jl index 021b7f783..beeb1834c 100644 --- a/src/general/buffer.jl +++ b/src/general/buffer.jl @@ -1,17 +1,13 @@ -struct SystemBuffer{} +struct SystemBuffer{V} active_particle :: BitVector - eachparticle :: Vector{Int} + eachparticle :: V # Vector{Int} buffer_size :: Int - function SystemBuffer(active_size, buffer_size) - if !(buffer_size isa Int) - throw(ArgumentError("`buffer_size` must be of type Int")) - end - + function SystemBuffer(active_size, buffer_size::Integer) active_particle = vcat(trues(active_size), falses(buffer_size)) eachparticle = collect(1:active_size) - return new{}(active_particle, eachparticle, buffer_size) + return new{typeof(eachparticle)}(active_particle, eachparticle, buffer_size) end end @@ -21,12 +17,13 @@ function allocate_buffer(initial_condition, buffer::SystemBuffer) (; buffer_size) = buffer # Initialize particles far away from simulation domain - coordinates = inv(eps()) * ones(ndims(initial_condition), buffer_size) + coordinates = fill(1e16, ndims(initial_condition), buffer_size) - if all(rho -> rho ≈ initial_condition.density[1], initial_condition.density) - density = initial_condition.density[1] + if all(rho -> isapprox(rho, first(initial_condition.density), atol=eps(), rtol=eps()), + initial_condition.density) + density = first(initial_condition.density) else - throw(ArgumentError("`density` needs to be constant when using `SystemBuffer`")) + throw(ArgumentError("`initial_condition.density` needs to be constant when using `SystemBuffer`")) end particle_spacing = initial_condition.particle_spacing @@ -47,10 +44,15 @@ end @inline function update_system_buffer!(buffer::SystemBuffer) (; active_particle) = buffer - new_eachparticle = [i for i in eachindex(active_particle) if active_particle[i]] - resize!(buffer.eachparticle, length(new_eachparticle)) + resize!(buffer.eachparticle, count(active_particle)) - buffer.eachparticle .= new_eachparticle + i = 1 + for j in eachindex(active_particle) + if active_particle[j] + buffer.eachparticle[i] = j + i += 1 + end + end return buffer end @@ -61,18 +63,18 @@ end @inline active_particles(system, buffer) = buffer.eachparticle -@inline function available_particle(system) +@inline function activate_next_particle(system) (; active_particle) = system.buffer - for particle in eachindex(active_particle) - if !active_particle[particle] - active_particle[particle] = true + next_particle = findfirst(active_particle) - return particle - end + if isnothing(next_particle) + error("0 out of $(system.buffer.buffer_size) buffer particles available") end - error("0 out of $(system.buffer.buffer_size) buffer particles available") + active_particle[next_particle] = true + + return next_particle end @inline function deactivate_particle!(system, particle, u) @@ -83,7 +85,7 @@ end # Set particle far away from simulation domain for dim in 1:ndims(system) # Inf or NaN causes instability outcome. - u[dim, particle] = inv(eps()) + u[dim, particle] = 1e16 end return system diff --git a/src/general/semidiscretization.jl b/src/general/semidiscretization.jl index 38259148a..b7857d5a8 100644 --- a/src/general/semidiscretization.jl +++ b/src/general/semidiscretization.jl @@ -647,7 +647,7 @@ function update_nhs!(neighborhood_search, # The current coordinates of fluids and open boundaries change over time. # TODO: Update only `active_coordinates` of open boundaries. - # Problem: Removing inactive particles from neigboring lists is necessary. + # Problem: Removing inactive particles from neighboring lists is necessary. PointNeighbors.update!(neighborhood_search, current_coordinates(u_system, system), current_coordinates(u_neighbor, neighbor), @@ -660,7 +660,7 @@ function update_nhs!(neighborhood_search, # The current coordinates of open boundaries and fluids change over time. # TODO: Update only `active_coordinates` of open boundaries. - # Problem: Removing inactive particles from neigboring lists is necessary. + # Problem: Removing inactive particles from neighboring lists is necessary. PointNeighbors.update!(neighborhood_search, current_coordinates(u_system, system), current_coordinates(u_neighbor, neighbor), diff --git a/src/schemes/boundary/open_boundary/system.jl b/src/schemes/boundary/open_boundary/system.jl index 3ecb9cded..a11da757c 100644 --- a/src/schemes/boundary/open_boundary/system.jl +++ b/src/schemes/boundary/open_boundary/system.jl @@ -97,7 +97,7 @@ struct OpenBoundarySPHSystem{BZ, NDIMS, ELTYPE <: Real, IC, ARRAY1D, ARRAY2D, S, reference_pressure :: RP reference_density :: RD buffer :: B - callback_used :: Ref{Bool} + update_callback_used :: Ref{Bool} function OpenBoundarySPHSystem(plane_points, boundary_zone::Union{InFlow, OutFlow}, sound_speed; @@ -232,7 +232,7 @@ function Base.show(io::IO, ::MIME"text/plain", system::OpenBoundarySPHSystem) end end -callback_used!(system::OpenBoundarySPHSystem) = system.callback_used[] = true +update_callback_used!(system::OpenBoundarySPHSystem) = system.update_callback_used[] = true @inline source_terms(system::OpenBoundarySPHSystem) = nothing @@ -296,7 +296,7 @@ end end function update_final!(system::OpenBoundarySPHSystem, v, u, v_ode, u_ode, semi, t) - if t > 0.0 && !(system.callback_used[]) + if t > 0.0 && !(system.update_callback_used[]) throw(ArgumentError("`UpdateCallback` is required when using `OpenBoundarySPHSystem`")) end @@ -557,7 +557,7 @@ end end @inline function activate_particle!(system_new, particle_old, v_new, u_new, v_old, u_old) - particle_new = available_particle(system_new) + particle_new = activate_next_particle(system_new) # Exchange integrated quantities for i in axes(u_new, 1) diff --git a/test/general/buffer.jl b/test/general/buffer.jl index 36d83aeca..5c0e01537 100644 --- a/test/general/buffer.jl +++ b/test/general/buffer.jl @@ -13,7 +13,7 @@ @test Base.OneTo(n_particles) == TrixiParticles.each_moving_particle(system_buffer) - particle_ID = TrixiParticles.available_particle(system_buffer) + particle_ID = TrixiParticles.activate_next_particle(system_buffer) TrixiParticles.update_system_buffer!(system_buffer.buffer) From 118ac971f7d84a25701c69ba268e15fed966b69e Mon Sep 17 00:00:00 2001 From: LasNikas Date: Tue, 21 May 2024 17:15:50 +0200 Subject: [PATCH 060/107] fix tests --- src/general/buffer.jl | 2 +- test/general/buffer.jl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/general/buffer.jl b/src/general/buffer.jl index beeb1834c..26c6a9238 100644 --- a/src/general/buffer.jl +++ b/src/general/buffer.jl @@ -66,7 +66,7 @@ end @inline function activate_next_particle(system) (; active_particle) = system.buffer - next_particle = findfirst(active_particle) + next_particle = findfirst(x -> !x, active_particle) if isnothing(next_particle) error("0 out of $(system.buffer.buffer_size) buffer particles available") diff --git a/test/general/buffer.jl b/test/general/buffer.jl index 5c0e01537..732712a52 100644 --- a/test/general/buffer.jl +++ b/test/general/buffer.jl @@ -57,7 +57,7 @@ @testset "Illegal Input" begin ic = rectangular_patch(0.1, (3, 3)) buffer = TrixiParticles.SystemBuffer(9, 7) - error_str = "`density` needs to be constant when using `SystemBuffer`" + error_str = "`initial_condition.density` needs to be constant when using `SystemBuffer`" @test_throws ArgumentError(error_str) TrixiParticles.allocate_buffer(ic, buffer) end end From c77a71ae1cd025fc1ceb5f2a8404063a8fec3df1 Mon Sep 17 00:00:00 2001 From: LasNikas Date: Fri, 24 May 2024 09:08:53 +0200 Subject: [PATCH 061/107] Revert "remove density and pressure setter" This reverts commit 0203a3a21a3700a4646a327c1d7eb137fa9bb43f. --- src/general/density_calculators.jl | 10 ++++++++ src/general/system.jl | 4 +++ src/schemes/boundary/open_boundary/system.jl | 25 +++++++++++++------ .../fluid/entropically_damped_sph/system.jl | 5 ++++ src/schemes/fluid/fluid.jl | 5 ++++ 5 files changed, 42 insertions(+), 7 deletions(-) diff --git a/src/general/density_calculators.jl b/src/general/density_calculators.jl index ee89c92a6..d35d0ae0f 100644 --- a/src/general/density_calculators.jl +++ b/src/general/density_calculators.jl @@ -35,6 +35,16 @@ end return v[end, particle] end +# *Note* that these functions are intended to internally set the density for buffer particles +# and density correction. It cannot be used to set up an initial condition, +# as the particle density depends on the particle positions. + +@inline set_particle_density(particle, v, ::SummationDensity, system, density) = system + +@inline function set_particle_density(particle, v, ::ContinuityDensity, system, density) + v[end, particle] = density +end + function summation_density!(system, semi, u, u_ode, density; particles=each_moving_particle(system)) set_zero!(density) diff --git a/src/general/system.jl b/src/general/system.jl index e80cf3996..f34477b8c 100644 --- a/src/general/system.jl +++ b/src/general/system.jl @@ -73,6 +73,10 @@ end return zero(SVector{ndims(system), eltype(system)}) end +@inline set_particle_density(particle, v, system, density) = system + +@inline set_particle_pressure(particle, v, system, pressure) = system + @inline function smoothing_kernel(system, distance) (; smoothing_kernel, smoothing_length) = system return kernel(smoothing_kernel, distance, smoothing_length) diff --git a/src/schemes/boundary/open_boundary/system.jl b/src/schemes/boundary/open_boundary/system.jl index a11da757c..bac685eda 100644 --- a/src/schemes/boundary/open_boundary/system.jl +++ b/src/schemes/boundary/open_boundary/system.jl @@ -534,7 +534,7 @@ end (; spanning_set) = system # Activate a new particle in simulation domain - activate_particle!(fluid_system, particle, v_fluid, u_fluid, v, u) + activate_particle!(fluid_system, system, particle, v_fluid, u_fluid, v, u) # Reset position of boundary particle for dim in 1:ndims(system) @@ -548,7 +548,7 @@ end @inline function transform_particle!(fluid_system::FluidSystem, system, boundary_zone, particle, v, u, v_fluid, u_fluid) # Activate particle in boundary zone - activate_particle!(system, particle, v, u, v_fluid, u_fluid) + activate_particle!(system, fluid_system, particle, v, u, v_fluid, u_fluid) # Deactivate particle in interior domain deactivate_particle!(fluid_system, particle, u_fluid) @@ -556,15 +556,26 @@ end return fluid_system end -@inline function activate_particle!(system_new, particle_old, v_new, u_new, v_old, u_old) +@inline function activate_particle!(system_new, system_old, particle_old, + v_new, u_new, v_old, u_old) particle_new = activate_next_particle(system_new) - # Exchange integrated quantities - for i in axes(u_new, 1) - u_new[i, particle_new] = u_old[i, particle_old] - v_new[i, particle_new] = v_old[i, particle_old] + # Exchange densities + density = particle_density(v_old, system_old, particle_old) + set_particle_density(particle_new, v_new, system_new, density) + + # Exchange pressure + pressure = particle_pressure(v_old, system_old, particle_old) + set_particle_pressure(particle_new, v_new, system_new, pressure) + + # Exchange position and velocity + for dim in 1:ndims(system_new) + u_new[dim, particle_new] = u_old[dim, particle_old] + v_new[dim, particle_new] = v_old[dim, particle_old] end + # TODO: Only when using TVF: set tvf + return system_new end diff --git a/src/schemes/fluid/entropically_damped_sph/system.jl b/src/schemes/fluid/entropically_damped_sph/system.jl index 3b9a61ee7..1f8036be1 100644 --- a/src/schemes/fluid/entropically_damped_sph/system.jl +++ b/src/schemes/fluid/entropically_damped_sph/system.jl @@ -156,6 +156,11 @@ end return v[end, particle] end +@inline function set_particle_pressure(particle, v, system::EntropicallyDampedSPHSystem, + pressure) + return v[end, particle] = pressure +end + @inline system_sound_speed(system::EntropicallyDampedSPHSystem) = system.sound_speed function update_quantities!(system::EntropicallyDampedSPHSystem, v, u, diff --git a/src/schemes/fluid/fluid.jl b/src/schemes/fluid/fluid.jl index 04e29888a..64ab0a1e8 100644 --- a/src/schemes/fluid/fluid.jl +++ b/src/schemes/fluid/fluid.jl @@ -1,3 +1,8 @@ +@inline function set_particle_density(particle, v, system::FluidSystem, + density) + set_particle_density(particle, v, system.density_calculator, system, density) +end + function create_cache_density(initial_condition, ::SummationDensity) density = similar(initial_condition.density) From 5a5b00786e343d9c5ba3d46f5f2ff3a025e25a79 Mon Sep 17 00:00:00 2001 From: LasNikas Date: Fri, 24 May 2024 14:13:22 +0200 Subject: [PATCH 062/107] implement suggestions --- src/general/buffer.jl | 7 +------ src/general/semidiscretization.jl | 2 +- src/schemes/boundary/rhs.jl | 2 +- src/schemes/boundary/system.jl | 8 ++++---- src/schemes/fluid/viscosity.jl | 1 + src/schemes/schemes.jl | 5 +---- src/schemes/solid/discrete_element_method/system.jl | 3 ++- src/visualization/write2vtk.jl | 12 ++++++------ 8 files changed, 17 insertions(+), 23 deletions(-) diff --git a/src/general/buffer.jl b/src/general/buffer.jl index 26c6a9238..b12cf05f3 100644 --- a/src/general/buffer.jl +++ b/src/general/buffer.jl @@ -35,12 +35,7 @@ end @inline update_system_buffer!(buffer::Nothing) = buffer -# `view(eachindex(buffer.active_particle), buffer.active_particle)` is a allocation -# (but thread supporting) version of: -# `(i for i in eachindex(buffer.active_particle) if buffer.active_particle[i])` -# TODO: Find a non-allocation version - -# This is also a allocation version but only in every `update!(buffer)` call +# TODO `resize` allocates. Find a non-allocating version @inline function update_system_buffer!(buffer::SystemBuffer) (; active_particle) = buffer diff --git a/src/general/semidiscretization.jl b/src/general/semidiscretization.jl index b7857d5a8..4b0414fb7 100644 --- a/src/general/semidiscretization.jl +++ b/src/general/semidiscretization.jl @@ -657,7 +657,7 @@ end function update_nhs!(neighborhood_search, system::OpenBoundarySPHSystem, neighbor::FluidSystem, u_system, u_neighbor) - # The current coordinates of open boundaries and fluids change over time. + # The current coordinates of both open boundaries and fluids change over time. # TODO: Update only `active_coordinates` of open boundaries. # Problem: Removing inactive particles from neighboring lists is necessary. diff --git a/src/schemes/boundary/rhs.jl b/src/schemes/boundary/rhs.jl index a114935f8..d9cfb1779 100644 --- a/src/schemes/boundary/rhs.jl +++ b/src/schemes/boundary/rhs.jl @@ -1,4 +1,4 @@ -# Interaction of boundary with other systems +# Interaction of boundary with other systems function interact!(dv, v_particle_system, u_particle_system, v_neighbor_system, u_neighbor_system, neighborhood_search, particle_system::Union{BoundarySystem, OpenBoundarySPHSystem}, diff --git a/src/schemes/boundary/system.jl b/src/schemes/boundary/system.jl index 5d1d0dce6..18cc31031 100644 --- a/src/schemes/boundary/system.jl +++ b/src/schemes/boundary/system.jl @@ -28,7 +28,8 @@ struct BoundarySPHSystem{BM, NDIMS, IC, CO, M, IM, CA} <: BoundarySystem{NDIMS} typeof(initial_condition), typeof(coordinates), typeof(movement), typeof(ismoving), typeof(cache)}(initial_condition, coordinates, boundary_model, - movement, ismoving, cache) + movement, ismoving, cache, + nothing) end end @@ -71,9 +72,8 @@ struct BoundaryDEMSystem{NDIMS, ELTYPE <: Real, ARRAY1D, ARRAY2D} <: BoundarySys ones(length(initial_condition.mass)) NDIMS = size(coordinates, 1) - return new{NDIMS, eltype(coordinates), typeof(radius), typeof(coordinates)}(coordinates, - radius, - normal_stiffness) + return new{NDIMS, eltype(coordinates), typeof(radius), + typeof(coordinates)}(coordinates, radius, normal_stiffness, nothing) end end diff --git a/src/schemes/fluid/viscosity.jl b/src/schemes/fluid/viscosity.jl index 0d0600225..3a81873aa 100644 --- a/src/schemes/fluid/viscosity.jl +++ b/src/schemes/fluid/viscosity.jl @@ -15,6 +15,7 @@ function dv_viscosity(particle_system, neighbor_system::OpenBoundarySPHSystem, v_particle_system, v_neighbor_system, particle, neighbor, pos_diff, distance, sound_speed, m_a, m_b, rho_mean) + # No viscosity in the open boundary system. Use viscosity of the fluid system. viscosity = viscosity_model(particle_system) return dv_viscosity(viscosity, particle_system, neighbor_system, diff --git a/src/schemes/schemes.jl b/src/schemes/schemes.jl index 0682b8298..9ec89b93b 100644 --- a/src/schemes/schemes.jl +++ b/src/schemes/schemes.jl @@ -1,9 +1,6 @@ -# Include open boundary system first, -# since this system should not depend on specific systems. -include("boundary/open_boundary/system.jl") - # Include all schemes without rhs first. The rhs depends on the systems to define # interactions between the different system types. +include("boundary/open_boundary/system.jl") include("fluid/fluid.jl") include("boundary/boundary.jl") include("solid/total_lagrangian_sph/total_lagrangian_sph.jl") diff --git a/src/schemes/solid/discrete_element_method/system.jl b/src/schemes/solid/discrete_element_method/system.jl index 49d08c3e9..d1dba75ac 100644 --- a/src/schemes/solid/discrete_element_method/system.jl +++ b/src/schemes/solid/discrete_element_method/system.jl @@ -57,7 +57,8 @@ struct DEMSystem{NDIMS, ELTYPE <: Real, ARRAY1D, ST} <: SolidSystem{NDIMS} return new{NDIMS, ELTYPE, typeof(mass), typeof(source_terms)}(initial_condition, mass, radius, elastic_modulus, poissons_ratio, normal_stiffness, - damping_coefficient, acceleration_, source_terms) + damping_coefficient, acceleration_, source_terms, + nothing) end end diff --git a/src/visualization/write2vtk.jl b/src/visualization/write2vtk.jl index e381a27d8..3bdf98528 100644 --- a/src/visualization/write2vtk.jl +++ b/src/visualization/write2vtk.jl @@ -182,11 +182,11 @@ end function write2vtk!(vtk, v, u, t, system::FluidSystem; write_meta_data=true) vtk["velocity"] = [current_velocity(v, system, particle) - for particle in each_moving_particle(system)] + for particle in active_particles(system)] vtk["density"] = [particle_density(v, system, particle) - for particle in each_moving_particle(system)] + for particle in active_particles(system)] vtk["pressure"] = [particle_pressure(v, system, particle) - for particle in each_moving_particle(system)] + for particle in active_particles(system)] if write_meta_data vtk["acceleration"] = system.acceleration @@ -265,11 +265,11 @@ function write2vtk!(vtk, v, u, t, system::OpenBoundarySPHSystem; write_meta_data (; reference_velocity, reference_pressure, reference_density) = system vtk["velocity"] = [current_velocity(v, system, particle) - for particle in each_moving_particle(system)] + for particle in active_particles(system)] vtk["density"] = [particle_density(v, system, particle) - for particle in each_moving_particle(system)] + for particle in active_particles(system)] vtk["pressure"] = [particle_pressure(v, system, particle) - for particle in each_moving_particle(system)] + for particle in active_particles(system)] NDIMS = ndims(system) ELTYPE = eltype(system) From b12bc5e2e0463ed8cefab7916d351eb0290bec40 Mon Sep 17 00:00:00 2001 From: LasNikas Date: Sat, 25 May 2024 14:35:21 +0200 Subject: [PATCH 063/107] rework in- and outflow --- examples/fluid/pipe_flow_2d.jl | 17 +- .../boundary/open_boundary/boundary_zones.jl | 174 ++++++++++++++++++ src/schemes/boundary/open_boundary/system.jl | 143 +++----------- src/visualization/write2vtk.jl | 2 +- 4 files changed, 207 insertions(+), 129 deletions(-) create mode 100644 src/schemes/boundary/open_boundary/boundary_zones.jl diff --git a/examples/fluid/pipe_flow_2d.jl b/examples/fluid/pipe_flow_2d.jl index 20ef2abee..3e744bcb3 100644 --- a/examples/fluid/pipe_flow_2d.jl +++ b/examples/fluid/pipe_flow_2d.jl @@ -70,18 +70,17 @@ function velocity_function(pos, t) return SVector(prescribed_velocity, 0.0) # SVector(0.5prescribed_velocity * sin(2pi * t) + prescribed_velocity, 0) end -open_boundary_in = OpenBoundarySPHSystem(([0.0, 0.0], [0.0, domain_size[2]]), InFlow(), - sound_speed; particle_spacing, - flow_direction, open_boundary_layers, - density=fluid_density, buffer=n_buffer_particles, +inflow = InFlow(; plane=([0.0, 0.0], [0.0, domain_size[2]]), flow_direction, + open_boundary_layers, density=fluid_density, particle_spacing) + +open_boundary_in = OpenBoundarySPHSystem(inflow, sound_speed; buffer=n_buffer_particles, reference_pressure=pressure, reference_velocity=velocity_function) -open_boundary_out = OpenBoundarySPHSystem(([domain_size[1], 0.0], - [domain_size[1], domain_size[2]]), OutFlow(), - sound_speed; particle_spacing, - flow_direction, open_boundary_layers, - density=fluid_density, buffer=n_buffer_particles, +outflow = OutFlow(; plane=([domain_size[1], 0.0], [domain_size[1], domain_size[2]]), + flow_direction, open_boundary_layers, density=fluid_density, + particle_spacing) +open_boundary_out = OpenBoundarySPHSystem(outflow, sound_speed; buffer=n_buffer_particles, reference_pressure=pressure, reference_velocity=velocity_function) diff --git a/src/schemes/boundary/open_boundary/boundary_zones.jl b/src/schemes/boundary/open_boundary/boundary_zones.jl new file mode 100644 index 000000000..1d6db80ee --- /dev/null +++ b/src/schemes/boundary/open_boundary/boundary_zones.jl @@ -0,0 +1,174 @@ +""" + InFlow + +Inflow boundary zone for [`OpenBoundarySPHSystem`](@ref) + +# Keywords +- `plane`: Points defining the boundary zones front plane. + The points must either span a rectangular plane in 3D or a line in 2D. +- `flow_direction`: Vector defining the flow direction. +- `open_boundary_layers`: Number of particle layers in upstream direction. +- `initial_condition`: TODO +- `particle_spacing`: TODO +- `density`: TODO +""" +struct InFlow{NDIMS, IC, S, ZO, ZW, FD} + initial_condition :: IC + spanning_set :: S + zone_origin :: ZO + zone_width :: ZW + flow_direction :: FD + + function InFlow(; plane=nothing, flow_direction, density=nothing, + particle_spacing=nothing, initial_condition=nothing, + open_boundary_layers::Integer=0) + if open_boundary_layers < sqrt(eps()) + throw(ArgumentError("`open_boundary_layers` must be positive and greater than zero")) + end + + # Unit vector pointing in downstream direction. + flow_direction_ = normalize(SVector(flow_direction...)) + + if isnothing(initial_condition) + # Sample particles in boundary zone. + initial_condition = extrude_geometry(plane; particle_spacing, density, + direction=-flow_direction_, + n_extrude=open_boundary_layers) + end + + NDIMS = ndims(initial_condition) + ELTYPE = eltype(initial_condition) + + zone_width = open_boundary_layers * initial_condition.particle_spacing + + # Vectors spanning the boundary zone/box. + spanning_set, zone_origin = calculate_spanning_vectors(plane, zone_width) + + # First vector of `spanning_vectors` is normal to the inflow plane. + # The normal vector must point in upstream direction for an inflow boundary. + dot_ = dot(normalize(spanning_set[:, 1]), flow_direction_) + + if !isapprox(abs(dot_), 1.0, atol=1e-7) + throw(ArgumentError("flow direction and normal vector of " * + "inflow-plane do not correspond")) + else + # Flip the inflow vector correspondingly + spanning_set[:, 1] .*= -dot_ + end + + spanning_set_ = reinterpret(reshape, SVector{NDIMS, ELTYPE}, spanning_set) + + return new{NDIMS, typeof(initial_condition), + typeof(spanning_set_), typeof(zone_origin), typeof(zone_width), + typeof(flow_direction_)}(initial_condition, spanning_set_, zone_origin, + zone_width, flow_direction_) + end +end + +""" + OutFlow + +Outflow boundary zone for [`OpenBoundarySPHSystem`](@ref) + + +# Keywords +- `plane`: Points defining the boundary zones front plane. + The points must either span a rectangular plane in 3D or a line in 2D. +- `flow_direction`: Vector defining the flow direction. +- `open_boundary_layers`: Number of particle layers in upstream direction. +- `initial_condition`: TODO +- `particle_spacing`: TODO +- `density`: TODO +""" +struct OutFlow{NDIMS, IC, S, ZO, ZW, FD} + initial_condition :: IC + spanning_set :: S + zone_origin :: ZO + zone_width :: ZW + flow_direction :: FD + + function OutFlow(; plane=nothing, flow_direction, density=nothing, + particle_spacing=nothing, initial_condition=nothing, + open_boundary_layers::Integer=0) + if open_boundary_layers < sqrt(eps()) + throw(ArgumentError("`open_boundary_layers` must be positive and greater than zero")) + end + + # Unit vector pointing in downstream direction. + flow_direction_ = normalize(SVector(flow_direction...)) + + if isnothing(initial_condition) + # Sample particles in boundary zone. + initial_condition = extrude_geometry(plane; particle_spacing, + direction=flow_direction_, density, + n_extrude=open_boundary_layers) + end + + NDIMS = ndims(initial_condition) + ELTYPE = eltype(initial_condition) + + zone_width = open_boundary_layers * initial_condition.particle_spacing + + # Vectors spanning the boundary zone/box. + spanning_set, zone_origin = calculate_spanning_vectors(plane, zone_width) + + # First vector of `spanning_vectors` is normal to the outflow plane. + # The normal vector must point in downstream direction for an outflow boundary. + dot_ = dot(normalize(spanning_set[:, 1]), flow_direction_) + + if !isapprox(abs(dot_), 1.0, atol=1e-7) + throw(ArgumentError("flow direction and normal vector of " * + "outflow-plane do not correspond")) + else + # Flip the inflow vector correspondingly + spanning_set[:, 1] .*= dot_ + end + + spanning_set_ = reinterpret(reshape, SVector{NDIMS, ELTYPE}, spanning_set) + + return new{NDIMS, typeof(initial_condition), + typeof(spanning_set_), typeof(zone_origin), typeof(zone_width), + typeof(flow_direction_)}(initial_condition, spanning_set_, zone_origin, + zone_width, flow_direction_) + end +end + +@inline Base.ndims(::Union{InFlow{NDIMS}, OutFlow{NDIMS}}) where {NDIMS} = NDIMS + +# function calculate_spanning_vectors(plane::Shapes, zone_width) +# # TODO: Handle differently +# end + +function calculate_spanning_vectors(plane, zone_width) + return spanning_vectors(plane, zone_width), SVector(plane[1]...) +end + +function spanning_vectors(plane_points, zone_width) + + # Convert to tuple + return spanning_vectors(tuple(plane_points...), zone_width) +end + +function spanning_vectors(plane_points::NTuple{2}, zone_width) + plane_size = plane_points[2] - plane_points[1] + + # Calculate normal vector of plane + b = Vector(normalize([-plane_size[2]; plane_size[1]]) * zone_width) + + return hcat(b, plane_size) +end + +function spanning_vectors(plane_points::NTuple{3}, zone_width) + # Vectors spanning the plane + edge1 = plane_points[2] - plane_points[1] + edge2 = plane_points[3] - plane_points[1] + + if !isapprox(dot(edge1, edge2), 0.0, atol=1e-7) + throw(ArgumentError("the provided points do not span a rectangular plane")) + end + + # Calculate normal vector of plane + c = Vector(normalize(cross(edge2, edge1)) * zone_width) + + return hcat(c, edge1, edge2) +end diff --git a/src/schemes/boundary/open_boundary/system.jl b/src/schemes/boundary/open_boundary/system.jl index bac685eda..9a7a63a82 100644 --- a/src/schemes/boundary/open_boundary/system.jl +++ b/src/schemes/boundary/open_boundary/system.jl @@ -1,16 +1,4 @@ -""" - InFlow - -Inflow boundary zone for [`OpenBoundarySPHSystem`](@ref) -""" -struct InFlow end - -""" - OutFlow - -Outflow boundary zone for [`OpenBoundarySPHSystem`](@ref) -""" -struct OutFlow end +include("boundary_zones.jl") """ OpenBoundarySPHSystem(plane_points, boundary_zone::Union{InFlow, OutFlow}, @@ -25,22 +13,10 @@ to the outlet or inlet and has been proposed by Lastiwka et al (2009). For more about the method see [Open Boundary System](@ref open_boundary). # Arguments -- `plane_points`: Points defining the boundary zones front plane. - The points must either span a rectangular plane in 3D or a line in 2D. - See description above for more information. - `boundary_zone`: Use [`InFlow`](@ref) for an inflow and [`OutFlow`](@ref) for an outflow boundary. - `sound_speed`: Speed of sound. # Keywords -- `sample_plane`: For customized particle sampling in the boundary zone, this can be either - points defining a 3D plane (2D line), particle coordinates defining a specific - shape or a specific [`InitialCondition`](@ref) type. - The geometry will be extruded in upstream direction with [`extrude_geometry`](@ref). - Default is `plane_points` which fully samples the boundary zone with particles. -- `particle_spacing`: The spacing between the particles in the boundary zone. -- `flow_direction`: Vector defining the flow direction. -- `open_boundary_layers`: Number of particle layers in upstream direction. -- `density`: Density of each particle to define the mass of each particle (see [`InitialCondition`](@ref)). - `buffer`: Number of buffer particles. - `reference_velocity`: Reference velocity is either a function mapping each particle's coordinates and time to its velocity, an array where the ``i``-th column holds @@ -79,7 +55,7 @@ system = OpenBoundarySPHSystem(plane_points, InFlow(), 10.0; particle_spacing=0. open_boundary_layers=4, density=1.0, flow_direction) ``` """ -struct OpenBoundarySPHSystem{BZ, NDIMS, ELTYPE <: Real, IC, ARRAY1D, ARRAY2D, S, RV, RP, +struct OpenBoundarySPHSystem{BZ, NDIMS, ELTYPE <: Real, IC, ARRAY1D, ARRAY2D, RV, RP, RD, B} <: System{NDIMS} initial_condition :: IC mass :: ARRAY1D # Array{ELTYPE, 1}: [particle] @@ -91,35 +67,18 @@ struct OpenBoundarySPHSystem{BZ, NDIMS, ELTYPE <: Real, IC, ARRAY1D, ARRAY2D, S, sound_speed :: ELTYPE boundary_zone :: BZ flow_direction :: SVector{NDIMS, ELTYPE} - zone_origin :: SVector{NDIMS, ELTYPE} - spanning_set :: S reference_velocity :: RV reference_pressure :: RP reference_density :: RD buffer :: B update_callback_used :: Ref{Bool} - function OpenBoundarySPHSystem(plane_points, boundary_zone::Union{InFlow, OutFlow}, - sound_speed; - sample_geometry=plane_points, particle_spacing, - flow_direction, open_boundary_layers::Integer=0, density, + function OpenBoundarySPHSystem(boundary_zone::Union{InFlow, OutFlow}, sound_speed; buffer=nothing, - reference_velocity=zeros(length(flow_direction)), - reference_pressure=0.0, reference_density=density) - if open_boundary_layers < sqrt(eps()) - throw(ArgumentError("`open_boundary_layers` must be positive and greater than zero")) - end - - # Unit vector pointing in downstream direction. - flow_direction_ = normalize(SVector(flow_direction...)) - - # Sample boundary zone with particles in corresponding direction. - (boundary_zone isa OutFlow) && (direction = flow_direction_) - (boundary_zone isa InFlow) && (direction = -flow_direction_) - - # Sample particles in boundary zone. - initial_condition = extrude_geometry(sample_geometry; particle_spacing, direction, - n_extrude=open_boundary_layers, density) + reference_velocity=zeros(ndims(boundary_zone)), + reference_pressure=0.0, + reference_density=first(boundary_zone.initial_condition.density)) + (; initial_condition) = boundary_zone (buffer ≠ nothing) && (buffer = SystemBuffer(nparticles(initial_condition), buffer)) initial_condition = allocate_buffer(initial_condition, buffer) @@ -150,33 +109,6 @@ struct OpenBoundarySPHSystem{BZ, NDIMS, ELTYPE <: Real, IC, ARRAY1D, ARRAY2D, S, reference_density_ = wrap_reference_function(reference_density, Val(NDIMS)) end - zone_width = open_boundary_layers * initial_condition.particle_spacing - - # Vectors spanning the boundary zone/box. - spanning_set = spanning_vectors(plane_points, zone_width) - - # First vector of `spanning_vectors` is normal to the in-/outflow plane. - # The normal vector must point in downstream direction for an outflow boundary and - # for an inflow boundary the normal vector must point in upstream direction. - # Thus, rotate the normal vector correspondingly. - if isapprox(dot(normalize(spanning_set[:, 1]), flow_direction_), 1.0, atol=1e-7) - # Normal vector points in downstream direction. - # Flip the inflow vector in upstream direction - (boundary_zone isa InFlow) && (spanning_set[:, 1] .*= -1) - elseif isapprox(dot(normalize(spanning_set[:, 1]), flow_direction_), -1.0, - atol=1e-7) - # Normal vector points in upstream direction. - # Flip the outflow vector in downstream direction - (boundary_zone isa OutFlow) && (spanning_set[:, 1] .*= -1) - else - throw(ArgumentError("flow direction and normal vector of " * - "$(typeof(boundary_zone))-plane do not correspond")) - end - - spanning_set_ = reinterpret(reshape, SVector{NDIMS, ELTYPE}, spanning_set) - - zone_origin = SVector(plane_points[1]...) - mass = copy(initial_condition.mass) pressure = [reference_pressure_(initial_condition.coordinates[:, i], 0.0) for i in eachparticle(initial_condition)] @@ -186,15 +118,16 @@ struct OpenBoundarySPHSystem{BZ, NDIMS, ELTYPE <: Real, IC, ARRAY1D, ARRAY2D, S, characteristics = zeros(ELTYPE, 3, length(mass)) previous_characteristics = zeros(ELTYPE, 3, length(mass)) + flow_direction_ = boundary_zone.flow_direction + return new{typeof(boundary_zone), NDIMS, ELTYPE, typeof(initial_condition), - typeof(mass), typeof(characteristics), typeof(spanning_set_), + typeof(mass), typeof(characteristics), typeof(reference_velocity_), typeof(reference_pressure_), typeof(reference_density_), typeof(buffer)}(initial_condition, mass, density, volume, pressure, characteristics, previous_characteristics, sound_speed, - boundary_zone, flow_direction_, zone_origin, - spanning_set_, reference_velocity_, reference_pressure_, - reference_density_, buffer, false) + boundary_zone, flow_direction_, reference_velocity_, + reference_pressure_, reference_density_, buffer, false) end end @@ -222,12 +155,12 @@ function Base.show(io::IO, ::MIME"text/plain", system::OpenBoundarySPHSystem) else summary_line(io, "#particles", nparticles(system)) end - summary_line(io, "boundary", system.boundary_zone) + summary_line(io, "boundary", type2string(system.boundary_zone)) summary_line(io, "flow direction", system.flow_direction) summary_line(io, "prescribed velocity", string(nameof(system.reference_velocity))) summary_line(io, "prescribed pressure", string(nameof(system.reference_pressure))) summary_line(io, "prescribed density", string(nameof(system.reference_density))) - summary_line(io, "width", round(norm(system.spanning_set[1]), digits=3)) + summary_line(io, "width", round(system.boundary_zone.zone_width, digits=3)) summary_footer(io) end end @@ -246,41 +179,11 @@ end return system.pressure[particle] end -function spanning_vectors(plane_points, zone_width) - - # Convert to tuple - return spanning_vectors(tuple(plane_points...), zone_width) -end - -function spanning_vectors(plane_points::NTuple{2}, zone_width) - plane_size = plane_points[2] - plane_points[1] - - # Calculate normal vector of plane - b = Vector(normalize([-plane_size[2]; plane_size[1]]) * zone_width) - - return hcat(b, plane_size) -end - -function spanning_vectors(plane_points::NTuple{3}, zone_width) - # Vectors spanning the plane - edge1 = plane_points[2] - plane_points[1] - edge2 = plane_points[3] - plane_points[1] - - if !isapprox(dot(edge1, edge2), 0.0, atol=1e-7) - throw(ArgumentError("the provided points do not span a rectangular plane")) - end - - # Calculate normal vector of plane - c = Vector(normalize(cross(edge2, edge1)) * zone_width) - - return hcat(c, edge1, edge2) -end - -@inline function within_boundary_zone(particle_coords, system) - (; zone_origin, spanning_set) = system +@inline function (boundary_zone::Union{InFlow, OutFlow})(particle_coords) + (; zone_origin, spanning_set) = boundary_zone particle_position = particle_coords - zone_origin - for dim in 1:ndims(system) + for dim in 1:ndims(boundary_zone) span_dim = spanning_set[dim] # Checks whether the projection of the particle position # falls within the range of the zone. @@ -501,7 +404,7 @@ function check_fluid_domain!(system, fluid_system::FluidSystem, particle, neighborhood_search = get_neighborhood_search(system, fluid_system, semi) # Check if the particle position is outside the boundary zone. - if !within_boundary_zone(particle_coords, system) + if !boundary_zone(particle_coords) transform_particle!(system, fluid_system, boundary_zone, particle, v, u, v_fluid, u_fluid) end @@ -511,7 +414,7 @@ function check_fluid_domain!(system, fluid_system::FluidSystem, particle, fluid_coords = current_coords(u_fluid, fluid_system, neighbor) # Check if neighbor position is in boundary zone - if within_boundary_zone(fluid_coords, system) + if boundary_zone(fluid_coords) transform_particle!(fluid_system, system, boundary_zone, neighbor, v, u, v_fluid, u_fluid) end @@ -522,7 +425,8 @@ end # Outflow particle is outside the boundary zone @inline function transform_particle!(system::OpenBoundarySPHSystem, fluid_system, - ::OutFlow, particle, v, u, v_fluid, u_fluid) + boundary_zone::OutFlow, particle, v, u, + v_fluid, u_fluid) deactivate_particle!(system, particle, u) return system @@ -530,8 +434,9 @@ end # Inflow particle is outside the boundary zone @inline function transform_particle!(system::OpenBoundarySPHSystem, fluid_system, - ::InFlow, particle, v, u, v_fluid, u_fluid) - (; spanning_set) = system + boundary_zone::InFlow, particle, v, u, + v_fluid, u_fluid) + (; spanning_set) = boundary_zone # Activate a new particle in simulation domain activate_particle!(fluid_system, system, particle, v_fluid, u_fluid, v, u) diff --git a/src/visualization/write2vtk.jl b/src/visualization/write2vtk.jl index 3bdf98528..2acc4b0df 100644 --- a/src/visualization/write2vtk.jl +++ b/src/visualization/write2vtk.jl @@ -282,7 +282,7 @@ function write2vtk!(vtk, v, u, t, system::OpenBoundarySPHSystem; write_meta_data if write_meta_data vtk["boundary_zone"] = type2string(system.boundary_zone) vtk["sound_speed"] = system.sound_speed - vtk["width"] = round(norm(system.spanning_set[1]), digits=3) + vtk["width"] = round(system.boundary_zone.zone_width, digits=3) vtk["flow_direction"] = system.flow_direction vtk["velocity_function"] = string(nameof(system.reference_velocity)) vtk["pressure_function"] = string(nameof(system.reference_pressure)) From 147a18d42a8d89cdcafe7cc68737ef4daeaa4a57 Mon Sep 17 00:00:00 2001 From: LasNikas Date: Mon, 27 May 2024 10:29:40 +0200 Subject: [PATCH 064/107] rename setter functions --- src/general/density_calculators.jl | 15 +++++++++------ src/general/system.jl | 4 ++-- src/schemes/boundary/open_boundary/system.jl | 4 ++-- .../fluid/entropically_damped_sph/system.jl | 11 +++++++++-- src/schemes/fluid/fluid.jl | 5 ++--- 5 files changed, 24 insertions(+), 15 deletions(-) diff --git a/src/general/density_calculators.jl b/src/general/density_calculators.jl index d35d0ae0f..7244253b0 100644 --- a/src/general/density_calculators.jl +++ b/src/general/density_calculators.jl @@ -35,14 +35,17 @@ end return v[end, particle] end -# *Note* that these functions are intended to internally set the density for buffer particles -# and density correction. It cannot be used to set up an initial condition, -# as the particle density depends on the particle positions. +# WARNING! +# These functions are intended to be used internally to set the density +# of newly activated particles in a callback. +# DO NOT use outside a callback. OrdinaryDiffEq does not allow changing `v` and `u` +# outside of callbacks. +@inline set_particle_density!(v, system, ::SummationDensity, particle, density) = v -@inline set_particle_density(particle, v, ::SummationDensity, system, density) = system - -@inline function set_particle_density(particle, v, ::ContinuityDensity, system, density) +@inline function set_particle_density!(v, system, ::ContinuityDensity, particle, density) v[end, particle] = density + + return v end function summation_density!(system, semi, u, u_ode, density; diff --git a/src/general/system.jl b/src/general/system.jl index f34477b8c..7883991fc 100644 --- a/src/general/system.jl +++ b/src/general/system.jl @@ -73,9 +73,9 @@ end return zero(SVector{ndims(system), eltype(system)}) end -@inline set_particle_density(particle, v, system, density) = system +@inline set_particle_density!(v, system, particle, density) = v -@inline set_particle_pressure(particle, v, system, pressure) = system +@inline set_particle_pressure!(v, system, particle, pressure) = v @inline function smoothing_kernel(system, distance) (; smoothing_kernel, smoothing_length) = system diff --git a/src/schemes/boundary/open_boundary/system.jl b/src/schemes/boundary/open_boundary/system.jl index bac685eda..9e1fa5d9d 100644 --- a/src/schemes/boundary/open_boundary/system.jl +++ b/src/schemes/boundary/open_boundary/system.jl @@ -562,11 +562,11 @@ end # Exchange densities density = particle_density(v_old, system_old, particle_old) - set_particle_density(particle_new, v_new, system_new, density) + set_particle_density!(v_new, system_new, particle_new, density) # Exchange pressure pressure = particle_pressure(v_old, system_old, particle_old) - set_particle_pressure(particle_new, v_new, system_new, pressure) + set_particle_pressure!(v_new, system_new, particle_new, pressure) # Exchange position and velocity for dim in 1:ndims(system_new) diff --git a/src/schemes/fluid/entropically_damped_sph/system.jl b/src/schemes/fluid/entropically_damped_sph/system.jl index 1f8036be1..f64af38ce 100644 --- a/src/schemes/fluid/entropically_damped_sph/system.jl +++ b/src/schemes/fluid/entropically_damped_sph/system.jl @@ -156,9 +156,16 @@ end return v[end, particle] end -@inline function set_particle_pressure(particle, v, system::EntropicallyDampedSPHSystem, +# WARNING! +# These functions are intended to be used internally to set the pressure +# of newly activated particles in a callback. +# DO NOT use outside a callback. OrdinaryDiffEq does not allow changing `v` and `u` +# outside of callbacks. +@inline function set_particle_pressure!(v, system::EntropicallyDampedSPHSystem, particle, pressure) - return v[end, particle] = pressure + v[end, particle] = pressure + + return v end @inline system_sound_speed(system::EntropicallyDampedSPHSystem) = system.sound_speed diff --git a/src/schemes/fluid/fluid.jl b/src/schemes/fluid/fluid.jl index 64ab0a1e8..280a6b76b 100644 --- a/src/schemes/fluid/fluid.jl +++ b/src/schemes/fluid/fluid.jl @@ -1,6 +1,5 @@ -@inline function set_particle_density(particle, v, system::FluidSystem, - density) - set_particle_density(particle, v, system.density_calculator, system, density) +@inline function set_particle_density!(v, system::FluidSystem, particle, density) + set_particle_density!(v, system, system.density_calculator, particle, density) end function create_cache_density(initial_condition, ::SummationDensity) From 75615f2e0b29ad52c1a198693ac2014fd4057d46 Mon Sep 17 00:00:00 2001 From: LasNikas Date: Mon, 27 May 2024 10:45:01 +0200 Subject: [PATCH 065/107] rename function --- src/schemes/boundary/open_boundary/system.jl | 12 ++++++------ src/schemes/fluid/entropically_damped_sph/system.jl | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/schemes/boundary/open_boundary/system.jl b/src/schemes/boundary/open_boundary/system.jl index 9e1fa5d9d..24c8c058b 100644 --- a/src/schemes/boundary/open_boundary/system.jl +++ b/src/schemes/boundary/open_boundary/system.jl @@ -534,7 +534,7 @@ end (; spanning_set) = system # Activate a new particle in simulation domain - activate_particle!(fluid_system, system, particle, v_fluid, u_fluid, v, u) + transfer_quantities!(fluid_system, system, particle, v_fluid, u_fluid, v, u) # Reset position of boundary particle for dim in 1:ndims(system) @@ -548,7 +548,7 @@ end @inline function transform_particle!(fluid_system::FluidSystem, system, boundary_zone, particle, v, u, v_fluid, u_fluid) # Activate particle in boundary zone - activate_particle!(system, fluid_system, particle, v, u, v_fluid, u_fluid) + transfer_quantities!(system, fluid_system, particle, v, u, v_fluid, u_fluid) # Deactivate particle in interior domain deactivate_particle!(fluid_system, particle, u_fluid) @@ -556,15 +556,15 @@ end return fluid_system end -@inline function activate_particle!(system_new, system_old, particle_old, - v_new, u_new, v_old, u_old) +@inline function transfer_quantities!(system_new, system_old, particle_old, + v_new, u_new, v_old, u_old) particle_new = activate_next_particle(system_new) - # Exchange densities + # Transfer densities density = particle_density(v_old, system_old, particle_old) set_particle_density!(v_new, system_new, particle_new, density) - # Exchange pressure + # Transfer pressure pressure = particle_pressure(v_old, system_old, particle_old) set_particle_pressure!(v_new, system_new, particle_new, pressure) diff --git a/src/schemes/fluid/entropically_damped_sph/system.jl b/src/schemes/fluid/entropically_damped_sph/system.jl index f64af38ce..780989e0c 100644 --- a/src/schemes/fluid/entropically_damped_sph/system.jl +++ b/src/schemes/fluid/entropically_damped_sph/system.jl @@ -162,7 +162,7 @@ end # DO NOT use outside a callback. OrdinaryDiffEq does not allow changing `v` and `u` # outside of callbacks. @inline function set_particle_pressure!(v, system::EntropicallyDampedSPHSystem, particle, - pressure) + pressure) v[end, particle] = pressure return v From a3adf1d1b3a8e02f25a3591f7bde76e73005c299 Mon Sep 17 00:00:00 2001 From: LasNikas Date: Mon, 27 May 2024 12:22:07 +0200 Subject: [PATCH 066/107] adapt tests --- src/schemes/boundary/open_boundary/system.jl | 2 +- .../boundary/open_boundary/boundary_zone.jl | 221 ++++++++++++++++++ .../open_boundary/characteristic_variables.jl | 65 +++--- .../boundary/open_boundary/open_boundary.jl | 2 + test/schemes/schemes.jl | 2 +- test/systems/open_boundary_system.jl | 219 +++-------------- 6 files changed, 296 insertions(+), 215 deletions(-) create mode 100644 test/schemes/boundary/open_boundary/boundary_zone.jl create mode 100644 test/schemes/boundary/open_boundary/open_boundary.jl diff --git a/src/schemes/boundary/open_boundary/system.jl b/src/schemes/boundary/open_boundary/system.jl index 9a7a63a82..805a16d9b 100644 --- a/src/schemes/boundary/open_boundary/system.jl +++ b/src/schemes/boundary/open_boundary/system.jl @@ -138,7 +138,7 @@ function Base.show(io::IO, system::OpenBoundarySPHSystem) @nospecialize system # reduce precompilation time print(io, "OpenBoundarySPHSystem{", ndims(system), "}(") - print(io, system.boundary_zone) + print(io, type2string(system.boundary_zone)) print(io, ") with ", nparticles(system), " particles") end diff --git a/test/schemes/boundary/open_boundary/boundary_zone.jl b/test/schemes/boundary/open_boundary/boundary_zone.jl new file mode 100644 index 000000000..58dd79783 --- /dev/null +++ b/test/schemes/boundary/open_boundary/boundary_zone.jl @@ -0,0 +1,221 @@ +@testset verbose=true "Boundary Zone" begin + @testset verbose=true "Boundary Zone 2D" begin + particle_spacing = 0.2 + open_boundary_layers = 4 + + plane_points_1 = [[0.0, 0.0], [0.5, -0.5], [1.0, 0.5]] + plane_points_2 = [[0.0, 1.0], [0.2, 2.0], [2.3, 0.5]] + + @testset "Points $(i)" for i in eachindex(plane_points_1) + point_1 = plane_points_1[i] + point_2 = plane_points_2[i] + + plane_size = point_2 - point_1 + + flow_directions = [ + normalize([-plane_size[2], plane_size[1]]), + -normalize([-plane_size[2], plane_size[1]]) + ] + + @testset "Flow Direction $(j)" for j in eachindex(flow_directions) + inflow = InFlow(; plane=(point_1, point_2), particle_spacing, + flow_direction=flow_directions[j], density=1.0, + open_boundary_layers) + outflow = OutFlow(; plane=(point_1, point_2), particle_spacing, + flow_direction=flow_directions[j], density=1.0, + open_boundary_layers) + + boundary_zones = [ + inflow, + outflow + ] + + @testset "$boundary_zone" for boundary_zone in boundary_zones + zone_width = open_boundary_layers * + boundary_zone.initial_condition.particle_spacing + sign_ = (boundary_zone isa InFlow) ? -1 : 1 + + @test plane_points_1[i] == boundary_zone.zone_origin + @test plane_points_2[i] - boundary_zone.zone_origin == + boundary_zone.spanning_set[2] + @test sign_ * flow_directions[j] ≈ + normalize(boundary_zone.spanning_set[1]) + @test zone_width ≈ norm(boundary_zone.spanning_set[1]) + end + end + end + end + + @testset verbose=true "Boundary Zone 3D" begin + particle_spacing = 0.05 + open_boundary_layers = 4 + + plane_points_1 = [ + [0.0, 0.0, 0.0], + [0.3113730847835541, 0.19079485535621643, -0.440864622592926] + ] + plane_points_2 = [ + [1.0, 0.0, 0.0], + [-0.10468611121177673, 0.252103328704834, -0.44965094327926636] + ] + plane_points_3 = [ + [0.0, 1.0, 0.0], + [0.3113730847835541, 0.25057315826416016, -0.02374829351902008] + ] + + @testset "Points $(i)" for i in eachindex(plane_points_1) + point_1 = plane_points_1[i] + point_2 = plane_points_2[i] + point_3 = plane_points_3[i] + + edge1 = point_2 - point_1 + edge2 = point_3 - point_1 + + flow_directions = [ + normalize(cross(edge1, edge2)), + -normalize(cross(edge1, edge2)) + ] + + @testset "Flow Direction $(j)" for j in eachindex(flow_directions) + inflow = InFlow(; plane=(point_1, point_2, point_3), particle_spacing, + flow_direction=flow_directions[j], density=1.0, + open_boundary_layers) + outflow = OutFlow(; plane=(point_1, point_2, point_3), particle_spacing, + flow_direction=flow_directions[j], density=1.0, + open_boundary_layers) + + boundary_zones = [ + inflow, + outflow + ] + + @testset "$boundary_zone" for boundary_zone in boundary_zones + zone_width = open_boundary_layers * + boundary_zone.initial_condition.particle_spacing + sign_ = (boundary_zone isa InFlow) ? -1 : 1 + + @test plane_points_1[i] == boundary_zone.zone_origin + @test plane_points_2[i] - boundary_zone.zone_origin == + boundary_zone.spanning_set[2] + @test plane_points_3[i] - boundary_zone.zone_origin == + boundary_zone.spanning_set[3] + @test sign_ * flow_directions[j] ≈ + normalize(boundary_zone.spanning_set[1]) + @test zone_width ≈ norm(boundary_zone.spanning_set[1]) + end + end + end + end + + @testset verbose=true "Particle In Boundary Zone 2D" begin + plane_points = [[-0.2, -0.5], [0.3, 0.6]] + plane_size = plane_points[2] - plane_points[1] + + flow_direction = normalize([-plane_size[2], plane_size[1]]) + + inflow = InFlow(; plane=plane_points, particle_spacing=0.1, + flow_direction, density=1.0, open_boundary_layers=4) + outflow = OutFlow(; plane=plane_points, particle_spacing=0.1, + flow_direction, density=1.0, open_boundary_layers=4) + + boundary_zones = [ + inflow, + outflow + ] + + @testset "$(nameof(typeof(boundary_zone)))" for boundary_zone in boundary_zones + perturb_ = boundary_zone isa InFlow ? eps() : -eps() + + point_3 = boundary_zone.spanning_set[1] + boundary_zone.zone_origin + + query_points = Dict( + "Behind" => ([-1.0, -1.0], false), + "Before" => ([2.0, 2.0], false), + "On Point 1" => (plane_points[1], true), + "On Point 2" => (plane_points[2], true), + "On Point 3" => (point_3, true), + "Closely On Point 1" => (plane_points[1] .+ perturb_ * flow_direction, + false)) + + TrixiParticles.@autoinfiltrate + + @testset "$k" for k in keys(query_points) + (particle_position, evaluation) = query_points[k] + + @test evaluation == boundary_zone(particle_position) + end + end + end + + @testset verbose=true "Particle In Boundary Zone 3D" begin + point1 = [-0.2, -0.5, 0.0] + point2 = [0.3, 0.5, 0.0] + point3 = [0.13111173850909402, -0.665555869254547, 0.0] + + flow_direction = normalize(cross(point2 - point1, point3 - point1)) + + inflow = InFlow(; plane=[point1, point2, point3], particle_spacing=0.1, + flow_direction, density=1.0, open_boundary_layers=4) + outflow = OutFlow(; plane=[point1, point2, point3], particle_spacing=0.1, + flow_direction, density=1.0, open_boundary_layers=4) + + boundary_zones = [ + inflow, + outflow + ] + + @testset "$(nameof(typeof(boundary_zone)))" for boundary_zone in boundary_zones + perturb_ = boundary_zone isa InFlow ? eps() : -eps() + query_points = Dict( + "Behind" => ([-1.0, -1.0, 1.2], false), + "Before" => ([2.0, 2.0, -1.2], false), + "On Point 1" => (point1, true), + "On Point 2" => (point2, true), + "On Point 3" => (point3, true), + "On Point 4" => (boundary_zone.spanning_set[1] + boundary_zone.zone_origin, + true), + "Closely On Point 1" => (point1 .+ perturb_ * flow_direction, false)) + + @testset "$k" for k in keys(query_points) + (particle_position, evaluation) = query_points[k] + + @test evaluation == boundary_zone(particle_position) + end + end + end + + @testset verbose=true "Illegal Inputs" begin + no_rectangular_plane = [[0.2, 0.3, -0.5], [-1.0, 1.5, 0.2], [-0.2, 2.0, -0.5]] + flow_direction = [0.0, 0.0, 1.0] + + error_str = "the provided points do not span a rectangular plane" + + @test_throws ArgumentError(error_str) InFlow(; plane=no_rectangular_plane, + particle_spacing=0.1, + flow_direction, density=1.0, + open_boundary_layers=2) + @test_throws ArgumentError(error_str) OutFlow(; plane=no_rectangular_plane, + particle_spacing=0.1, + flow_direction, density=1.0, + open_boundary_layers=2) + + rectangular_plane = [[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0]] + flow_direction = [0.0, 1.0, 0.0] + + error_str = "flow direction and normal vector of " * + "inflow-plane do not correspond" + + @test_throws ArgumentError(error_str) InFlow(; plane=rectangular_plane, + particle_spacing=0.1, + flow_direction, density=1.0, + open_boundary_layers=2) + + error_str = "flow direction and normal vector of " * + "outflow-plane do not correspond" + + @test_throws ArgumentError(error_str) OutFlow(; plane=rectangular_plane, + particle_spacing=0.1, + flow_direction, density=1.0, + open_boundary_layers=2) + end +end diff --git a/test/schemes/boundary/open_boundary/characteristic_variables.jl b/test/schemes/boundary/open_boundary/characteristic_variables.jl index fafa0c72b..da535ce82 100644 --- a/test/schemes/boundary/open_boundary/characteristic_variables.jl +++ b/test/schemes/boundary/open_boundary/characteristic_variables.jl @@ -1,6 +1,5 @@ @testset verbose=true "Characteristic Variables" begin particle_spacing = 0.1 - boundary_zones = [InFlow(), OutFlow()] # Number of boundary particles in the influence of fluid particles influenced_particles = [20, 52, 26] @@ -19,29 +18,37 @@ reference_density = (pos, t) -> 1000.0 * t # Plane points of open boundary - point1s = [[0.0, 0.0], [0.5, -0.5], [1.0, 0.5]] - point2s = [[0.0, 1.0], [0.2, 2.0], [2.3, 0.5]] - - @testset "$boundary_zone" for boundary_zone in boundary_zones - @testset "Points $(i)" for i in eachindex(point1s) - n_influenced = influenced_particles[i] - - plane_points = [point1s[i], point2s[i]] - - plane_size = plane_points[2] - plane_points[1] - flow_directions = [ - normalize([-plane_size[2], plane_size[1]]), - -normalize([-plane_size[2], plane_size[1]]), + plane_points_1 = [[0.0, 0.0], [0.5, -0.5], [1.0, 0.5]] + plane_points_2 = [[0.0, 1.0], [0.2, 2.0], [2.3, 0.5]] + + @testset "Points $(i)" for i in eachindex(plane_points_1) + n_influenced = influenced_particles[i] + + plane_points = [plane_points_1[i], plane_points_2[i]] + + plane_size = plane_points[2] - plane_points[1] + flow_directions = [ + normalize([-plane_size[2], plane_size[1]]), + -normalize([-plane_size[2], plane_size[1]]), + ] + + @testset "Flow Direction $(j)" for j in eachindex(flow_directions) + flow_direction = flow_directions[j] + inflow = InFlow(; plane=plane_points, particle_spacing, density, + flow_direction, open_boundary_layers) + outflow = OutFlow(; plane=plane_points, particle_spacing, density, + flow_direction, open_boundary_layers) + + boundary_zones = [ + inflow, + outflow, ] - @testset "Flow Direction $(j)" for j in eachindex(flow_directions) - flow_direction = flow_directions[j] - - inlet_system = OpenBoundarySPHSystem(plane_points, boundary_zone, - sound_speed; flow_direction, - particle_spacing, open_boundary_layers, - density, reference_velocity, - reference_pressure, reference_density) + @testset "$(nameof(typeof(boundary_zone)))" for boundary_zone in boundary_zones + boundary_system = OpenBoundarySPHSystem(boundary_zone, sound_speed; + reference_velocity, + reference_pressure, + reference_density) sign_ = (boundary_zone isa InFlow) ? 1 : -1 fluid = extrude_geometry(plane_points; particle_spacing, n_extrude=4, @@ -52,13 +59,13 @@ density_calculator=ContinuityDensity(), smoothing_length, sound_speed) - semi = Semidiscretization(fluid_system, inlet_system) + semi = Semidiscretization(fluid_system, boundary_system) ode = semidiscretize(semi, (0.0, 5.0)) v0_ode, u0_ode = ode.u0.x - v = TrixiParticles.wrap_v(v0_ode, inlet_system, semi) - u = TrixiParticles.wrap_u(u0_ode, inlet_system, semi) + v = TrixiParticles.wrap_v(v0_ode, boundary_system, semi) + u = TrixiParticles.wrap_u(u0_ode, boundary_system, semi) # ==== Characteristic Variables # `J1 = -sound_speed^2 * (rho - rho_ref) + (p - p_ref)` @@ -82,9 +89,9 @@ # First evaluation # Particles not influenced by the fluid have zero values t1 = 2.0 - TrixiParticles.evaluate_characteristics!(inlet_system, + TrixiParticles.evaluate_characteristics!(boundary_system, v, u, v0_ode, u0_ode, semi, t1) - evaluated_vars1 = inlet_system.characteristics + evaluated_vars1 = boundary_system.characteristics if boundary_zone isa InFlow @test all(isapprox.(evaluated_vars1[1, :], 0.0)) @@ -102,9 +109,9 @@ # Second evaluation # Particles not influenced by the fluid have previous values t2 = 3.0 - TrixiParticles.evaluate_characteristics!(inlet_system, + TrixiParticles.evaluate_characteristics!(boundary_system, v, u, v0_ode, u0_ode, semi, t2) - evaluated_vars2 = inlet_system.characteristics + evaluated_vars2 = boundary_system.characteristics if boundary_zone isa InFlow @test all(isapprox.(evaluated_vars2[1, :], 0.0)) diff --git a/test/schemes/boundary/open_boundary/open_boundary.jl b/test/schemes/boundary/open_boundary/open_boundary.jl new file mode 100644 index 000000000..5fe09c703 --- /dev/null +++ b/test/schemes/boundary/open_boundary/open_boundary.jl @@ -0,0 +1,2 @@ +include("characteristic_variables.jl") +include("boundary_zone.jl") diff --git a/test/schemes/schemes.jl b/test/schemes/schemes.jl index c25bbba21..5cf7cd5bd 100644 --- a/test/schemes/schemes.jl +++ b/test/schemes/schemes.jl @@ -1,5 +1,5 @@ include("solid/total_lagrangian_sph/total_lagrangian_sph.jl") include("boundary/dummy_particles/dummy_particles.jl") include("boundary/monaghan_kajtar/monaghan_kajtar.jl") -include("boundary/open_boundary/characteristic_variables.jl") +include("boundary/open_boundary/open_boundary.jl") include("fluid/fluid.jl") diff --git a/test/systems/open_boundary_system.jl b/test/systems/open_boundary_system.jl index d8b48d620..d1abfdb40 100644 --- a/test/systems/open_boundary_system.jl +++ b/test/systems/open_boundary_system.jl @@ -1,212 +1,63 @@ @testset verbose=true "OpenBoundarySPHSystem" begin - @testset verbose=true "Boundary Zone 2D" begin - boundary_zones = [InFlow(), OutFlow()] - particle_spacing = 0.2 - open_boundary_layers = 4 - - point1s = [[0.0, 0.0], [0.5, -0.5], [1.0, 0.5]] - point2s = [[0.0, 1.0], [0.2, 2.0], [2.3, 0.5]] - - @testset "$boundary_zone" for boundary_zone in boundary_zones - @testset "Points $(i)" for i in eachindex(point1s) - plane_size = point2s[i] - point1s[i] - flow_directions = [ - normalize([-plane_size[2], plane_size[1]]), - -normalize([-plane_size[2], plane_size[1]]), - ] - - plane_points = [point1s[i], point2s[i]] - - @testset "Flow Direction $(j)" for j in eachindex(flow_directions) - system = OpenBoundarySPHSystem(plane_points, boundary_zone, 1.0; - flow_direction=flow_directions[j], - particle_spacing, - open_boundary_layers, - density=1.0) - zone_width = open_boundary_layers * - system.initial_condition.particle_spacing - sign_ = (boundary_zone isa InFlow) ? -1 : 1 - - @test point1s[i] == system.zone_origin - @test point2s[i] - system.zone_origin == system.spanning_set[2] - @test sign_ * flow_directions[j] ≈ normalize(system.spanning_set[1]) - @test zone_width ≈ norm(system.spanning_set[1]) - end - end - end - end - - @testset verbose=true "Boundary Zone 3D" begin - boundary_zones = [InFlow(), OutFlow()] - particle_spacing = 0.05 - open_boundary_layers = 4 - - point1s = [ - [0.0, 0.0, 0.0], - [0.3113730847835541, 0.19079485535621643, -0.440864622592926], - ] - point2s = [ - [1.0, 0.0, 0.0], - [-0.10468611121177673, 0.252103328704834, -0.44965094327926636], - ] - point3s = [ - [0.0, 1.0, 0.0], - [0.3113730847835541, 0.25057315826416016, -0.02374829351902008], - ] - - @testset "$boundary_zone" for boundary_zone in boundary_zones - @testset "Points $(i)" for i in eachindex(point1s) - edge1 = point2s[i] - point1s[i] - edge2 = point3s[i] - point1s[i] - - flow_directions = [ - normalize(cross(edge1, edge2)), - -normalize(cross(edge1, edge2)), - ] - - plane_points = [point1s[i], point2s[i], point3s[i]] - - @testset "Flow Direction $(j)" for j in eachindex(flow_directions) - system = OpenBoundarySPHSystem(plane_points, boundary_zone, 1.0; - flow_direction=flow_directions[j], - particle_spacing, - open_boundary_layers, - density=1.0) - zone_width = open_boundary_layers * - system.initial_condition.particle_spacing - sign_ = (boundary_zone isa InFlow) ? -1 : 1 - - @test point1s[i] == system.zone_origin - @test point2s[i] - system.zone_origin == system.spanning_set[2] - @test point3s[i] - system.zone_origin == system.spanning_set[3] - @test sign_ * flow_directions[j] ≈ normalize(system.spanning_set[1]) - @test zone_width ≈ norm(system.spanning_set[1]) - end - end - end - end - - @testset verbose=true "Particle In Boundary Zone 2D" begin - plane_points = [[-0.2, -0.5], [0.3, 0.5]] - plane_size = plane_points[2] - plane_points[1] - - flow_direction = normalize([-plane_size[2], plane_size[1]]) - system = OpenBoundarySPHSystem(plane_points, InFlow(), 1.0; flow_direction, - density=1.0, - particle_spacing=0.1, open_boundary_layers=4) - - query_points = Dict( - "Behind" => ([-1.0, -1.0], false), - "Before" => ([2.0, 2.0], false), - "On Point 1" => (plane_points[1], true), - "On Point 2" => (plane_points[2], true), - "On Point 3" => (system.spanning_set[1] + system.zone_origin, true), - "Closely On Point 1" => (plane_points[1] .+ eps() * flow_direction, false)) - - @testset "$key" for key in keys(query_points) - (particle_position, evaluation) = query_points[key] - - @test evaluation == - TrixiParticles.within_boundary_zone(particle_position, system) - end - end - - @testset verbose=true "Particle In Boundary Zone 3D" begin - point1 = [-0.2, -0.5, 0.0] - point2 = [0.3, 0.5, 0.0] - point3 = [0.13111173850909402, -0.665555869254547, 0.0] - - flow_direction = normalize(cross(point2 - point1, point3 - point1)) - system = OpenBoundarySPHSystem([point1, point2, point3], InFlow(), 1.0; - flow_direction, - density=1.0, particle_spacing=0.1, - open_boundary_layers=4) - - query_points = Dict( - "Behind" => ([-1.0, -1.0, 1.2], false), - "Before" => ([2.0, 2.0, -1.2], false), - "On Point 1" => (point1, true), - "On Point 2" => (point2, true), - "On Point 3" => (point3, true), - "On Point 4" => (system.spanning_set[1] + system.zone_origin, true), - "Closely On Point 1" => (point1 .+ eps() * flow_direction, false)) - - @testset "$key" for key in keys(query_points) - (particle_position, evaluation) = query_points[key] - - @test evaluation == - TrixiParticles.within_boundary_zone(particle_position, system) - end - end - @testset verbose=true "Illegal Inputs" begin - no_rectangular_plane = [[0.2, 0.3, -0.5], [-1.0, 1.5, 0.2], [-0.2, 2.0, -0.5]] - flow_direction = [0.0, 0.0, 1.0] - error_str = "the provided points do not span a rectangular plane" - @test_throws ArgumentError(error_str) OpenBoundarySPHSystem(no_rectangular_plane, - InFlow(), 1.0; - flow_direction, - particle_spacing=0.1, - open_boundary_layers=2, - density=1.0) - - rectangular_plane = [[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0]] - flow_direction = [0.0, 1.0, 0.0] - error_str = "flow direction and normal vector of " * - "InFlow-plane do not correspond" - @test_throws ArgumentError(error_str) OpenBoundarySPHSystem(rectangular_plane, - InFlow(), 1.0; - flow_direction, - particle_spacing=0.1, - open_boundary_layers=2, - density=1.0) - plane = ([0.0, 0.0], [0.0, 1.0]) flow_direction = (1.0, 0.0) + + inflow = InFlow(; plane, particle_spacing=0.1, + flow_direction, density=1.0, open_boundary_layers=2) + error_str = "`reference_velocity` must be either a function mapping " * "each particle's coordinates and time to its velocity or a " * "vector of length 2 for a 2D problem" reference_velocity = 1.0 - @test_throws ArgumentError(error_str) OpenBoundarySPHSystem(plane, InFlow(), 1.0; - flow_direction, - particle_spacing=0.1, - reference_velocity, - open_boundary_layers=2, - density=1.0) + @test_throws ArgumentError(error_str) OpenBoundarySPHSystem(inflow, 1.0; + reference_velocity) error_str = "`reference_pressure` must be either a function mapping " * "each particle's coordinates and time to its pressure or a scalar" reference_pressure = [1.0, 1.0] - @test_throws ArgumentError(error_str) OpenBoundarySPHSystem(plane, InFlow(), 1.0; - flow_direction, - particle_spacing=0.1, - reference_pressure, - open_boundary_layers=2, - density=1.0) + @test_throws ArgumentError(error_str) OpenBoundarySPHSystem(inflow, 1.0; + reference_pressure) error_str = "`reference_density` must be either a function mapping " * "each particle's coordinates and time to its density or a scalar" reference_density = [1.0, 1.0] - @test_throws ArgumentError(error_str) OpenBoundarySPHSystem(plane, InFlow(), 1.0; - flow_direction, - particle_spacing=0.1, - reference_density, - open_boundary_layers=2, - density=1.0) + @test_throws ArgumentError(error_str) OpenBoundarySPHSystem(inflow, 1.0; + reference_density) end @testset "show" begin - system = OpenBoundarySPHSystem(([0.0, 0.0], [0.0, 1.0]), InFlow(), 1.0; - flow_direction=(1.0, 0.0), density=1.0, - particle_spacing=0.05, open_boundary_layers=4) + inflow = InFlow(; plane=([0.0, 0.0], [0.0, 1.0]), particle_spacing=0.05, + flow_direction=(1.0, 0.0), density=1.0, open_boundary_layers=4) + system = OpenBoundarySPHSystem(inflow, 1.0) + + show_compact = "OpenBoundarySPHSystem{2}(InFlow) with 80 particles" + @test repr(system) == show_compact + show_box = """ + ┌──────────────────────────────────────────────────────────────────────────────────────────────────┐ + │ OpenBoundarySPHSystem{2} │ + │ ════════════════════════ │ + │ #particles: ………………………………………………… 80 │ + │ boundary: ……………………………………………………… InFlow │ + │ flow direction: ……………………………………… [1.0, 0.0] │ + │ prescribed velocity: ………………………… constant_vector │ + │ prescribed pressure: ………………………… constant_scalar │ + │ prescribed density: …………………………… constant_scalar │ + │ width: ……………………………………………………………… 0.2 │ + └──────────────────────────────────────────────────────────────────────────────────────────────────┘""" + @test repr("text/plain", system) == show_box + + outflow = OutFlow(; plane=([0.0, 0.0], [0.0, 1.0]), particle_spacing=0.05, + flow_direction=(1.0, 0.0), density=1.0, open_boundary_layers=4) + system = OpenBoundarySPHSystem(outflow, 1.0) - show_compact = "OpenBoundarySPHSystem{2}(InFlow()) with 80 particles" + show_compact = "OpenBoundarySPHSystem{2}(OutFlow) with 80 particles" @test repr(system) == show_compact show_box = """ ┌──────────────────────────────────────────────────────────────────────────────────────────────────┐ │ OpenBoundarySPHSystem{2} │ │ ════════════════════════ │ │ #particles: ………………………………………………… 80 │ - │ boundary: ……………………………………………………… InFlow() │ + │ boundary: ……………………………………………………… OutFlow │ │ flow direction: ……………………………………… [1.0, 0.0] │ │ prescribed velocity: ………………………… constant_vector │ │ prescribed pressure: ………………………… constant_scalar │ From 9401be908f1775b58363e09fd45b81d053b96caa Mon Sep 17 00:00:00 2001 From: LasNikas Date: Mon, 27 May 2024 13:17:29 +0200 Subject: [PATCH 067/107] add docs --- .../boundary/open_boundary/boundary_zones.jl | 163 ++++++++++++++---- src/schemes/boundary/open_boundary/system.jl | 24 --- .../boundary/open_boundary/boundary_zone.jl | 18 +- 3 files changed, 141 insertions(+), 64 deletions(-) diff --git a/src/schemes/boundary/open_boundary/boundary_zones.jl b/src/schemes/boundary/open_boundary/boundary_zones.jl index 1d6db80ee..cc8366471 100644 --- a/src/schemes/boundary/open_boundary/boundary_zones.jl +++ b/src/schemes/boundary/open_boundary/boundary_zones.jl @@ -1,5 +1,7 @@ """ - InFlow + InFlow(; plane, flow_direction, density, particle_spacing, + initial_condition=nothing, extrude_geometry=nothing, + open_boundary_layers::Integer=0) Inflow boundary zone for [`OpenBoundarySPHSystem`](@ref) @@ -8,9 +10,35 @@ Inflow boundary zone for [`OpenBoundarySPHSystem`](@ref) The points must either span a rectangular plane in 3D or a line in 2D. - `flow_direction`: Vector defining the flow direction. - `open_boundary_layers`: Number of particle layers in upstream direction. -- `initial_condition`: TODO -- `particle_spacing`: TODO -- `density`: TODO +- `particle_spacing`: The spacing between the particles (see [`InitialCondition`](@ref)). +- `density`: Particle density (see [`InitialCondition`](@ref)). +- `initial_condition=nothing`: `InitialCondition` for boundary zone (optional). + Particles outside the boundary zone will be removed. +- `extrude_geometry=nothing`: Extrude a geometry inside the boundary zone (optional). + For further information see [`extrude_geometry`](@ref). + +# Examples +```julia +# 2D +plane_points = ([0.0, 0.0], [0.0, 1.0]) +flow_direction=[1.0, 0.0] + +inflow = InFlow(; plane=plane_points, particle_spacing=0.1, flow_direction, density=1.0, + open_boundary_layers=4) + +# 3D +plane_points = ([0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0]) +flow_direction=[0.0, 0.0, 1.0] + +inflow = InFlow(; plane=plane_points, particle_spacing=0.1, flow_direction, density=1.0, + open_boundary_layers=4) + +# 3D particles sampled as cylinder +circle = SphereShape(0.1, 0.5, (0.5, 0.5), 1.0, sphere_type=RoundSphere()) + +inflow = InFlow(; plane=plane_points, particle_spacing=0.1, flow_direction, density=1.0, + extrude_geometry=circle, open_boundary_layers=4) +``` """ struct InFlow{NDIMS, IC, S, ZO, ZW, FD} initial_condition :: IC @@ -19,8 +47,8 @@ struct InFlow{NDIMS, IC, S, ZO, ZW, FD} zone_width :: ZW flow_direction :: FD - function InFlow(; plane=nothing, flow_direction, density=nothing, - particle_spacing=nothing, initial_condition=nothing, + function InFlow(; plane, flow_direction, density, particle_spacing, + initial_condition=nothing, extrude_geometry=nothing, open_boundary_layers::Integer=0) if open_boundary_layers < sqrt(eps()) throw(ArgumentError("`open_boundary_layers` must be positive and greater than zero")) @@ -29,11 +57,18 @@ struct InFlow{NDIMS, IC, S, ZO, ZW, FD} # Unit vector pointing in downstream direction. flow_direction_ = normalize(SVector(flow_direction...)) - if isnothing(initial_condition) - # Sample particles in boundary zone. - initial_condition = extrude_geometry(plane; particle_spacing, density, - direction=-flow_direction_, - n_extrude=open_boundary_layers) + # Sample particles in boundary zone. + if isnothing(initial_condition) && isnothing(extrude_geometry) + initial_condition = TrixiParticles.extrude_geometry(plane; particle_spacing, + density, + direction=-flow_direction_, + n_extrude=open_boundary_layers) + elseif !isnothing(extrude_geometry) + initial_condition = TrixiParticles.extrude_geometry(extrude_geometry; + particle_spacing, + density, + direction=-flow_direction_, + n_extrude=open_boundary_layers) end NDIMS = ndims(initial_condition) @@ -58,27 +93,58 @@ struct InFlow{NDIMS, IC, S, ZO, ZW, FD} spanning_set_ = reinterpret(reshape, SVector{NDIMS, ELTYPE}, spanning_set) - return new{NDIMS, typeof(initial_condition), - typeof(spanning_set_), typeof(zone_origin), typeof(zone_width), - typeof(flow_direction_)}(initial_condition, spanning_set_, zone_origin, - zone_width, flow_direction_) + # Remove paricles outside the boundary zone. + # This check is only necessary when custom `initial_condition` are passed. + ic = remove_outside_particles(initial_condition, spanning_set_, zone_origin) + + return new{NDIMS, typeof(ic), typeof(spanning_set_), typeof(zone_origin), + typeof(zone_width), + typeof(flow_direction_)}(ic, spanning_set_, zone_origin, zone_width, + flow_direction_) end end """ - OutFlow + OutFlow(; plane, flow_direction, density, particle_spacing, + initial_condition=nothing, extrude_geometry=nothing, + open_boundary_layers::Integer=0) Outflow boundary zone for [`OpenBoundarySPHSystem`](@ref) - # Keywords - `plane`: Points defining the boundary zones front plane. The points must either span a rectangular plane in 3D or a line in 2D. - `flow_direction`: Vector defining the flow direction. - `open_boundary_layers`: Number of particle layers in upstream direction. -- `initial_condition`: TODO -- `particle_spacing`: TODO -- `density`: TODO +- `particle_spacing`: The spacing between the particles (see [`InitialCondition`](@ref)). +- `density`: Particle density (see [`InitialCondition`](@ref)). +- `initial_condition=nothing`: `InitialCondition` for boundary zone (optional). + Particles outside the boundary zone will be removed. +- `extrude_geometry=nothing`: Extrude a geometry inside the boundary zone (optional). + For further information see [`extrude_geometry`](@ref). + +# Examples +```julia +# 2D +plane_points = ([0.0, 0.0], [0.0, 1.0]) +flow_direction = [1.0, 0.0] + +outflow = OutFlow(; plane=plane_points, particle_spacing=0.1, flow_direction, density=1.0, + open_boundary_layers=4) + +# 3D +plane_points = ([0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0]) +flow_direction = [0.0, 0.0, 1.0] + +outflow = OutFlow(; plane=plane_points, particle_spacing=0.1, flow_direction, density=1.0, + open_boundary_layers=4) + +# 3D particles sampled as cylinder +circle = SphereShape(0.1, 0.5, (0.5, 0.5), 1.0, sphere_type=RoundSphere()) + +outflow = OutFlow(; plane=plane_points, particle_spacing=0.1, flow_direction, density=1.0, + extrude_geometry=circle, open_boundary_layers=4) +``` """ struct OutFlow{NDIMS, IC, S, ZO, ZW, FD} initial_condition :: IC @@ -87,8 +153,8 @@ struct OutFlow{NDIMS, IC, S, ZO, ZW, FD} zone_width :: ZW flow_direction :: FD - function OutFlow(; plane=nothing, flow_direction, density=nothing, - particle_spacing=nothing, initial_condition=nothing, + function OutFlow(; plane, flow_direction, density, particle_spacing, + initial_condition=nothing, extrude_geometry=nothing, open_boundary_layers::Integer=0) if open_boundary_layers < sqrt(eps()) throw(ArgumentError("`open_boundary_layers` must be positive and greater than zero")) @@ -97,11 +163,17 @@ struct OutFlow{NDIMS, IC, S, ZO, ZW, FD} # Unit vector pointing in downstream direction. flow_direction_ = normalize(SVector(flow_direction...)) - if isnothing(initial_condition) - # Sample particles in boundary zone. - initial_condition = extrude_geometry(plane; particle_spacing, - direction=flow_direction_, density, - n_extrude=open_boundary_layers) + # Sample particles in boundary zone. + if isnothing(initial_condition) && isnothing(extrude_geometry) + initial_condition = TrixiParticles.extrude_geometry(plane; particle_spacing, + density, + direction=flow_direction_, + n_extrude=open_boundary_layers) + elseif !isnothing(extrude_geometry) + initial_condition = TrixiParticles.extrude_geometry(extrude_geometry; + particle_spacing, density, + direction=-flow_direction_, + n_extrude=open_boundary_layers) end NDIMS = ndims(initial_condition) @@ -126,10 +198,14 @@ struct OutFlow{NDIMS, IC, S, ZO, ZW, FD} spanning_set_ = reinterpret(reshape, SVector{NDIMS, ELTYPE}, spanning_set) - return new{NDIMS, typeof(initial_condition), - typeof(spanning_set_), typeof(zone_origin), typeof(zone_width), - typeof(flow_direction_)}(initial_condition, spanning_set_, zone_origin, - zone_width, flow_direction_) + # Remove paricles outside the boundary zone. + # This check is only necessary when custom `initial_condition` are passed. + ic = remove_outside_particles(initial_condition, spanning_set_, zone_origin) + + return new{NDIMS, typeof(ic), typeof(spanning_set_), typeof(zone_origin), + typeof(zone_width), + typeof(flow_direction_)}(ic, spanning_set_, zone_origin, zone_width, + flow_direction_) end end @@ -172,3 +248,28 @@ function spanning_vectors(plane_points::NTuple{3}, zone_width) return hcat(c, edge1, edge2) end + +function remove_outside_particles(initial_condition, spanning_set, zone_origin) + (; coordinates, density, particle_spacing) = initial_condition + + in_zone = trues(nparticles(initial_condition)) + + for particle in eachparticle(initial_condition) + current_position = current_coords(coordinates, initial_condition, particle) + particle_position = current_position - zone_origin + + for dim in 1:ndims(initial_condition) + span_dim = spanning_set[dim] + # Checks whether the projection of the particle position + # falls within the range of the zone. + if !(0 <= dot(particle_position, span_dim) <= dot(span_dim, span_dim)) + + # Particle is not in boundary zone. + in_zone[particle] = false + end + end + end + + return InitialCondition(; coordinates=coordinates[:, in_zone], density=first(density), + particle_spacing) +end diff --git a/src/schemes/boundary/open_boundary/system.jl b/src/schemes/boundary/open_boundary/system.jl index 805a16d9b..166909767 100644 --- a/src/schemes/boundary/open_boundary/system.jl +++ b/src/schemes/boundary/open_boundary/system.jl @@ -30,30 +30,6 @@ about the method see [Open Boundary System](@ref open_boundary). and time to its density, a vector holding the density of each particle, or a scalar for a constant density over all particles. Density is constant zero by default. - -# Examples -```julia -# 2D inflow -plane_points = ([0.0, 0.0], [0.0, 1.0]) -flow_direction=[1.0, 0.0] - -system = OpenBoundarySPHSystem(plane_points, InFlow(), 10.0; particle_spacing=0.1, - open_boundary_layers=4, density=1.0, flow_direction) - -# 3D outflow -plane_points = ([0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0]) -flow_direction=[0.0, 0.0, 1.0] - -system = OpenBoundarySPHSystem(plane_points, OutFlow(), 10.0; particle_spacing=0.1, - open_boundary_layers=4, density=1.0, flow_direction) - -# 3D particles sampled as cylinder -circle = SphereShape(0.1, 0.5, (0.5, 0.5), 1.0, sphere_type=RoundSphere()) - -system = OpenBoundarySPHSystem(plane_points, InFlow(), 10.0; particle_spacing=0.1, - sample_geometry=circle, - open_boundary_layers=4, density=1.0, flow_direction) -``` """ struct OpenBoundarySPHSystem{BZ, NDIMS, ELTYPE <: Real, IC, ARRAY1D, ARRAY2D, RV, RP, RD, B} <: System{NDIMS} diff --git a/test/schemes/boundary/open_boundary/boundary_zone.jl b/test/schemes/boundary/open_boundary/boundary_zone.jl index 58dd79783..35b1076c3 100644 --- a/test/schemes/boundary/open_boundary/boundary_zone.jl +++ b/test/schemes/boundary/open_boundary/boundary_zone.jl @@ -14,7 +14,7 @@ flow_directions = [ normalize([-plane_size[2], plane_size[1]]), - -normalize([-plane_size[2], plane_size[1]]) + -normalize([-plane_size[2], plane_size[1]]), ] @testset "Flow Direction $(j)" for j in eachindex(flow_directions) @@ -27,7 +27,7 @@ boundary_zones = [ inflow, - outflow + outflow, ] @testset "$boundary_zone" for boundary_zone in boundary_zones @@ -52,15 +52,15 @@ plane_points_1 = [ [0.0, 0.0, 0.0], - [0.3113730847835541, 0.19079485535621643, -0.440864622592926] + [0.3113730847835541, 0.19079485535621643, -0.440864622592926], ] plane_points_2 = [ [1.0, 0.0, 0.0], - [-0.10468611121177673, 0.252103328704834, -0.44965094327926636] + [-0.10468611121177673, 0.252103328704834, -0.44965094327926636], ] plane_points_3 = [ [0.0, 1.0, 0.0], - [0.3113730847835541, 0.25057315826416016, -0.02374829351902008] + [0.3113730847835541, 0.25057315826416016, -0.02374829351902008], ] @testset "Points $(i)" for i in eachindex(plane_points_1) @@ -73,7 +73,7 @@ flow_directions = [ normalize(cross(edge1, edge2)), - -normalize(cross(edge1, edge2)) + -normalize(cross(edge1, edge2)), ] @testset "Flow Direction $(j)" for j in eachindex(flow_directions) @@ -86,7 +86,7 @@ boundary_zones = [ inflow, - outflow + outflow, ] @testset "$boundary_zone" for boundary_zone in boundary_zones @@ -120,7 +120,7 @@ boundary_zones = [ inflow, - outflow + outflow, ] @testset "$(nameof(typeof(boundary_zone)))" for boundary_zone in boundary_zones @@ -161,7 +161,7 @@ boundary_zones = [ inflow, - outflow + outflow, ] @testset "$(nameof(typeof(boundary_zone)))" for boundary_zone in boundary_zones From 1533a913b4d1e99655b3c3d5b08ecc18817803eb Mon Sep 17 00:00:00 2001 From: LasNikas Date: Mon, 27 May 2024 13:20:52 +0200 Subject: [PATCH 068/107] rename function --- src/schemes/boundary/open_boundary/system.jl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/schemes/boundary/open_boundary/system.jl b/src/schemes/boundary/open_boundary/system.jl index 9bd0af42d..f590d22d2 100644 --- a/src/schemes/boundary/open_boundary/system.jl +++ b/src/schemes/boundary/open_boundary/system.jl @@ -415,7 +415,7 @@ end (; spanning_set) = boundary_zone # Activate a new particle in simulation domain - transfer_quantities!(fluid_system, system, particle, v_fluid, u_fluid, v, u) + transfer_particle!(fluid_system, system, particle, v_fluid, u_fluid, v, u) # Reset position of boundary particle for dim in 1:ndims(system) @@ -429,7 +429,7 @@ end @inline function transform_particle!(fluid_system::FluidSystem, system, boundary_zone, particle, v, u, v_fluid, u_fluid) # Activate particle in boundary zone - transfer_quantities!(system, fluid_system, particle, v, u, v_fluid, u_fluid) + transfer_particle!(system, fluid_system, particle, v, u, v_fluid, u_fluid) # Deactivate particle in interior domain deactivate_particle!(fluid_system, particle, u_fluid) @@ -437,7 +437,7 @@ end return fluid_system end -@inline function transfer_quantities!(system_new, system_old, particle_old, +@inline function transfer_particle!(system_new, system_old, particle_old, v_new, u_new, v_old, u_old) particle_new = activate_next_particle(system_new) From a9e91ce995440c970c54a424317f13de9928d4b7 Mon Sep 17 00:00:00 2001 From: LasNikas Date: Mon, 27 May 2024 13:28:50 +0200 Subject: [PATCH 069/107] apply formatter --- src/schemes/boundary/open_boundary/system.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/schemes/boundary/open_boundary/system.jl b/src/schemes/boundary/open_boundary/system.jl index f590d22d2..aa2cdec0d 100644 --- a/src/schemes/boundary/open_boundary/system.jl +++ b/src/schemes/boundary/open_boundary/system.jl @@ -438,7 +438,7 @@ end end @inline function transfer_particle!(system_new, system_old, particle_old, - v_new, u_new, v_old, u_old) + v_new, u_new, v_old, u_old) particle_new = activate_next_particle(system_new) # Transfer densities From 38f50341cdcc52e99b46161d707a59a70ffd4f1f Mon Sep 17 00:00:00 2001 From: LasNikas Date: Mon, 27 May 2024 14:16:47 +0200 Subject: [PATCH 070/107] fix tests --- test/general/buffer.jl | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/test/general/buffer.jl b/test/general/buffer.jl index 732712a52..f5bb66359 100644 --- a/test/general/buffer.jl +++ b/test/general/buffer.jl @@ -1,10 +1,8 @@ @testset verbose=true "SystemBuffer" begin - system = OpenBoundarySPHSystem(([0.0, 0.0], [0.0, 1.0]), InFlow(), 1.0; - flow_direction=[1.0, 0.0], particle_spacing=0.2, - open_boundary_layers=2, density=1.0) - system_buffer = OpenBoundarySPHSystem(([0.0, 0.0], [0.0, 1.0]), InFlow(), 1.0; - flow_direction=[1.0, 0.0], particle_spacing=0.2, - open_boundary_layers=2, density=1.0, buffer=5) + inflow = InFlow(; plane=([0.0, 0.0], [0.0, 1.0]), particle_spacing=0.2, + open_boundary_layers=2, density=1.0, flow_direction=[1.0, 0.0]) + system = OpenBoundarySPHSystem(inflow, 1.0) + system_buffer = OpenBoundarySPHSystem(inflow, 1.0; buffer=5) n_particles = nparticles(system) From e2930014967c4b414cd36a4d5b4a7d8364e7240e Mon Sep 17 00:00:00 2001 From: LasNikas Date: Mon, 27 May 2024 15:48:16 +0200 Subject: [PATCH 071/107] fix bug in plot recipes --- src/visualization/recipes_plots.jl | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/visualization/recipes_plots.jl b/src/visualization/recipes_plots.jl index a3fb7de7e..d7bd3f9c4 100644 --- a/src/visualization/recipes_plots.jl +++ b/src/visualization/recipes_plots.jl @@ -12,10 +12,9 @@ end RecipesBase.@recipe function f(v_ode, u_ode, semi::Semidiscretization; size=(600, 400)) # Default size systems_data = map(semi.systems) do system - (; initial_condition) = system u = wrap_u(u_ode, system, semi) - coordinates = current_coordinates(u, system) + coordinates = active_coordinates(u, system) x = collect(coordinates[1, :]) y = collect(coordinates[2, :]) @@ -24,8 +23,8 @@ RecipesBase.@recipe function f(v_ode, u_ode, semi::Semidiscretization; particle_spacing = 0.0 end - x_min, y_min = minimum(initial_condition.coordinates, dims=2) .- 0.5particle_spacing - x_max, y_max = maximum(initial_condition.coordinates, dims=2) .+ 0.5particle_spacing + x_min, y_min = minimum(coordinates, dims=2) .- 0.5particle_spacing + x_max, y_max = maximum(coordinates, dims=2) .+ 0.5particle_spacing return (; x, y, x_min, x_max, y_min, y_max, particle_spacing, label=timer_name(system)) From e2dcc01b5bbdedcac7a339eeaaa6d5ed3e66e35d Mon Sep 17 00:00:00 2001 From: LasNikas Date: Mon, 27 May 2024 16:42:32 +0200 Subject: [PATCH 072/107] apply formatter --- src/visualization/recipes_plots.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/src/visualization/recipes_plots.jl b/src/visualization/recipes_plots.jl index d7bd3f9c4..f7e4d5b23 100644 --- a/src/visualization/recipes_plots.jl +++ b/src/visualization/recipes_plots.jl @@ -12,7 +12,6 @@ end RecipesBase.@recipe function f(v_ode, u_ode, semi::Semidiscretization; size=(600, 400)) # Default size systems_data = map(semi.systems) do system - u = wrap_u(u_ode, system, semi) coordinates = active_coordinates(u, system) x = collect(coordinates[1, :]) From 9de2c484c06490ec21034df501e3f176f0046b46 Mon Sep 17 00:00:00 2001 From: LasNikas Date: Mon, 3 Jun 2024 17:34:51 +0200 Subject: [PATCH 073/107] implement suggestions for `boundary_zone.jl` --- .../boundary/open_boundary/boundary_zones.jl | 142 ++++++++++++------ src/schemes/boundary/open_boundary/system.jl | 14 +- src/schemes/schemes.jl | 1 + src/setups/extrude_geometry.jl | 6 +- .../boundary/open_boundary/boundary_zone.jl | 8 +- 5 files changed, 108 insertions(+), 63 deletions(-) diff --git a/src/schemes/boundary/open_boundary/boundary_zones.jl b/src/schemes/boundary/open_boundary/boundary_zones.jl index cc8366471..1621deb0f 100644 --- a/src/schemes/boundary/open_boundary/boundary_zones.jl +++ b/src/schemes/boundary/open_boundary/boundary_zones.jl @@ -1,21 +1,47 @@ -""" +@doc raw""" InFlow(; plane, flow_direction, density, particle_spacing, initial_condition=nothing, extrude_geometry=nothing, - open_boundary_layers::Integer=0) - -Inflow boundary zone for [`OpenBoundarySPHSystem`](@ref) + open_boundary_layers::Integer) + +Inflow boundary zone for [`OpenBoundarySPHSystem`](@ref). + +The specified plane (line in 2D or rectangle in 3D) will be extruded in upstream +direction to create a box for the boundary zone. +There are three ways to specify the actual shape of the inflow: +1. Don't pass `initial_condition` or `extrude_geometry`. The boundary zone box will then + be filled with inflow particles. +2. Pass a 1D shape in 2D or a 2D shape in 3D, which is then extruded in upstream direction + to create the inflow particles. + In 2D, the shape must be either an initial condition with 2D coordinates, which lies + on the line specified by `plane`, or an initial condition with 1D coordinates, which lies + on the line specified by `plane` when a y-coordinate of `0` is added. + In 3D, the shape must be either an initial condition with 3D coordinates, which lies + in the rectangle specified by `plane`, or an initial condition with 2D coordinates, + which lies in the rectangle specified by `plane` when a z-coordinate of `0` is added. + Note that particles outside the boundary zone box will be removed. +3. Pass a 2D initial condition in 2D or a 3D initial condition in 3D, which will be used + for the inflow particles. Note that particles outside the boundary zone box will be removed. # Keywords -- `plane`: Points defining the boundary zones front plane. - The points must either span a rectangular plane in 3D or a line in 2D. +- `plane`: Tuple of points defining a part of the surface of the domain. + The points must either span a line in 2D or a rectangle in 3D. + This line or rectangle is then extruded in upstream direction to obtain + the boundary zone. + In 2D, pass two points ``(A, B)``, so that the interval ``[A, B]`` is + the inflow surface. + In 3D, pass three points ``(A, B, C)``, so that the rectangular inflow surface + is spanned by the vectors ``\widehat{AB}`` and ``\widehat{AC}``. + These two vectors must be orthogonal. - `flow_direction`: Vector defining the flow direction. - `open_boundary_layers`: Number of particle layers in upstream direction. - `particle_spacing`: The spacing between the particles (see [`InitialCondition`](@ref)). - `density`: Particle density (see [`InitialCondition`](@ref)). -- `initial_condition=nothing`: `InitialCondition` for boundary zone (optional). +- `initial_condition=nothing`: `InitialCondition` for the inflow particles. Particles outside the boundary zone will be removed. -- `extrude_geometry=nothing`: Extrude a geometry inside the boundary zone (optional). - For further information see [`extrude_geometry`](@ref). + Do not use together with `extrude_geometry`. +- `extrude_geometry=nothing`: 1D shape in 2D or 2D shape in 3D, which lies on the plane + and is extruded upstream to obtain the inflow particles. + See point 2 above for more details. # Examples ```julia @@ -49,15 +75,15 @@ struct InFlow{NDIMS, IC, S, ZO, ZW, FD} function InFlow(; plane, flow_direction, density, particle_spacing, initial_condition=nothing, extrude_geometry=nothing, - open_boundary_layers::Integer=0) - if open_boundary_layers < sqrt(eps()) + open_boundary_layers::Integer) + if open_boundary_layers <= 0 throw(ArgumentError("`open_boundary_layers` must be positive and greater than zero")) end - # Unit vector pointing in downstream direction. + # Unit vector pointing in downstream direction flow_direction_ = normalize(SVector(flow_direction...)) - # Sample particles in boundary zone. + # Sample particles in boundary zone if isnothing(initial_condition) && isnothing(extrude_geometry) initial_condition = TrixiParticles.extrude_geometry(plane; particle_spacing, density, @@ -76,7 +102,7 @@ struct InFlow{NDIMS, IC, S, ZO, ZW, FD} zone_width = open_boundary_layers * initial_condition.particle_spacing - # Vectors spanning the boundary zone/box. + # Vectors spanning the boundary zone/box spanning_set, zone_origin = calculate_spanning_vectors(plane, zone_width) # First vector of `spanning_vectors` is normal to the inflow plane. @@ -84,17 +110,16 @@ struct InFlow{NDIMS, IC, S, ZO, ZW, FD} dot_ = dot(normalize(spanning_set[:, 1]), flow_direction_) if !isapprox(abs(dot_), 1.0, atol=1e-7) - throw(ArgumentError("flow direction and normal vector of " * - "inflow-plane do not correspond")) + throw(ArgumentError("`flow_direction` is not normal to inflow plane")) else - # Flip the inflow vector correspondingly - spanning_set[:, 1] .*= -dot_ + # Flip the normal vector to point in the opposite direction of `flow_direction` + spanning_set[:, 1] .*= -sign(dot_) end spanning_set_ = reinterpret(reshape, SVector{NDIMS, ELTYPE}, spanning_set) - # Remove paricles outside the boundary zone. - # This check is only necessary when custom `initial_condition` are passed. + # Remove particles outside the boundary zone. + # This check is only necessary when `initial_condition` or `extrude_geometry` are passed. ic = remove_outside_particles(initial_condition, spanning_set_, zone_origin) return new{NDIMS, typeof(ic), typeof(spanning_set_), typeof(zone_origin), @@ -104,24 +129,50 @@ struct InFlow{NDIMS, IC, S, ZO, ZW, FD} end end -""" +@doc raw""" OutFlow(; plane, flow_direction, density, particle_spacing, initial_condition=nothing, extrude_geometry=nothing, - open_boundary_layers::Integer=0) + open_boundary_layers::Integer) Outflow boundary zone for [`OpenBoundarySPHSystem`](@ref) +The specified plane (line in 2D or rectangle in 3D) will be extruded in downstream +direction to create a box for the boundary zone. +There are three ways to specify the actual shape of the outflow: +1. Don't pass `initial_condition` or `extrude_geometry`. The boundary zone box will then + be filled with outflow particles. +2. Pass a 1D shape in 2D or a 2D shape in 3D, which is then extruded in downstream direction + to create the outflow particles. + In 2D, the shape must be either an initial condition with 2D coordinates, which lies + on the line specified by `plane`, or an initial condition with 1D coordinates, which lies + on the line specified by `plane` when a y-coordinate of `0` is added. + In 3D, the shape must be either an initial condition with 3D coordinates, which lies + in the rectangle specified by `plane`, or an initial condition with 2D coordinates, + which lies in the rectangle specified by `plane` when a z-coordinate of `0` is added. + Note that particles outside the boundary zone box will be removed. +3. Pass a 2D initial condition in 2D or a 3D initial condition in 3D, which will be used + for the outflow particles. Note that particles outside the boundary zone box will be removed. + # Keywords -- `plane`: Points defining the boundary zones front plane. - The points must either span a rectangular plane in 3D or a line in 2D. +- `plane`: Tuple of points defining a part of the surface of the domain. + The points must either span a line in 2D or a rectangle in 3D. + This line or rectangle is then extruded in downstream direction to obtain + the boundary zone. + In 2D, pass two points ``(A, B)``, so that the interval ``[A, B]`` is + the outflow surface. + In 3D, pass three points ``(A, B, C)``, so that the rectangular outflow surface + is spanned by the vectors ``\widehat{AB}`` and ``\widehat{AC}``. + These two vectors must be orthogonal. - `flow_direction`: Vector defining the flow direction. -- `open_boundary_layers`: Number of particle layers in upstream direction. +- `open_boundary_layers`: Number of particle layers in downstream direction. - `particle_spacing`: The spacing between the particles (see [`InitialCondition`](@ref)). - `density`: Particle density (see [`InitialCondition`](@ref)). -- `initial_condition=nothing`: `InitialCondition` for boundary zone (optional). - Particles outside the boundary zone will be removed. -- `extrude_geometry=nothing`: Extrude a geometry inside the boundary zone (optional). - For further information see [`extrude_geometry`](@ref). +- `initial_condition=nothing`: `InitialCondition` for the outflow particles. + Particles outside the boundary zone will be removed. + Do not use together with `extrude_geometry`. +- `extrude_geometry=nothing`: 1D shape in 2D or 2D shape in 3D, which lies on the plane + and is extruded downstream to obtain the outflow particles. + See point 2 above for more details. # Examples ```julia @@ -155,15 +206,15 @@ struct OutFlow{NDIMS, IC, S, ZO, ZW, FD} function OutFlow(; plane, flow_direction, density, particle_spacing, initial_condition=nothing, extrude_geometry=nothing, - open_boundary_layers::Integer=0) - if open_boundary_layers < sqrt(eps()) + open_boundary_layers::Integer) + if open_boundary_layers <= 0 throw(ArgumentError("`open_boundary_layers` must be positive and greater than zero")) end - # Unit vector pointing in downstream direction. + # Unit vector pointing in downstream direction flow_direction_ = normalize(SVector(flow_direction...)) - # Sample particles in boundary zone. + # Sample particles in boundary zone if isnothing(initial_condition) && isnothing(extrude_geometry) initial_condition = TrixiParticles.extrude_geometry(plane; particle_spacing, density, @@ -181,7 +232,7 @@ struct OutFlow{NDIMS, IC, S, ZO, ZW, FD} zone_width = open_boundary_layers * initial_condition.particle_spacing - # Vectors spanning the boundary zone/box. + # Vectors spanning the boundary zone/box spanning_set, zone_origin = calculate_spanning_vectors(plane, zone_width) # First vector of `spanning_vectors` is normal to the outflow plane. @@ -189,17 +240,16 @@ struct OutFlow{NDIMS, IC, S, ZO, ZW, FD} dot_ = dot(normalize(spanning_set[:, 1]), flow_direction_) if !isapprox(abs(dot_), 1.0, atol=1e-7) - throw(ArgumentError("flow direction and normal vector of " * - "outflow-plane do not correspond")) + throw(ArgumentError("`flow_direction` is not normal to outflow plane")) else - # Flip the inflow vector correspondingly - spanning_set[:, 1] .*= dot_ + # Flip the normal vector to point in `flow_direction` + spanning_set[:, 1] .*= sign(dot_) end spanning_set_ = reinterpret(reshape, SVector{NDIMS, ELTYPE}, spanning_set) - # Remove paricles outside the boundary zone. - # This check is only necessary when custom `initial_condition` are passed. + # Remove particles outside the boundary zone. + # This check is only necessary when `initial_condition` or `extrude_geometry` are passed. ic = remove_outside_particles(initial_condition, spanning_set_, zone_origin) return new{NDIMS, typeof(ic), typeof(spanning_set_), typeof(zone_origin), @@ -216,20 +266,14 @@ end # end function calculate_spanning_vectors(plane, zone_width) - return spanning_vectors(plane, zone_width), SVector(plane[1]...) -end - -function spanning_vectors(plane_points, zone_width) - - # Convert to tuple - return spanning_vectors(tuple(plane_points...), zone_width) + return spanning_vectors(Tuple(plane), zone_width), SVector(plane[1]...) end function spanning_vectors(plane_points::NTuple{2}, zone_width) plane_size = plane_points[2] - plane_points[1] # Calculate normal vector of plane - b = Vector(normalize([-plane_size[2]; plane_size[1]]) * zone_width) + b = normalize([-plane_size[2], plane_size[1]]) * zone_width return hcat(b, plane_size) end @@ -240,7 +284,7 @@ function spanning_vectors(plane_points::NTuple{3}, zone_width) edge2 = plane_points[3] - plane_points[1] if !isapprox(dot(edge1, edge2), 0.0, atol=1e-7) - throw(ArgumentError("the provided points do not span a rectangular plane")) + throw(ArgumentError("the vectors `AB` and `AC` for the provided points `A`, `B`, `C` must be orthogonal")) end # Calculate normal vector of plane diff --git a/src/schemes/boundary/open_boundary/system.jl b/src/schemes/boundary/open_boundary/system.jl index aa2cdec0d..285593b1f 100644 --- a/src/schemes/boundary/open_boundary/system.jl +++ b/src/schemes/boundary/open_boundary/system.jl @@ -1,12 +1,12 @@ include("boundary_zones.jl") """ - OpenBoundarySPHSystem(plane_points, boundary_zone::Union{InFlow, OutFlow}, - sound_speed; - sample_geometry=plane_points, particle_spacing, - flow_direction, open_boundary_layers::Integer=0, density, - buffer=nothing, reference_velocity=zero(flow_direction), - reference_pressure=0.0, reference_density=density) + OpenBoundarySPHSystem(boundary_zone::Union{InFlow, OutFlow}, sound_speed; + buffer=nothing, + reference_velocity=zeros(ndims(boundary_zone)), + reference_pressure=0.0, + reference_density=first(boundary_zone.initial_condition.density)) + Open boundary system for in- and outflow particles. These open boundaries use the characteristic variables to propagate the appropriate values to the outlet or inlet and has been proposed by Lastiwka et al (2009). For more information @@ -32,7 +32,7 @@ about the method see [Open Boundary System](@ref open_boundary). Density is constant zero by default. """ struct OpenBoundarySPHSystem{BZ, NDIMS, ELTYPE <: Real, IC, ARRAY1D, ARRAY2D, RV, RP, - RD, B} <: System{NDIMS} + RD, B} <: System{NDIMS, IC} initial_condition :: IC mass :: ARRAY1D # Array{ELTYPE, 1}: [particle] density :: ARRAY1D # Array{ELTYPE, 1}: [particle] diff --git a/src/schemes/schemes.jl b/src/schemes/schemes.jl index 9ec89b93b..6f13d7a6a 100644 --- a/src/schemes/schemes.jl +++ b/src/schemes/schemes.jl @@ -1,5 +1,6 @@ # Include all schemes without rhs first. The rhs depends on the systems to define # interactions between the different system types. +# Viscosity requires the open boundary system. include("boundary/open_boundary/system.jl") include("fluid/fluid.jl") include("boundary/boundary.jl") diff --git a/src/setups/extrude_geometry.jl b/src/setups/extrude_geometry.jl index 9b7a62401..82df9aaa3 100644 --- a/src/setups/extrude_geometry.jl +++ b/src/setups/extrude_geometry.jl @@ -8,8 +8,10 @@ Extrude either a line, a plane or a shape along a specific direction. # Arguments - `geometry`: Either particle coordinates or an [`InitialCondition`](@ref) defining a 2D shape to extrude to a 3D volume, or two 2D points - defining a line to extrude to a plane in 2D, or three 3D points defining - a parallelogram to extrude to a parallelepiped. + ``(A, B)`` defining the interval ``[A, B]`` to extrude to a plane + in 2D, or three 3D points ``(A, B, C)`` defining the parallelogram + spanned by the vectors ``\widehat{AB}`` and ``\widehat {AC}`` to extrude + to a parallelepiped. # Keywords - `particle_spacing`: Spacing between the particles. Can be omitted when `geometry` is an diff --git a/test/schemes/boundary/open_boundary/boundary_zone.jl b/test/schemes/boundary/open_boundary/boundary_zone.jl index 35b1076c3..e99dabcd2 100644 --- a/test/schemes/boundary/open_boundary/boundary_zone.jl +++ b/test/schemes/boundary/open_boundary/boundary_zone.jl @@ -188,7 +188,7 @@ no_rectangular_plane = [[0.2, 0.3, -0.5], [-1.0, 1.5, 0.2], [-0.2, 2.0, -0.5]] flow_direction = [0.0, 0.0, 1.0] - error_str = "the provided points do not span a rectangular plane" + error_str = "the vectors `AB` and `AC` for the provided points `A`, `B`, `C` must be orthogonal" @test_throws ArgumentError(error_str) InFlow(; plane=no_rectangular_plane, particle_spacing=0.1, @@ -202,16 +202,14 @@ rectangular_plane = [[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0]] flow_direction = [0.0, 1.0, 0.0] - error_str = "flow direction and normal vector of " * - "inflow-plane do not correspond" + error_str = "`flow_direction` is not normal to inflow plane" @test_throws ArgumentError(error_str) InFlow(; plane=rectangular_plane, particle_spacing=0.1, flow_direction, density=1.0, open_boundary_layers=2) - error_str = "flow direction and normal vector of " * - "outflow-plane do not correspond" + error_str = "`flow_direction` is not normal to outflow plane" @test_throws ArgumentError(error_str) OutFlow(; plane=rectangular_plane, particle_spacing=0.1, From 38c05efd062fd8475d87a34545279f19ae50f847 Mon Sep 17 00:00:00 2001 From: LasNikas Date: Mon, 3 Jun 2024 17:43:07 +0200 Subject: [PATCH 074/107] rename kwarg --- examples/fluid/pipe_flow_2d.jl | 8 +++++--- src/schemes/boundary/open_boundary/system.jl | 8 +++++--- src/schemes/fluid/entropically_damped_sph/system.jl | 6 ++++-- src/schemes/fluid/weakly_compressible_sph/system.jl | 6 ++++-- test/general/buffer.jl | 2 +- 5 files changed, 19 insertions(+), 11 deletions(-) diff --git a/examples/fluid/pipe_flow_2d.jl b/examples/fluid/pipe_flow_2d.jl index 3e744bcb3..52cd437ec 100644 --- a/examples/fluid/pipe_flow_2d.jl +++ b/examples/fluid/pipe_flow_2d.jl @@ -62,7 +62,7 @@ viscosity = ArtificialViscosityMonaghan(; alpha, beta=0.0) fluid_system = WeaklyCompressibleSPHSystem(pipe.fluid, fluid_density_calculator, state_equation, smoothing_kernel, smoothing_length, viscosity=viscosity, - buffer=n_buffer_particles) + buffer_size=n_buffer_particles) # ========================================================================================== # ==== Open Boundary @@ -73,14 +73,16 @@ end inflow = InFlow(; plane=([0.0, 0.0], [0.0, domain_size[2]]), flow_direction, open_boundary_layers, density=fluid_density, particle_spacing) -open_boundary_in = OpenBoundarySPHSystem(inflow, sound_speed; buffer=n_buffer_particles, +open_boundary_in = OpenBoundarySPHSystem(inflow, sound_speed; + buffer_size=n_buffer_particles, reference_pressure=pressure, reference_velocity=velocity_function) outflow = OutFlow(; plane=([domain_size[1], 0.0], [domain_size[1], domain_size[2]]), flow_direction, open_boundary_layers, density=fluid_density, particle_spacing) -open_boundary_out = OpenBoundarySPHSystem(outflow, sound_speed; buffer=n_buffer_particles, +open_boundary_out = OpenBoundarySPHSystem(outflow, sound_speed; + buffer_size=n_buffer_particles, reference_pressure=pressure, reference_velocity=velocity_function) diff --git a/src/schemes/boundary/open_boundary/system.jl b/src/schemes/boundary/open_boundary/system.jl index 285593b1f..03dbb0440 100644 --- a/src/schemes/boundary/open_boundary/system.jl +++ b/src/schemes/boundary/open_boundary/system.jl @@ -17,7 +17,7 @@ about the method see [Open Boundary System](@ref open_boundary). - `sound_speed`: Speed of sound. # Keywords -- `buffer`: Number of buffer particles. +- `buffer_size`: Number of buffer particles. - `reference_velocity`: Reference velocity is either a function mapping each particle's coordinates and time to its velocity, an array where the ``i``-th column holds the velocity of particle ``i`` or, for a constant fluid velocity, @@ -50,13 +50,15 @@ struct OpenBoundarySPHSystem{BZ, NDIMS, ELTYPE <: Real, IC, ARRAY1D, ARRAY2D, RV update_callback_used :: Ref{Bool} function OpenBoundarySPHSystem(boundary_zone::Union{InFlow, OutFlow}, sound_speed; - buffer=nothing, + buffer_size=0, reference_velocity=zeros(ndims(boundary_zone)), reference_pressure=0.0, reference_density=first(boundary_zone.initial_condition.density)) (; initial_condition) = boundary_zone - (buffer ≠ nothing) && (buffer = SystemBuffer(nparticles(initial_condition), buffer)) + buffer = buffer_size > 0 ? + SystemBuffer(nparticles(initial_condition), buffer_size) : nothing + initial_condition = allocate_buffer(initial_condition, buffer) NDIMS = ndims(initial_condition) diff --git a/src/schemes/fluid/entropically_damped_sph/system.jl b/src/schemes/fluid/entropically_damped_sph/system.jl index 5b6abff4d..dfab783b2 100644 --- a/src/schemes/fluid/entropically_damped_sph/system.jl +++ b/src/schemes/fluid/entropically_damped_sph/system.jl @@ -63,8 +63,10 @@ struct EntropicallyDampedSPHSystem{NDIMS, ELTYPE <: Real, IC, M, DC, K, V, alpha=0.5, viscosity=nothing, acceleration=ntuple(_ -> 0.0, ndims(smoothing_kernel)), - source_terms=nothing, buffer=nothing) - (buffer ≠ nothing) && (buffer = SystemBuffer(nparticles(initial_condition), buffer)) + source_terms=nothing, buffer_size=0) + buffer = buffer_size > 0 ? + SystemBuffer(nparticles(initial_condition), buffer_size) : nothing + initial_condition = allocate_buffer(initial_condition, buffer) NDIMS = ndims(initial_condition) diff --git a/src/schemes/fluid/weakly_compressible_sph/system.jl b/src/schemes/fluid/weakly_compressible_sph/system.jl index 79ecd014a..9476b734f 100644 --- a/src/schemes/fluid/weakly_compressible_sph/system.jl +++ b/src/schemes/fluid/weakly_compressible_sph/system.jl @@ -66,13 +66,15 @@ end function WeaklyCompressibleSPHSystem(initial_condition, density_calculator, state_equation, smoothing_kernel, smoothing_length; - pressure_acceleration=nothing, buffer=nothing, + pressure_acceleration=nothing, buffer_size=0, viscosity=nothing, density_diffusion=nothing, acceleration=ntuple(_ -> 0.0, ndims(smoothing_kernel)), correction=nothing, source_terms=nothing, surface_tension=nothing) - (buffer ≠ nothing) && (buffer = SystemBuffer(nparticles(initial_condition), buffer)) + buffer = buffer_size > 0 ? + SystemBuffer(nparticles(initial_condition), buffer_size) : nothing + initial_condition = allocate_buffer(initial_condition, buffer) NDIMS = ndims(initial_condition) diff --git a/test/general/buffer.jl b/test/general/buffer.jl index f5bb66359..8dabd3212 100644 --- a/test/general/buffer.jl +++ b/test/general/buffer.jl @@ -2,7 +2,7 @@ inflow = InFlow(; plane=([0.0, 0.0], [0.0, 1.0]), particle_spacing=0.2, open_boundary_layers=2, density=1.0, flow_direction=[1.0, 0.0]) system = OpenBoundarySPHSystem(inflow, 1.0) - system_buffer = OpenBoundarySPHSystem(inflow, 1.0; buffer=5) + system_buffer = OpenBoundarySPHSystem(inflow, 1.0; buffer_size=5) n_particles = nparticles(system) From 032e7da11615da57460d4dbd5c20bd1707812e05 Mon Sep 17 00:00:00 2001 From: LasNikas Date: Tue, 4 Jun 2024 13:55:02 +0200 Subject: [PATCH 075/107] implement suggestions --- .../boundary/open_boundary/boundary_zones.jl | 16 +++++++++------- src/schemes/boundary/open_boundary/system.jl | 5 ++++- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/schemes/boundary/open_boundary/boundary_zones.jl b/src/schemes/boundary/open_boundary/boundary_zones.jl index 1621deb0f..353e3433a 100644 --- a/src/schemes/boundary/open_boundary/boundary_zones.jl +++ b/src/schemes/boundary/open_boundary/boundary_zones.jl @@ -6,7 +6,7 @@ Inflow boundary zone for [`OpenBoundarySPHSystem`](@ref). The specified plane (line in 2D or rectangle in 3D) will be extruded in upstream -direction to create a box for the boundary zone. +direction (the direction opposite to `flow_direction`) to create a box for the boundary zone. There are three ways to specify the actual shape of the inflow: 1. Don't pass `initial_condition` or `extrude_geometry`. The boundary zone box will then be filled with inflow particles. @@ -65,6 +65,9 @@ circle = SphereShape(0.1, 0.5, (0.5, 0.5), 1.0, sphere_type=RoundSphere()) inflow = InFlow(; plane=plane_points, particle_spacing=0.1, flow_direction, density=1.0, extrude_geometry=circle, open_boundary_layers=4) ``` + +!!! warning "Experimental Implementation" + This is an experimental feature and may change in any future releases. """ struct InFlow{NDIMS, IC, S, ZO, ZW, FD} initial_condition :: IC @@ -134,10 +137,10 @@ end initial_condition=nothing, extrude_geometry=nothing, open_boundary_layers::Integer) -Outflow boundary zone for [`OpenBoundarySPHSystem`](@ref) +Outflow boundary zone for [`OpenBoundarySPHSystem`](@ref). The specified plane (line in 2D or rectangle in 3D) will be extruded in downstream -direction to create a box for the boundary zone. +direction (the direction in `flow_direction`) to create a box for the boundary zone. There are three ways to specify the actual shape of the outflow: 1. Don't pass `initial_condition` or `extrude_geometry`. The boundary zone box will then be filled with outflow particles. @@ -196,6 +199,9 @@ circle = SphereShape(0.1, 0.5, (0.5, 0.5), 1.0, sphere_type=RoundSphere()) outflow = OutFlow(; plane=plane_points, particle_spacing=0.1, flow_direction, density=1.0, extrude_geometry=circle, open_boundary_layers=4) ``` + +!!! warning "Experimental Implementation" + This is an experimental feature and may change in any future releases. """ struct OutFlow{NDIMS, IC, S, ZO, ZW, FD} initial_condition :: IC @@ -261,10 +267,6 @@ end @inline Base.ndims(::Union{InFlow{NDIMS}, OutFlow{NDIMS}}) where {NDIMS} = NDIMS -# function calculate_spanning_vectors(plane::Shapes, zone_width) -# # TODO: Handle differently -# end - function calculate_spanning_vectors(plane, zone_width) return spanning_vectors(Tuple(plane), zone_width), SVector(plane[1]...) end diff --git a/src/schemes/boundary/open_boundary/system.jl b/src/schemes/boundary/open_boundary/system.jl index 03dbb0440..d5b2239d2 100644 --- a/src/schemes/boundary/open_boundary/system.jl +++ b/src/schemes/boundary/open_boundary/system.jl @@ -2,7 +2,7 @@ include("boundary_zones.jl") """ OpenBoundarySPHSystem(boundary_zone::Union{InFlow, OutFlow}, sound_speed; - buffer=nothing, + buffer_size=0, reference_velocity=zeros(ndims(boundary_zone)), reference_pressure=0.0, reference_density=first(boundary_zone.initial_condition.density)) @@ -30,6 +30,9 @@ about the method see [Open Boundary System](@ref open_boundary). and time to its density, a vector holding the density of each particle, or a scalar for a constant density over all particles. Density is constant zero by default. + +!!! warning "Experimental Implementation" + This is an experimental feature and may change in any future releases. """ struct OpenBoundarySPHSystem{BZ, NDIMS, ELTYPE <: Real, IC, ARRAY1D, ARRAY2D, RV, RP, RD, B} <: System{NDIMS, IC} From e341098aba80ed0ffcd4228e9e5a771ce0310b33 Mon Sep 17 00:00:00 2001 From: LasNikas Date: Wed, 5 Jun 2024 21:34:41 +0200 Subject: [PATCH 076/107] implement suggestions --- .../boundary/open_boundary/boundary_zones.jl | 35 +++++++---- src/schemes/boundary/open_boundary/system.jl | 58 ++++++------------- src/schemes/schemes.jl | 1 + 3 files changed, 44 insertions(+), 50 deletions(-) diff --git a/src/schemes/boundary/open_boundary/boundary_zones.jl b/src/schemes/boundary/open_boundary/boundary_zones.jl index 353e3433a..3286905cb 100644 --- a/src/schemes/boundary/open_boundary/boundary_zones.jl +++ b/src/schemes/boundary/open_boundary/boundary_zones.jl @@ -295,6 +295,30 @@ function spanning_vectors(plane_points::NTuple{3}, zone_width) return hcat(c, edge1, edge2) end +@inline function is_in_boundary_zone(boundary_zone::Union{InFlow, OutFlow}, particle_coords) + (; zone_origin, spanning_set) = boundary_zone + particle_position = particle_coords - zone_origin + + return is_in_boundary_zone(spanning_set, particle_position) +end + +@inline function is_in_boundary_zone(spanning_set::AbstractArray, + particle_position::SVector{NDIMS}) where {NDIMS} + for dim in 1:NDIMS + span_dim = spanning_set[dim] + # Checks whether the projection of the particle position + # falls within the range of the zone + if !(0 <= dot(particle_position, span_dim) <= dot(span_dim, span_dim)) + + # Particle is not in boundary zone + return false + end + end + + # Particle is in boundary zone + return true +end + function remove_outside_particles(initial_condition, spanning_set, zone_origin) (; coordinates, density, particle_spacing) = initial_condition @@ -304,16 +328,7 @@ function remove_outside_particles(initial_condition, spanning_set, zone_origin) current_position = current_coords(coordinates, initial_condition, particle) particle_position = current_position - zone_origin - for dim in 1:ndims(initial_condition) - span_dim = spanning_set[dim] - # Checks whether the projection of the particle position - # falls within the range of the zone. - if !(0 <= dot(particle_position, span_dim) <= dot(span_dim, span_dim)) - - # Particle is not in boundary zone. - in_zone[particle] = false - end - end + in_zone[particle] = is_in_boundary_zone(spanning_set, particle_position) end return InitialCondition(; coordinates=coordinates[:, in_zone], density=first(density), diff --git a/src/schemes/boundary/open_boundary/system.jl b/src/schemes/boundary/open_boundary/system.jl index d5b2239d2..e754cbcc1 100644 --- a/src/schemes/boundary/open_boundary/system.jl +++ b/src/schemes/boundary/open_boundary/system.jl @@ -1,5 +1,3 @@ -include("boundary_zones.jl") - """ OpenBoundarySPHSystem(boundary_zone::Union{InFlow, OutFlow}, sound_speed; buffer_size=0, @@ -9,7 +7,7 @@ include("boundary_zones.jl") Open boundary system for in- and outflow particles. These open boundaries use the characteristic variables to propagate the appropriate values -to the outlet or inlet and has been proposed by Lastiwka et al (2009). For more information +to the outlet or inlet and have been proposed by Lastiwka et al (2009). For more information about the method see [Open Boundary System](@ref open_boundary). # Arguments @@ -29,7 +27,7 @@ about the method see [Open Boundary System](@ref open_boundary). - `reference_density`: Reference density is either a function mapping each particle's coordinates and time to its density, a vector holding the density of each particle, or a scalar for a constant density over all particles. - Density is constant zero by default. + Density is the density of the first particle in the initial condition by default. !!! warning "Experimental Implementation" This is an experimental feature and may change in any future releases. @@ -41,8 +39,8 @@ struct OpenBoundarySPHSystem{BZ, NDIMS, ELTYPE <: Real, IC, ARRAY1D, ARRAY2D, RV density :: ARRAY1D # Array{ELTYPE, 1}: [particle] volume :: ARRAY1D # Array{ELTYPE, 1}: [particle] pressure :: ARRAY1D # Array{ELTYPE, 1}: [particle] - characteristics :: ARRAY2D # Array{ELTYPE, 2}: [characteristics, particle] - previous_characteristics :: ARRAY2D # Array{ELTYPE, 2}: [characteristics, particle] + characteristics :: ARRAY2D # Array{ELTYPE, 2}: [characteristic, particle] + previous_characteristics :: ARRAY2D # Array{ELTYPE, 2}: [characteristic, particle] sound_speed :: ELTYPE boundary_zone :: BZ flow_direction :: SVector{NDIMS, ELTYPE} @@ -160,25 +158,6 @@ end return system.pressure[particle] end -@inline function (boundary_zone::Union{InFlow, OutFlow})(particle_coords) - (; zone_origin, spanning_set) = boundary_zone - particle_position = particle_coords - zone_origin - - for dim in 1:ndims(boundary_zone) - span_dim = spanning_set[dim] - # Checks whether the projection of the particle position - # falls within the range of the zone. - if !(0 <= dot(particle_position, span_dim) <= dot(span_dim, span_dim)) - - # Particle is not in boundary zone. - return false - end - end - - # Particle is in boundary zone. - return true -end - function update_final!(system::OpenBoundarySPHSystem, v, u, v_ode, u_ode, semi, t) if t > 0.0 && !(system.update_callback_used[]) throw(ArgumentError("`UpdateCallback` is required when using `OpenBoundarySPHSystem`")) @@ -282,26 +261,25 @@ function evaluate_characteristics!(system, neighbor_system::FluidSystem, system_coords = current_coordinates(u, system) neighbor_coords = current_coordinates(u_neighbor_system, neighbor_system) - # Loop over all fluid neighbors within the kernel cutoff. + # Loop over all fluid neighbors within the kernel cutoff for_particle_neighbor(system, neighbor_system, system_coords, neighbor_coords, nhs) do particle, neighbor, pos_diff, distance neighbor_position = current_coords(u_neighbor_system, neighbor_system, neighbor) # Determine current and prescribed quantities - rho = particle_density(v_neighbor_system, neighbor_system, neighbor) + rho_b = particle_density(v_neighbor_system, neighbor_system, neighbor) rho_ref = reference_density(neighbor_position, t) - p = particle_pressure(v_neighbor_system, neighbor_system, neighbor) + p_b = particle_pressure(v_neighbor_system, neighbor_system, neighbor) p_ref = reference_pressure(neighbor_position, t) - v_neighbor = current_velocity(v_neighbor_system, neighbor_system, neighbor) + v_b = current_velocity(v_neighbor_system, neighbor_system, neighbor) v_neighbor_ref = reference_velocity(neighbor_position, t) # Determine characteristic variables - density_term = -sound_speed^2 * (rho - rho_ref) - pressure_term = p - p_ref - velocity_term = rho * sound_speed * - (dot(v_neighbor - v_neighbor_ref, flow_direction)) + density_term = -sound_speed^2 * (rho_b - rho_ref) + pressure_term = p_b - p_ref + velocity_term = rho_b * sound_speed * (dot(v_b - v_neighbor_ref, flow_direction)) kernel_ = smoothing_kernel(neighbor_system, distance) @@ -364,17 +342,17 @@ function check_domain!(system, v, u, v_ode, u_ode, semi) # TODO: Is a thread supported version possible? for particle in each_moving_particle(system) foreach_system(semi) do fluid_system - check_fluid_domain!(system, fluid_system, particle, v, u, v_ode, u_ode, semi) + check_domain!(system, fluid_system, particle, v, u, v_ode, u_ode, semi) end end end -function check_fluid_domain!(system, neighbor_system, particle, v, u, v_ode, u_ode, semi) +function check_domain!(system, neighbor_system, particle, v, u, v_ode, u_ode, semi) return system end -function check_fluid_domain!(system, fluid_system::FluidSystem, particle, - v, u, v_ode, u_ode, semi) +function check_domain!(system, fluid_system::FluidSystem, particle, v, u, v_ode, u_ode, + semi) (; boundary_zone) = system particle_coords = current_coords(u, system, particle) @@ -384,8 +362,8 @@ function check_fluid_domain!(system, fluid_system::FluidSystem, particle, neighborhood_search = get_neighborhood_search(system, fluid_system, semi) - # Check if the particle position is outside the boundary zone. - if !boundary_zone(particle_coords) + # Check if the particle position is outside the boundary zone + if !is_in_boundary_zone(boundary_zone, particle_coords) transform_particle!(system, fluid_system, boundary_zone, particle, v, u, v_fluid, u_fluid) end @@ -395,7 +373,7 @@ function check_fluid_domain!(system, fluid_system::FluidSystem, particle, fluid_coords = current_coords(u_fluid, fluid_system, neighbor) # Check if neighbor position is in boundary zone - if boundary_zone(fluid_coords) + if is_in_boundary_zone(boundary_zone, fluid_coords) transform_particle!(fluid_system, system, boundary_zone, neighbor, v, u, v_fluid, u_fluid) end diff --git a/src/schemes/schemes.jl b/src/schemes/schemes.jl index 6f13d7a6a..fadcb240e 100644 --- a/src/schemes/schemes.jl +++ b/src/schemes/schemes.jl @@ -1,6 +1,7 @@ # Include all schemes without rhs first. The rhs depends on the systems to define # interactions between the different system types. # Viscosity requires the open boundary system. +include("boundary/open_boundary/boundary_zones.jl") include("boundary/open_boundary/system.jl") include("fluid/fluid.jl") include("boundary/boundary.jl") From 4aa2a899eb2fa8b9dd1d2f48408363d922457c4a Mon Sep 17 00:00:00 2001 From: LasNikas Date: Wed, 5 Jun 2024 22:46:10 +0200 Subject: [PATCH 077/107] modify `check_domain!` --- src/schemes/boundary/open_boundary/system.jl | 62 +++++++++++++------- 1 file changed, 41 insertions(+), 21 deletions(-) diff --git a/src/schemes/boundary/open_boundary/system.jl b/src/schemes/boundary/open_boundary/system.jl index e754cbcc1..7142ede99 100644 --- a/src/schemes/boundary/open_boundary/system.jl +++ b/src/schemes/boundary/open_boundary/system.jl @@ -1,6 +1,6 @@ """ OpenBoundarySPHSystem(boundary_zone::Union{InFlow, OutFlow}, sound_speed; - buffer_size=0, + buffer_size::Integer=0, reference_velocity=zeros(ndims(boundary_zone)), reference_pressure=0.0, reference_density=first(boundary_zone.initial_condition.density)) @@ -51,14 +51,13 @@ struct OpenBoundarySPHSystem{BZ, NDIMS, ELTYPE <: Real, IC, ARRAY1D, ARRAY2D, RV update_callback_used :: Ref{Bool} function OpenBoundarySPHSystem(boundary_zone::Union{InFlow, OutFlow}, sound_speed; - buffer_size=0, + buffer_size::Integer=0, reference_velocity=zeros(ndims(boundary_zone)), reference_pressure=0.0, reference_density=first(boundary_zone.initial_condition.density)) (; initial_condition) = boundary_zone - buffer = buffer_size > 0 ? - SystemBuffer(nparticles(initial_condition), buffer_size) : nothing + buffer = SystemBuffer(nparticles(initial_condition), buffer_size) initial_condition = allocate_buffer(initial_condition, buffer) @@ -339,40 +338,48 @@ end end function check_domain!(system, v, u, v_ode, u_ode, semi) - # TODO: Is a thread supported version possible? + (; boundary_zone) = system + + # Find next fluid system with a `SystemBuffer` + next_system = next_fluid_system(semi) + + u_fluid = wrap_u(u_ode, next_system, semi) + v_fluid = wrap_v(v_ode, next_system, semi) + for particle in each_moving_particle(system) - foreach_system(semi) do fluid_system - check_domain!(system, fluid_system, particle, v, u, v_ode, u_ode, semi) + particle_coords = current_coords(u, system, particle) + + # Check if the particle position is outside the boundary zone + if !is_in_boundary_zone(boundary_zone, particle_coords) + transform_particle!(system, next_system, boundary_zone, particle, + v, u, v_fluid, u_fluid) end end + + # Check all the other fluid systems + foreach_system(semi) do fluid_system + check_domain!(system, fluid_system, v, u, v_ode, u_ode, semi) + end end -function check_domain!(system, neighbor_system, particle, v, u, v_ode, u_ode, semi) +function check_domain!(system, neighbor_system, v, u, v_ode, u_ode, semi) return system end -function check_domain!(system, fluid_system::FluidSystem, particle, v, u, v_ode, u_ode, - semi) +function check_domain!(system, fluid_system::FluidSystem, v, u, v_ode, u_ode, semi) (; boundary_zone) = system - particle_coords = current_coords(u, system, particle) - u_fluid = wrap_u(u_ode, fluid_system, semi) v_fluid = wrap_v(v_ode, fluid_system, semi) neighborhood_search = get_neighborhood_search(system, fluid_system, semi) - # Check if the particle position is outside the boundary zone - if !is_in_boundary_zone(boundary_zone, particle_coords) - transform_particle!(system, fluid_system, boundary_zone, particle, - v, u, v_fluid, u_fluid) - end - - # Check fluid neighbors - for neighbor in PointNeighbors.eachneighbor(particle_coords, neighborhood_search) + # Loop over all pairs of particles and neighbors within the kernel cutoff + for_particle_neighbor(system, fluid_system, u, u_fluid, neighborhood_search, + parallel=false) do particle, neighbor, pos_diff, distance fluid_coords = current_coords(u_fluid, fluid_system, neighbor) - # Check if neighbor position is in boundary zone + # Check if neighboring fluid particle is in boundary zone if is_in_boundary_zone(boundary_zone, fluid_coords) transform_particle!(fluid_system, system, boundary_zone, neighbor, v, u, v_fluid, u_fluid) @@ -484,3 +491,16 @@ end function wrap_reference_function(constant_vector_, ::Val{NDIMS}) where {NDIMS} return constant_vector(coords, t) = SVector{NDIMS}(constant_vector_) end + +@inline function next_fluid_system(semi) + (; systems) = semi + + for system_index in eachindex(systems) + system = systems[system_index] + if system isa FluidSystem && system.buffer isa SystemBuffer + return system + end + end + + return throw(ArgumentError("No `FluidSystem` in `Semidiscretization`")) +end From d23f53ebe7377dc2ca2a6f6200f5ce41d2f049fc Mon Sep 17 00:00:00 2001 From: LasNikas Date: Thu, 6 Jun 2024 09:40:03 +0200 Subject: [PATCH 078/107] add comments and check for fluid system with buffer --- src/general/semidiscretization.jl | 3 +++ src/schemes/boundary/open_boundary/system.jl | 16 +++++++++------- .../fluid/entropically_damped_sph/system.jl | 10 ++++++---- .../fluid/weakly_compressible_sph/system.jl | 10 +++++++--- 4 files changed, 25 insertions(+), 14 deletions(-) diff --git a/src/general/semidiscretization.jl b/src/general/semidiscretization.jl index 0cbfdb447..ba9e18fa1 100644 --- a/src/general/semidiscretization.jl +++ b/src/general/semidiscretization.jl @@ -808,3 +808,6 @@ function check_configuration(system::TotalLagrangianSPHSystem, systems) "`ContinuityDensity` is not yet supported for a `TotalLagrangianSPHSystem`")) end end + +# Check if a fluid system with `SystemBuffer` exists +check_configuration(system::OpenBoundarySPHSystem, systems) = next_fluid_system(systems) diff --git a/src/schemes/boundary/open_boundary/system.jl b/src/schemes/boundary/open_boundary/system.jl index 7142ede99..152d6a16a 100644 --- a/src/schemes/boundary/open_boundary/system.jl +++ b/src/schemes/boundary/open_boundary/system.jl @@ -167,13 +167,14 @@ function update_final!(system::OpenBoundarySPHSystem, v, u, v_ode, u_ode, semi, semi, t) end -update_open_boundary_eachstep!(system, v_ode, u_ode, semi, t) = system - +# This function is called by the `UpdateCallback`, as the integrator arrray might be modified function update_open_boundary_eachstep!(system::OpenBoundarySPHSystem, v_ode, u_ode, semi, t) u = wrap_u(u_ode, system, semi) v = wrap_v(v_ode, system, semi) + # Update density, pressure and velocity depending on the characteristic variables. + # See eq. 13-15 in Lastiwka (2009) https://doi.org/10.1002/fld.1971 @trixi_timeit timer() "update quantities" update_quantities!(system, v, u, t) @trixi_timeit timer() "check domain" check_domain!(system, v, u, v_ode, u_ode, semi) @@ -183,6 +184,8 @@ function update_open_boundary_eachstep!(system::OpenBoundarySPHSystem, v_ode, u_ end end +update_open_boundary_eachstep!(system, v_ode, u_ode, semi, t) = system + # ==== Characteristics # J1: Associated with convection and entropy and propagates at flow velocity. # J2: Propagates downstream to the local flow @@ -207,7 +210,7 @@ function evaluate_characteristics!(system, v, u, v_ode, u_ode, semi, t) # Only some of the in-/outlet particles are in the influence of the fluid particles. # Thus, we find the characteristics for the particle which are outside the influence # using the average of the values of the previous time step. - # Negi (2020) https://doi.org/10.1016/j.cma.2020.113119 + # See eq. 27 in Negi (2020) https://doi.org/10.1016/j.cma.2020.113119 @threaded for particle in each_moving_particle(system) # Particle is outside of the influence of fluid particles @@ -341,7 +344,7 @@ function check_domain!(system, v, u, v_ode, u_ode, semi) (; boundary_zone) = system # Find next fluid system with a `SystemBuffer` - next_system = next_fluid_system(semi) + next_system = next_fluid_system(semi.systems) u_fluid = wrap_u(u_ode, next_system, semi) v_fluid = wrap_v(v_ode, next_system, semi) @@ -492,8 +495,7 @@ function wrap_reference_function(constant_vector_, ::Val{NDIMS}) where {NDIMS} return constant_vector(coords, t) = SVector{NDIMS}(constant_vector_) end -@inline function next_fluid_system(semi) - (; systems) = semi +@inline function next_fluid_system(systems) for system_index in eachindex(systems) system = systems[system_index] @@ -502,5 +504,5 @@ end end end - return throw(ArgumentError("No `FluidSystem` in `Semidiscretization`")) + return throw(ArgumentError("When simulating with `OpenBoundarySPHSystem`, a `FluidSystem` with a `SystemBuffer` is needed")) end diff --git a/src/schemes/fluid/entropically_damped_sph/system.jl b/src/schemes/fluid/entropically_damped_sph/system.jl index dfab783b2..a787262d0 100644 --- a/src/schemes/fluid/entropically_damped_sph/system.jl +++ b/src/schemes/fluid/entropically_damped_sph/system.jl @@ -4,7 +4,7 @@ pressure_acceleration=inter_particle_averaged_pressure, density_calculator=SummationDensity(), alpha=0.5, viscosity=nothing, - acceleration=ntuple(_ -> 0.0, NDIMS), + acceleration=ntuple(_ -> 0.0, NDIMS), buffer_size=nothing, source_terms=nothing) System for particles of a fluid. @@ -28,6 +28,8 @@ See [Entropically Damped Artificial Compressibility for SPH](@ref edac) for more When set to `nothing`, the pressure acceleration formulation for the corresponding [density calculator](@ref density_calculator) is chosen. - `density_calculator`: [Density calculator](@ref density_calculator) (default: [`SummationDensity`](@ref)) +- `buffer_size`: Number of buffer particles. + This is only needed when simulating with [`OpenBoundarySPHSystem`](@ref). - `source_terms`: Additional source terms for this system. Has to be either `nothing` (by default), or a function of `(coords, velocity, density, pressure)` (which are the quantities of a single particle), returning a `Tuple` @@ -63,9 +65,9 @@ struct EntropicallyDampedSPHSystem{NDIMS, ELTYPE <: Real, IC, M, DC, K, V, alpha=0.5, viscosity=nothing, acceleration=ntuple(_ -> 0.0, ndims(smoothing_kernel)), - source_terms=nothing, buffer_size=0) - buffer = buffer_size > 0 ? - SystemBuffer(nparticles(initial_condition), buffer_size) : nothing + source_terms=nothing, buffer_size=nothing) + buffer = isnothing(buffer_size) ? nothing : + SystemBuffer(nparticles(initial_condition), buffer_size) initial_condition = allocate_buffer(initial_condition, buffer) diff --git a/src/schemes/fluid/weakly_compressible_sph/system.jl b/src/schemes/fluid/weakly_compressible_sph/system.jl index 9476b734f..3627211c1 100644 --- a/src/schemes/fluid/weakly_compressible_sph/system.jl +++ b/src/schemes/fluid/weakly_compressible_sph/system.jl @@ -4,6 +4,7 @@ smoothing_kernel, smoothing_length; viscosity=nothing, density_diffusion=nothing, acceleration=ntuple(_ -> 0.0, NDIMS), + buffer_size=nothing, correction=nothing, source_terms=nothing) System for particles of a fluid. @@ -26,6 +27,8 @@ See [Weakly Compressible SPH](@ref wcsph) for more details on the method. See [`ArtificialViscosityMonaghan`](@ref) or [`ViscosityAdami`](@ref). - `density_diffusion`: Density diffusion terms for this system. See [`DensityDiffusion`](@ref). - `acceleration`: Acceleration vector for the system. (default: zero vector) +- `buffer_size`: Number of buffer particles. + This is only needed when simulating with [`OpenBoundarySPHSystem`](@ref). - `correction`: Correction method used for this system. (default: no correction, see [Corrections](@ref corrections)) - `source_terms`: Additional source terms for this system. Has to be either `nothing` (by default), or a function of `(coords, velocity, density, pressure)` @@ -66,14 +69,15 @@ end function WeaklyCompressibleSPHSystem(initial_condition, density_calculator, state_equation, smoothing_kernel, smoothing_length; - pressure_acceleration=nothing, buffer_size=0, + pressure_acceleration=nothing, + buffer_size=nothing, viscosity=nothing, density_diffusion=nothing, acceleration=ntuple(_ -> 0.0, ndims(smoothing_kernel)), correction=nothing, source_terms=nothing, surface_tension=nothing) - buffer = buffer_size > 0 ? - SystemBuffer(nparticles(initial_condition), buffer_size) : nothing + buffer = isnothing(buffer_size) ? nothing : + SystemBuffer(nparticles(initial_condition), buffer_size) initial_condition = allocate_buffer(initial_condition, buffer) From 6f3ed3e08c75d199c9ffef09c970521b21c4311e Mon Sep 17 00:00:00 2001 From: LasNikas Date: Thu, 6 Jun 2024 09:55:22 +0200 Subject: [PATCH 079/107] modify error message --- src/schemes/boundary/open_boundary/system.jl | 12 +++++++----- test/systems/open_boundary_system.jl | 14 ++++++++++---- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/schemes/boundary/open_boundary/system.jl b/src/schemes/boundary/open_boundary/system.jl index 152d6a16a..48fdb5d01 100644 --- a/src/schemes/boundary/open_boundary/system.jl +++ b/src/schemes/boundary/open_boundary/system.jl @@ -67,22 +67,25 @@ struct OpenBoundarySPHSystem{BZ, NDIMS, ELTYPE <: Real, IC, ARRAY1D, ARRAY2D, RV if !(reference_velocity isa Function || (reference_velocity isa Vector && length(reference_velocity) == NDIMS)) throw(ArgumentError("`reference_velocity` must be either a function mapping " * - "each particle's coordinates and time to its velocity or a " * - "vector of length $NDIMS for a $(NDIMS)D problem")) + "each particle's coordinates and time to its velocity, " * + "an array where the ``i``-th column holds the velocity of particle ``i`` " * + "or, for a constant fluid velocity, a vector of length $NDIMS for a $(NDIMS)D problem holding this velocity")) else reference_velocity_ = wrap_reference_function(reference_velocity, Val(NDIMS)) end if !(reference_pressure isa Function || reference_pressure isa Real) throw(ArgumentError("`reference_pressure` must be either a function mapping " * - "each particle's coordinates and time to its pressure or a scalar")) + "each particle's coordinates and time to its pressure, " * + "a vector holding the pressure of each particle, or a scalar")) else reference_pressure_ = wrap_reference_function(reference_pressure, Val(NDIMS)) end if !(reference_density isa Function || reference_density isa Real) throw(ArgumentError("`reference_density` must be either a function mapping " * - "each particle's coordinates and time to its density or a scalar")) + "each particle's coordinates and time to its density, " * + "a vector holding the density of each particle, or a scalar")) else reference_density_ = wrap_reference_function(reference_density, Val(NDIMS)) end @@ -496,7 +499,6 @@ function wrap_reference_function(constant_vector_, ::Val{NDIMS}) where {NDIMS} end @inline function next_fluid_system(systems) - for system_index in eachindex(systems) system = systems[system_index] if system isa FluidSystem && system.buffer isa SystemBuffer diff --git a/test/systems/open_boundary_system.jl b/test/systems/open_boundary_system.jl index d1abfdb40..c6dbe9cb3 100644 --- a/test/systems/open_boundary_system.jl +++ b/test/systems/open_boundary_system.jl @@ -7,20 +7,26 @@ flow_direction, density=1.0, open_boundary_layers=2) error_str = "`reference_velocity` must be either a function mapping " * - "each particle's coordinates and time to its velocity or a " * - "vector of length 2 for a 2D problem" + "each particle's coordinates and time to its velocity, " * + "an array where the ``i``-th column holds the velocity of particle ``i`` " * + "or, for a constant fluid velocity, a vector of length 2 for a 2D problem holding this velocity" + reference_velocity = 1.0 @test_throws ArgumentError(error_str) OpenBoundarySPHSystem(inflow, 1.0; reference_velocity) error_str = "`reference_pressure` must be either a function mapping " * - "each particle's coordinates and time to its pressure or a scalar" + "each particle's coordinates and time to its pressure, " * + "a vector holding the pressure of each particle, or a scalar" + reference_pressure = [1.0, 1.0] @test_throws ArgumentError(error_str) OpenBoundarySPHSystem(inflow, 1.0; reference_pressure) error_str = "`reference_density` must be either a function mapping " * - "each particle's coordinates and time to its density or a scalar" + "each particle's coordinates and time to its density, " * + "a vector holding the density of each particle, or a scalar" + reference_density = [1.0, 1.0] @test_throws ArgumentError(error_str) OpenBoundarySPHSystem(inflow, 1.0; reference_density) From 39fe9f0d9f0127ca29c31df39cf988626a80b9ad Mon Sep 17 00:00:00 2001 From: LasNikas Date: Thu, 6 Jun 2024 10:22:03 +0200 Subject: [PATCH 080/107] fix tests --- test/schemes/boundary/open_boundary/boundary_zone.jl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/schemes/boundary/open_boundary/boundary_zone.jl b/test/schemes/boundary/open_boundary/boundary_zone.jl index e99dabcd2..2f60e2bd3 100644 --- a/test/schemes/boundary/open_boundary/boundary_zone.jl +++ b/test/schemes/boundary/open_boundary/boundary_zone.jl @@ -137,12 +137,11 @@ "Closely On Point 1" => (plane_points[1] .+ perturb_ * flow_direction, false)) - TrixiParticles.@autoinfiltrate - @testset "$k" for k in keys(query_points) (particle_position, evaluation) = query_points[k] - @test evaluation == boundary_zone(particle_position) + @test evaluation == + TrixiParticles.is_in_boundary_zone(boundary_zone, particle_position) end end end @@ -179,7 +178,8 @@ @testset "$k" for k in keys(query_points) (particle_position, evaluation) = query_points[k] - @test evaluation == boundary_zone(particle_position) + @test evaluation == + TrixiParticles.is_in_boundary_zone(boundary_zone, particle_position) end end end From e1ed3fc1862dafb99bd4a39af13f55e4d85fa8a8 Mon Sep 17 00:00:00 2001 From: LasNikas Date: Thu, 6 Jun 2024 10:40:40 +0200 Subject: [PATCH 081/107] fix `callback_used` --- src/callbacks/density_reinit.jl | 2 +- src/callbacks/post_process.jl | 2 +- src/callbacks/solution_saving.jl | 2 +- src/callbacks/update.jl | 2 +- src/general/semidiscretization.jl | 4 ++-- src/general/system.jl | 2 +- src/schemes/boundary/open_boundary/system.jl | 7 ++++--- src/schemes/boundary/system.jl | 3 ++- src/schemes/solid/total_lagrangian_sph/system.jl | 3 ++- src/visualization/write2vtk.jl | 2 +- .../boundary/open_boundary/characteristic_variables.jl | 1 + 11 files changed, 17 insertions(+), 13 deletions(-) diff --git a/src/callbacks/density_reinit.jl b/src/callbacks/density_reinit.jl index 5c8a7b5e1..74c6fe5c9 100644 --- a/src/callbacks/density_reinit.jl +++ b/src/callbacks/density_reinit.jl @@ -74,7 +74,7 @@ function initialize_reinit_cb!(cb::DensityReinitializationCallback, u, t, integr # Update systems to compute quantities like density and pressure. semi = integrator.p v_ode, u_ode = u.x - update_systems_and_nhs(v_ode, u_ode, semi, t) + update_systems_and_nhs(v_ode, u_ode, semi, t; update_from_callback=true) # Apply the callback. cb(integrator) diff --git a/src/callbacks/post_process.jl b/src/callbacks/post_process.jl index e2e98a2a0..2811f6092 100644 --- a/src/callbacks/post_process.jl +++ b/src/callbacks/post_process.jl @@ -231,7 +231,7 @@ function (pp::PostprocessCallback)(integrator) new_data = false # Update systems to compute quantities like density and pressure - update_systems_and_nhs(v_ode, u_ode, semi, t) + update_systems_and_nhs(v_ode, u_ode, semi, t; update_from_callback=true) foreach_system(semi) do system if system isa BoundarySystem && pp.exclude_boundary diff --git a/src/callbacks/solution_saving.jl b/src/callbacks/solution_saving.jl index 5163199d6..32f85bf4d 100644 --- a/src/callbacks/solution_saving.jl +++ b/src/callbacks/solution_saving.jl @@ -137,7 +137,7 @@ function initialize_save_cb!(solution_callback::SolutionSavingCallback, u, t, in # Update systems to compute quantities like density and pressure semi = integrator.p v_ode, u_ode = u.x - update_systems_and_nhs(v_ode, u_ode, semi, t) + update_systems_and_nhs(v_ode, u_ode, semi, t; update_from_callback=true) # Apply the callback solution_callback(integrator) diff --git a/src/callbacks/update.jl b/src/callbacks/update.jl index b5f85b8fb..3595d5c36 100644 --- a/src/callbacks/update.jl +++ b/src/callbacks/update.jl @@ -78,7 +78,7 @@ function (update_callback!::UpdateCallback)(integrator) # Update quantities that are stored in the systems. These quantities (e.g. pressure) # still have the values from the last stage of the previous step if not updated here. - update_systems_and_nhs(v_ode, u_ode, semi, t) + update_systems_and_nhs(v_ode, u_ode, semi, t; update_from_callback=true) # Other updates might be added here later (e.g. Transport Velocity Formulation). @trixi_timeit timer() "update open boundary" foreach_system(semi) do system diff --git a/src/general/semidiscretization.jl b/src/general/semidiscretization.jl index ba9e18fa1..8c2fe94a6 100644 --- a/src/general/semidiscretization.jl +++ b/src/general/semidiscretization.jl @@ -441,7 +441,7 @@ function kick!(dv_ode, v_ode, u_ode, semi, t) end # Update the systems and neighborhood searches (NHS) for a simulation before calling `interact!` to compute forces -function update_systems_and_nhs(v_ode, u_ode, semi, t) +function update_systems_and_nhs(v_ode, u_ode, semi, t; update_from_callback=false) # First update step before updating the NHS # (for example for writing the current coordinates in the solid system) foreach_system(semi) do system @@ -478,7 +478,7 @@ function update_systems_and_nhs(v_ode, u_ode, semi, t) v = wrap_v(v_ode, system, semi) u = wrap_u(u_ode, system, semi) - update_final!(system, v, u, v_ode, u_ode, semi, t) + update_final!(system, v, u, v_ode, u_ode, semi, t; update_from_callback) end end diff --git a/src/general/system.jl b/src/general/system.jl index 7883991fc..5c937ce80 100644 --- a/src/general/system.jl +++ b/src/general/system.jl @@ -116,6 +116,6 @@ function update_pressure!(system, v, u, v_ode, u_ode, semi, t) return system end -function update_final!(system, v, u, v_ode, u_ode, semi, t) +function update_final!(system, v, u, v_ode, u_ode, semi, t; update_from_callback=false) return system end diff --git a/src/schemes/boundary/open_boundary/system.jl b/src/schemes/boundary/open_boundary/system.jl index 48fdb5d01..2f518ad12 100644 --- a/src/schemes/boundary/open_boundary/system.jl +++ b/src/schemes/boundary/open_boundary/system.jl @@ -160,8 +160,9 @@ end return system.pressure[particle] end -function update_final!(system::OpenBoundarySPHSystem, v, u, v_ode, u_ode, semi, t) - if t > 0.0 && !(system.update_callback_used[]) +function update_final!(system::OpenBoundarySPHSystem, v, u, v_ode, u_ode, semi, t; + update_from_callback=false) + if !update_from_callback && !(system.update_callback_used[]) throw(ArgumentError("`UpdateCallback` is required when using `OpenBoundarySPHSystem`")) end @@ -170,7 +171,7 @@ function update_final!(system::OpenBoundarySPHSystem, v, u, v_ode, u_ode, semi, semi, t) end -# This function is called by the `UpdateCallback`, as the integrator arrray might be modified +# This function is called by the `UpdateCallback`, as the integrator array might be modified function update_open_boundary_eachstep!(system::OpenBoundarySPHSystem, v_ode, u_ode, semi, t) u = wrap_u(u_ode, system, semi) diff --git a/src/schemes/boundary/system.jl b/src/schemes/boundary/system.jl index 0ecc9f69f..73af6a843 100644 --- a/src/schemes/boundary/system.jl +++ b/src/schemes/boundary/system.jl @@ -336,7 +336,8 @@ end # This update depends on the computed quantities of the fluid system and therefore # has to be in `update_final!` after `update_quantities!`. -function update_final!(system::BoundarySPHSystem, v, u, v_ode, u_ode, semi, t) +function update_final!(system::BoundarySPHSystem, v, u, v_ode, u_ode, semi, t; + update_from_callback=false) (; boundary_model) = system update_pressure!(boundary_model, system, v, u, v_ode, u_ode, semi) diff --git a/src/schemes/solid/total_lagrangian_sph/system.jl b/src/schemes/solid/total_lagrangian_sph/system.jl index 4f193c53e..9203425fb 100644 --- a/src/schemes/solid/total_lagrangian_sph/system.jl +++ b/src/schemes/solid/total_lagrangian_sph/system.jl @@ -247,7 +247,8 @@ function update_quantities!(system::TotalLagrangianSPHSystem, v, u, v_ode, u_ode return system end -function update_final!(system::TotalLagrangianSPHSystem, v, u, v_ode, u_ode, semi, t) +function update_final!(system::TotalLagrangianSPHSystem, v, u, v_ode, u_ode, semi, t; + update_from_callback=false) (; boundary_model) = system # Only update boundary model diff --git a/src/visualization/write2vtk.jl b/src/visualization/write2vtk.jl index 2acc4b0df..61f01977f 100644 --- a/src/visualization/write2vtk.jl +++ b/src/visualization/write2vtk.jl @@ -45,7 +45,7 @@ function trixi2vtk(vu_ode, semi, t; iter=nothing, output_directory="out", prefix # Update quantities that are stored in the systems. These quantities (e.g. pressure) # still have the values from the last stage of the previous step if not updated here. - update_systems_and_nhs(v_ode, u_ode, semi, t) + update_systems_and_nhs(v_ode, u_ode, semi, t; update_from_callback=true) filenames = system_names(systems) diff --git a/test/schemes/boundary/open_boundary/characteristic_variables.jl b/test/schemes/boundary/open_boundary/characteristic_variables.jl index da535ce82..206f00781 100644 --- a/test/schemes/boundary/open_boundary/characteristic_variables.jl +++ b/test/schemes/boundary/open_boundary/characteristic_variables.jl @@ -56,6 +56,7 @@ direction=(sign_ * flow_direction)) fluid_system = EntropicallyDampedSPHSystem(fluid, smoothing_kernel, + buffer_size=0, density_calculator=ContinuityDensity(), smoothing_length, sound_speed) From a17161a4b6735015f2a18bae5700a4d7d295b3bc Mon Sep 17 00:00:00 2001 From: LasNikas Date: Thu, 6 Jun 2024 11:01:50 +0200 Subject: [PATCH 082/107] using Measurements --- Project.toml | 3 ++- test/schemes/boundary/open_boundary/boundary_zone.jl | 4 ++-- test/test_util.jl | 1 + 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Project.toml b/Project.toml index ea1bc9aa5..368888741 100644 --- a/Project.toml +++ b/Project.toml @@ -13,6 +13,7 @@ FastPow = "c0e83750-1142-43a8-81cf-6c956b72b4d1" ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210" JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" +Measurements = "eff96d63-e80a-5855-80a2-b1b0885c5ab7" MuladdMacro = "46d2c3a1-f734-5fdb-9937-b9b9aeba4221" PointNeighbors = "1c4d5385-0a27-49de-8e2c-43b175c8985c" Polyester = "f517fe37-dbe3-4b94-8317-1923a5111588" @@ -35,6 +36,7 @@ FastPow = "0.1" ForwardDiff = "0.10" JSON = "0.21" MuladdMacro = "0.2" +PointNeighbors = "0.2" Polyester = "0.7.5" RecipesBase = "1" Reexport = "1" @@ -43,6 +45,5 @@ StaticArrays = "1" StrideArrays = "0.1" TimerOutputs = "0.5" TrixiBase = "0.1" -PointNeighbors = "0.2" WriteVTK = "1" julia = "1.9" diff --git a/test/schemes/boundary/open_boundary/boundary_zone.jl b/test/schemes/boundary/open_boundary/boundary_zone.jl index 2f60e2bd3..05af2df43 100644 --- a/test/schemes/boundary/open_boundary/boundary_zone.jl +++ b/test/schemes/boundary/open_boundary/boundary_zone.jl @@ -141,7 +141,7 @@ (particle_position, evaluation) = query_points[k] @test evaluation == - TrixiParticles.is_in_boundary_zone(boundary_zone, particle_position) + TrixiParticles.is_in_boundary_zone(boundary_zone, particle_position .± eps()) end end end @@ -179,7 +179,7 @@ (particle_position, evaluation) = query_points[k] @test evaluation == - TrixiParticles.is_in_boundary_zone(boundary_zone, particle_position) + TrixiParticles.is_in_boundary_zone(boundary_zone, particle_position .± eps()) end end end diff --git a/test/test_util.jl b/test/test_util.jl index 5937cc68f..f061b32e7 100644 --- a/test/test_util.jl +++ b/test/test_util.jl @@ -7,6 +7,7 @@ using DataFrames: DataFrame using JSON: JSON using QuadGK: quadgk # For integration in smoothing kernel tests using Random: Random # For rectangular patch +using Measurements: ± using Polyester: disable_polyester_threads # For `count_rhs_allocations` """ From fb162a59cc73b573c14004d2701cf841956862e7 Mon Sep 17 00:00:00 2001 From: LasNikas Date: Thu, 6 Jun 2024 11:52:50 +0200 Subject: [PATCH 083/107] fix tests --- Project.toml | 1 - test/Project.toml | 1 + test/schemes/boundary/open_boundary/boundary_zone.jl | 6 ++++-- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Project.toml b/Project.toml index 368888741..25ada5ac1 100644 --- a/Project.toml +++ b/Project.toml @@ -13,7 +13,6 @@ FastPow = "c0e83750-1142-43a8-81cf-6c956b72b4d1" ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210" JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" -Measurements = "eff96d63-e80a-5855-80a2-b1b0885c5ab7" MuladdMacro = "46d2c3a1-f734-5fdb-9937-b9b9aeba4221" PointNeighbors = "1c4d5385-0a27-49de-8e2c-43b175c8985c" Polyester = "f517fe37-dbe3-4b94-8317-1923a5111588" diff --git a/test/Project.toml b/test/Project.toml index ef78271e3..8412db44c 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -6,6 +6,7 @@ GLM = "38e38edf-8417-5370-95a0-9cbb8c7f171a" Glob = "c27321d9-0574-5035-807b-f59d2c89b15c" JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" +Measurements = "eff96d63-e80a-5855-80a2-b1b0885c5ab7" OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed" Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" Polyester = "f517fe37-dbe3-4b94-8317-1923a5111588" diff --git a/test/schemes/boundary/open_boundary/boundary_zone.jl b/test/schemes/boundary/open_boundary/boundary_zone.jl index 05af2df43..41db0a719 100644 --- a/test/schemes/boundary/open_boundary/boundary_zone.jl +++ b/test/schemes/boundary/open_boundary/boundary_zone.jl @@ -141,7 +141,8 @@ (particle_position, evaluation) = query_points[k] @test evaluation == - TrixiParticles.is_in_boundary_zone(boundary_zone, particle_position .± eps()) + TrixiParticles.is_in_boundary_zone(boundary_zone, + particle_position .± eps()) end end end @@ -179,7 +180,8 @@ (particle_position, evaluation) = query_points[k] @test evaluation == - TrixiParticles.is_in_boundary_zone(boundary_zone, particle_position .± eps()) + TrixiParticles.is_in_boundary_zone(boundary_zone, + particle_position .± eps()) end end end From 2dbc8bbde6c9d156f319a7d58fe3c7160072bdd9 Mon Sep 17 00:00:00 2001 From: LasNikas Date: Thu, 6 Jun 2024 12:01:01 +0200 Subject: [PATCH 084/107] sqrt(eps()) --- test/schemes/boundary/open_boundary/boundary_zone.jl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/schemes/boundary/open_boundary/boundary_zone.jl b/test/schemes/boundary/open_boundary/boundary_zone.jl index 41db0a719..8dfb0e1d7 100644 --- a/test/schemes/boundary/open_boundary/boundary_zone.jl +++ b/test/schemes/boundary/open_boundary/boundary_zone.jl @@ -124,7 +124,7 @@ ] @testset "$(nameof(typeof(boundary_zone)))" for boundary_zone in boundary_zones - perturb_ = boundary_zone isa InFlow ? eps() : -eps() + perturb_ = boundary_zone isa InFlow ? sqrt(eps()) : -sqrt(eps()) point_3 = boundary_zone.spanning_set[1] + boundary_zone.zone_origin @@ -142,7 +142,7 @@ @test evaluation == TrixiParticles.is_in_boundary_zone(boundary_zone, - particle_position .± eps()) + particle_position .± sqrt(eps())) end end end @@ -165,7 +165,7 @@ ] @testset "$(nameof(typeof(boundary_zone)))" for boundary_zone in boundary_zones - perturb_ = boundary_zone isa InFlow ? eps() : -eps() + perturb_ = boundary_zone isa InFlow ? sqrt(eps()) : -sqrt(eps()) query_points = Dict( "Behind" => ([-1.0, -1.0, 1.2], false), "Before" => ([2.0, 2.0, -1.2], false), @@ -181,7 +181,7 @@ @test evaluation == TrixiParticles.is_in_boundary_zone(boundary_zone, - particle_position .± eps()) + particle_position .± sqrt(eps())) end end end From 0495ab9a62a2e020b07156d17b430b569cba8c6f Mon Sep 17 00:00:00 2001 From: LasNikas Date: Thu, 6 Jun 2024 12:04:02 +0200 Subject: [PATCH 085/107] fix tests again --- test/schemes/boundary/open_boundary/boundary_zone.jl | 8 ++++---- test/systems/open_boundary_system.jl | 2 ++ 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/test/schemes/boundary/open_boundary/boundary_zone.jl b/test/schemes/boundary/open_boundary/boundary_zone.jl index 8dfb0e1d7..41db0a719 100644 --- a/test/schemes/boundary/open_boundary/boundary_zone.jl +++ b/test/schemes/boundary/open_boundary/boundary_zone.jl @@ -124,7 +124,7 @@ ] @testset "$(nameof(typeof(boundary_zone)))" for boundary_zone in boundary_zones - perturb_ = boundary_zone isa InFlow ? sqrt(eps()) : -sqrt(eps()) + perturb_ = boundary_zone isa InFlow ? eps() : -eps() point_3 = boundary_zone.spanning_set[1] + boundary_zone.zone_origin @@ -142,7 +142,7 @@ @test evaluation == TrixiParticles.is_in_boundary_zone(boundary_zone, - particle_position .± sqrt(eps())) + particle_position .± eps()) end end end @@ -165,7 +165,7 @@ ] @testset "$(nameof(typeof(boundary_zone)))" for boundary_zone in boundary_zones - perturb_ = boundary_zone isa InFlow ? sqrt(eps()) : -sqrt(eps()) + perturb_ = boundary_zone isa InFlow ? eps() : -eps() query_points = Dict( "Behind" => ([-1.0, -1.0, 1.2], false), "Before" => ([2.0, 2.0, -1.2], false), @@ -181,7 +181,7 @@ @test evaluation == TrixiParticles.is_in_boundary_zone(boundary_zone, - particle_position .± sqrt(eps())) + particle_position .± eps()) end end end diff --git a/test/systems/open_boundary_system.jl b/test/systems/open_boundary_system.jl index c6dbe9cb3..a0f3ba8e7 100644 --- a/test/systems/open_boundary_system.jl +++ b/test/systems/open_boundary_system.jl @@ -43,6 +43,7 @@ │ OpenBoundarySPHSystem{2} │ │ ════════════════════════ │ │ #particles: ………………………………………………… 80 │ + │ #buffer_particles: ……………………………… 0 │ │ boundary: ……………………………………………………… InFlow │ │ flow direction: ……………………………………… [1.0, 0.0] │ │ prescribed velocity: ………………………… constant_vector │ @@ -63,6 +64,7 @@ │ OpenBoundarySPHSystem{2} │ │ ════════════════════════ │ │ #particles: ………………………………………………… 80 │ + │ #buffer_particles: ……………………………… 0 │ │ boundary: ……………………………………………………… OutFlow │ │ flow direction: ……………………………………… [1.0, 0.0] │ │ prescribed velocity: ………………………… constant_vector │ From 079d5e1dfceb2d344f93b48f6d0120a08652ac9b Mon Sep 17 00:00:00 2001 From: LasNikas Date: Thu, 6 Jun 2024 16:27:28 +0200 Subject: [PATCH 086/107] add doc to `boundary.md` --- docs/Project.toml | 2 +- docs/src/systems/boundary.md | 83 ++++++++++++++++++++ docs/src/systems/open_boundary.md | 79 ------------------- src/schemes/boundary/open_boundary/system.jl | 2 +- 4 files changed, 85 insertions(+), 81 deletions(-) delete mode 100644 docs/src/systems/open_boundary.md diff --git a/docs/Project.toml b/docs/Project.toml index 7ada97297..ab1dd531a 100644 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -2,8 +2,8 @@ Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed" TrixiBase = "9a0f1c46-06d5-4909-a5a3-ce25d3fa3284" +TrixiParticles = "66699cd8-9c01-4e9d-a059-b96c86d16b3a" [compat] Documenter = "1" OrdinaryDiffEq = "6" -TrixiBase = "0.1" diff --git a/docs/src/systems/boundary.md b/docs/src/systems/boundary.md index 8b374a71e..889c2098b 100644 --- a/docs/src/systems/boundary.md +++ b/docs/src/systems/boundary.md @@ -234,3 +234,86 @@ Pages = [joinpath("schemes", "boundary", "monaghan_kajtar", "monaghan_kajtar.jl" - Alireza Valizadeh, Joseph J. Monaghan. "A study of solid wall models for weakly compressible SPH." In: Journal of Computational Physics 300 (2015), pages 5–19. [doi: 10.1016/J.JCP.2015.07.033](https://doi.org/10.1016/J.JCP.2015.07.033) + +# [Open Boundary System](@id open_boundary) + +TODO: Make the entire doc nicer and clearer +The difficulty in non-reflecting boundary conditions, also called open boundaries, is to determine +the appropriate boundary values of the exact characteristics of the Euler equations. +Assuming the flow near the boundaries is normal to the boundary +and free of shock waves and significant viscous effects, it can be shown that three characteristics variables exist: + +- ``J_1``, associated with convection of entropy and propagates at flow velocity, +- ``J_2``, downstream-running characteristics, +- ``J_3``, Upstream-running characteristics. + +Giles (1990) derived those variables based on a linearized set of governing equations: +```math +J_1 = -c_s^2 (\rho - \rho_{\text{ref}}) + (p - p_{\text{ref}}) +``` +```math +J_2 = \rho c_s (v - v_{\text{ref}}) + (p - p_{\text{ref}}) +``` +```math +J_3 = - \rho c_s (v - v_{\text{ref}}) + (p - p_{\text{ref}}) +``` +where the subscript "ref" denotes the reference flow near the boundaries, which can be prescribed. + +Specifying the reference variables is **not** equivalent to prescription of ``\rho``, ``v`` and ``p`` +directly, since the perturbation from the reference flow is allowed. + +Lastiwka et al (2009) applied the method of characteristic to SPH and determine the number of variables that should be +**prescribed** at the boundary and the number which should be **propagated** from the fluid domain to the boundary: + +Flow enters the domain through an +- **inflow** boundary: + - Prescribe *downstream*-running characteristics ``J_1`` and ``J_2`` + - Transmit ``J_3`` from the fluid domain (allow ``J_3`` to propagate upstream to the boundary). + +- **outflow** boundary: + - Prescribe *upstream*-running characteristic ``J_3`` + - Transmit ``J_1`` and ``J_2`` from the fluid domain. + +Prescribing is done by simply setting the characteristics to zero. To transmit the characteristics from the fluid +domain, or in other words, to carry the information of the fluid to the boundaries, Negi (2020) use a Shepard Interpolation +```math +f_i = \frac{\sum_j^N f_j W_{ij}}{\sum_j^N W_{ij}}, +``` +where the ``i``th particle is a boundary particle, ``f`` is either ``J_1``, ``J_2`` or ``J_3`` and ``N`` is the set of +neighboring fluid particles. + +To express pressure ``p``, density ``\rho`` and velocity ``v`` as functions of the characteristic variables, the system of equations +from the characteristic variables is inverted and gives +```math + \rho - \rho_{\text{ref}} = \frac{1}{c_s^2} \left( -J_1 + \frac{1}{2} J_2 + \frac{1}{2} J_3 \right), +``` +```math +u - u_{\text{ref}}= \frac{1}{2\rho c_s} \left( J_2 - J_3 \right), +``` +```math +p - p_{\text{ref}} = \frac{1}{2} \left( J_2 + J_3 \right). +``` +Thus, determined ``J_1``, ``J_2`` and ``J_3``, we can easily solve for the actual variables for each particle. + +```@autodocs +Modules = [TrixiParticles] +Pages = [joinpath("schemes", "boundary", "open_boundary", "boundary_zones.jl")] +``` + +```@autodocs +Modules = [TrixiParticles] +Pages = [joinpath("schemes", "boundary", "open_boundary", "system.jl")] +``` + +### References +- M. B. Giles "Nonreflecting boundary conditions for Euler equation calculations". + In: AIAA Journal , Vol. 28, No. 12 pages 2050--2058 + [doi: 10.2514/3.10521](https://doi.org/10.2514/3.10521) +- M. Lastiwka, M. Basa, N. J. Quinlan. + "Permeable and non-reflecting boundary conditions in SPH". + In: International Journal for Numerical Methods in Fluids 61, (2009), pages 709--724. + [doi: 10.1002/fld.1971](https://doi.org/10.1002/fld.1971) +- P. Negi, P. Ramachandran, A. Haftu. + "An improved non-reflecting outlet boundary condition for weakly-compressible SPH". + In: Computer Methods in Applied Mechanics and Engineering 367, (2020), pages 113119. + [doi: 10.1016/j.cma.2020.113119](https://doi.org/10.1016/j.cma.2020.113119) diff --git a/docs/src/systems/open_boundary.md b/docs/src/systems/open_boundary.md deleted file mode 100644 index 7af9fe068..000000000 --- a/docs/src/systems/open_boundary.md +++ /dev/null @@ -1,79 +0,0 @@ -# [Open Boundary System](@id open_boundary) -The difficulty in non-reflecting boundary conditions, also called open boundaries, is to determine -the appropriate boundary values of the exact characteristics of the Euler equations. -Giles (1990) derived three characteristic variables which are constant along curves in ``x``-``t`` plane -defined by -```math -\underbrace{\frac{\partial x}{\partial t} = v + c_s, \quad \frac{\partial x}{\partial t} = v}_{\text{downstream-running}}, - \quad - \text{and} \underbrace{\frac{\partial x}{\partial t} = v - c_s}_{\text{upstream-running (for subsonic - flow)}} -``` -and can be interpreted as the trajectories of the sound waves and material particles that carry constant values of the -characteristic variables. - -The characteristic variables based on a linearized set of governing equations are given as -```math -J_1 = -c_s^2 (\rho - \rho_{\text{ref}}) + (p - p_{\text{ref}}) -``` -```math -J_2 = \rho c_s (v - v_{\text{ref}}) + (p - p_{\text{ref}}) -``` -```math -J_3 = - \rho c_s (v - v_{\text{ref}}) + (p - p_{\text{ref}}) -``` -where the subscript "ref" denotes the reference flow near the boundaries, which can be prescribed. - -Specifying the reference variables is **not** equivalent to prescription of ``\rho``, ``v`` and ``p`` -directly, since the perturbation from the reference flow is allowed. - -Lastiwka et al (2009) applied the method of characteristic to SPH and determine the number of variables that should be -**prescribed** at the boundary and the number which should be **propagated** from the fluid domain to the boundary: - -Flow enters the domain through an -- **inflow** boundary: - - Prescribe *downstream*-running characteristics ``J_1`` and ``J_2`` - - Transmit ``J_3`` from the fluid domain (allow ``J_3`` to propagate upstream to the boundary). - -- **outflow** boundary: - - Prescribe *upstream*-running characteristic ``J_3`` - - Transmit ``J_1`` and ``J_2`` from the fluid domain. - -Prescribing is done by simply setting the characteristics to zero. To transmit the characteristics from the fluid -domain, or in other words, to carry the information of the fluid to the boundaries, Negi (2020) use a Shepard Interpolation -```math -f_i = \frac{\sum_j^N f_j W_{ij}}{\sum_j^N W_{ij}}, -``` -where the ``i``th particle is a boundary particle, ``f`` is either ``J_1``, ``J_2`` or ``J_3`` and ``N`` is the set of -neighboring fluid particles. - -To express pressure ``p``, density ``\rho`` and velocity ``v`` as functions of the characteristic variables, the system of equations -from the characteristic variables is inverted and gives -```math - \rho - \rho_{\text{ref}} = \frac{1}{c_s^2} \left( -J_1 + \frac{1}{2} J_2 + \frac{1}{2} J_3 \right), -``` -```math -u - u_{\text{ref}}= \frac{1}{2\rho c_s} \left( J_2 - J_3 \right), -``` -```math -p - p_{\text{ref}} = \frac{1}{2} \left( J_2 + J_3 \right). -``` -Thus, determined ``J_1``, ``J_2`` and ``J_3``, we can easily solve for the actual variables for each particle. - -```@autodocs -Modules = [TrixiParticles] -Pages = [joinpath("schemes", "boundary", "open_boundary", "system.jl")] -``` - -## References -- M. B. Giles "Nonreflecting boundary conditions for Euler equation calculations". - In: AIAA Journal , Vol. 28, No. 12 pages 2050--2058 - [doi: 10.2514/3.10521](https://doi.org/10.2514/3.10521) -- M. Lastiwka, M. Basa, N. J. Quinlan. - "Permeable and non-reflecting boundary conditions in SPH". - In: International Journal for Numerical Methods in Fluids 61, (2009), pages 709--724. - [doi: 10.1002/fld.1971](https://doi.org/10.1002/fld.1971) -- P. Negi, P. Ramachandran, A. Haftu. - "An improved non-reflecting outlet boundary condition for weakly-compressible SPH". - In: Computer Methods in Applied Mechanics and Engineering 367, (2020), pages 113119. - [doi: 10.1016/j.cma.2020.113119](https://doi.org/10.1016/j.cma.2020.113119) diff --git a/src/schemes/boundary/open_boundary/system.jl b/src/schemes/boundary/open_boundary/system.jl index 2f518ad12..58901d5cf 100644 --- a/src/schemes/boundary/open_boundary/system.jl +++ b/src/schemes/boundary/open_boundary/system.jl @@ -1,4 +1,4 @@ -""" +@doc raw""" OpenBoundarySPHSystem(boundary_zone::Union{InFlow, OutFlow}, sound_speed; buffer_size::Integer=0, reference_velocity=zeros(ndims(boundary_zone)), From 421743dc2d890aecee390074a558e19362b8347c Mon Sep 17 00:00:00 2001 From: LasNikas Date: Thu, 6 Jun 2024 17:22:02 +0200 Subject: [PATCH 087/107] link single fluid system --- examples/fluid/pipe_flow_2d.jl | 4 +- src/general/semidiscretization.jl | 3 - src/schemes/boundary/open_boundary/system.jl | 133 +++++++------------ test/systems/open_boundary_system.jl | 15 ++- 4 files changed, 61 insertions(+), 94 deletions(-) diff --git a/examples/fluid/pipe_flow_2d.jl b/examples/fluid/pipe_flow_2d.jl index 52cd437ec..5a8739bdd 100644 --- a/examples/fluid/pipe_flow_2d.jl +++ b/examples/fluid/pipe_flow_2d.jl @@ -73,7 +73,7 @@ end inflow = InFlow(; plane=([0.0, 0.0], [0.0, domain_size[2]]), flow_direction, open_boundary_layers, density=fluid_density, particle_spacing) -open_boundary_in = OpenBoundarySPHSystem(inflow, sound_speed; +open_boundary_in = OpenBoundarySPHSystem(inflow; sound_speed, fluid_system, buffer_size=n_buffer_particles, reference_pressure=pressure, reference_velocity=velocity_function) @@ -81,7 +81,7 @@ open_boundary_in = OpenBoundarySPHSystem(inflow, sound_speed; outflow = OutFlow(; plane=([domain_size[1], 0.0], [domain_size[1], domain_size[2]]), flow_direction, open_boundary_layers, density=fluid_density, particle_spacing) -open_boundary_out = OpenBoundarySPHSystem(outflow, sound_speed; +open_boundary_out = OpenBoundarySPHSystem(outflow; sound_speed, fluid_system, buffer_size=n_buffer_particles, reference_pressure=pressure, reference_velocity=velocity_function) diff --git a/src/general/semidiscretization.jl b/src/general/semidiscretization.jl index 8c2fe94a6..c9b7e111a 100644 --- a/src/general/semidiscretization.jl +++ b/src/general/semidiscretization.jl @@ -808,6 +808,3 @@ function check_configuration(system::TotalLagrangianSPHSystem, systems) "`ContinuityDensity` is not yet supported for a `TotalLagrangianSPHSystem`")) end end - -# Check if a fluid system with `SystemBuffer` exists -check_configuration(system::OpenBoundarySPHSystem, systems) = next_fluid_system(systems) diff --git a/src/schemes/boundary/open_boundary/system.jl b/src/schemes/boundary/open_boundary/system.jl index 58901d5cf..c733e4a2f 100644 --- a/src/schemes/boundary/open_boundary/system.jl +++ b/src/schemes/boundary/open_boundary/system.jl @@ -1,9 +1,9 @@ @doc raw""" - OpenBoundarySPHSystem(boundary_zone::Union{InFlow, OutFlow}, sound_speed; - buffer_size::Integer=0, - reference_velocity=zeros(ndims(boundary_zone)), - reference_pressure=0.0, - reference_density=first(boundary_zone.initial_condition.density)) + OpenBoundarySPHSystem(boundary_zone::Union{InFlow, OutFlow}; sound_speed, + buffer_size::Integer=0, + reference_velocity=zeros(ndims(boundary_zone)), + reference_pressure=0.0, + reference_density=first(boundary_zone.initial_condition.density)) Open boundary system for in- and outflow particles. These open boundaries use the characteristic variables to propagate the appropriate values @@ -12,29 +12,31 @@ about the method see [Open Boundary System](@ref open_boundary). # Arguments - `boundary_zone`: Use [`InFlow`](@ref) for an inflow and [`OutFlow`](@ref) for an outflow boundary. -- `sound_speed`: Speed of sound. # Keywords +- `sound_speed`: Speed of sound. +- `fluid_system`: The corresponding fluid system - `buffer_size`: Number of buffer particles. - `reference_velocity`: Reference velocity is either a function mapping each particle's coordinates - and time to its velocity, an array where the ``i``-th column holds - the velocity of particle ``i`` or, for a constant fluid velocity, - a vector holding this velocity. Velocity is constant zero by default. + and time to its velocity, an array where the ``i``-th column holds + the velocity of particle ``i`` or, for a constant fluid velocity, + a vector holding this velocity. Velocity is constant zero by default. - `reference_pressure`: Reference pressure is either a function mapping each particle's coordinates - and time to its pressure, a vector holding the pressure of each particle, - or a scalar for a constant pressure over all particles. - Pressure is constant zero by default. + and time to its pressure, a vector holding the pressure of each particle, + or a scalar for a constant pressure over all particles. + Pressure is constant zero by default. - `reference_density`: Reference density is either a function mapping each particle's coordinates - and time to its density, a vector holding the density of each particle, - or a scalar for a constant density over all particles. - Density is the density of the first particle in the initial condition by default. + and time to its density, a vector holding the density of each particle, + or a scalar for a constant density over all particles. + Density is the density of the first particle in the initial condition by default. !!! warning "Experimental Implementation" - This is an experimental feature and may change in any future releases. + This is an experimental feature and may change in any future releases. """ -struct OpenBoundarySPHSystem{BZ, NDIMS, ELTYPE <: Real, IC, ARRAY1D, ARRAY2D, RV, RP, +struct OpenBoundarySPHSystem{BZ, NDIMS, ELTYPE <: Real, IC, FS, ARRAY1D, ARRAY2D, RV, RP, RD, B} <: System{NDIMS, IC} initial_condition :: IC + fluid_system :: FS mass :: ARRAY1D # Array{ELTYPE, 1}: [particle] density :: ARRAY1D # Array{ELTYPE, 1}: [particle] volume :: ARRAY1D # Array{ELTYPE, 1}: [particle] @@ -50,8 +52,8 @@ struct OpenBoundarySPHSystem{BZ, NDIMS, ELTYPE <: Real, IC, ARRAY1D, ARRAY2D, RV buffer :: B update_callback_used :: Ref{Bool} - function OpenBoundarySPHSystem(boundary_zone::Union{InFlow, OutFlow}, sound_speed; - buffer_size::Integer=0, + function OpenBoundarySPHSystem(boundary_zone::Union{InFlow, OutFlow}; sound_speed, + fluid_system::FluidSystem, buffer_size::Integer=0, reference_velocity=zeros(ndims(boundary_zone)), reference_pressure=0.0, reference_density=first(boundary_zone.initial_condition.density)) @@ -102,13 +104,14 @@ struct OpenBoundarySPHSystem{BZ, NDIMS, ELTYPE <: Real, IC, ARRAY1D, ARRAY2D, RV flow_direction_ = boundary_zone.flow_direction return new{typeof(boundary_zone), NDIMS, ELTYPE, typeof(initial_condition), - typeof(mass), typeof(characteristics), + typeof(fluid_system), typeof(mass), typeof(characteristics), typeof(reference_velocity_), typeof(reference_pressure_), typeof(reference_density_), - typeof(buffer)}(initial_condition, mass, density, volume, pressure, - characteristics, previous_characteristics, sound_speed, - boundary_zone, flow_direction_, reference_velocity_, - reference_pressure_, reference_density_, buffer, false) + typeof(buffer)}(initial_condition, fluid_system, mass, density, volume, + pressure, characteristics, previous_characteristics, + sound_speed, boundary_zone, flow_direction_, + reference_velocity_, reference_pressure_, + reference_density_, buffer, false) end end @@ -130,12 +133,9 @@ function Base.show(io::IO, ::MIME"text/plain", system::OpenBoundarySPHSystem) show(io, system) else summary_header(io, "OpenBoundarySPHSystem{$(ndims(system))}") - if system.buffer isa SystemBuffer - summary_line(io, "#particles", nparticles(system)) - summary_line(io, "#buffer_particles", system.buffer.buffer_size) - else - summary_line(io, "#particles", nparticles(system)) - end + summary_line(io, "#particles", nparticles(system)) + summary_line(io, "#buffer_particles", system.buffer.buffer_size) + summary_line(io, "fluid system", type2string(system.fluid_system)) summary_line(io, "boundary", type2string(system.boundary_zone)) summary_line(io, "flow direction", system.flow_direction) summary_line(io, "prescribed velocity", string(nameof(system.reference_velocity))) @@ -183,9 +183,9 @@ function update_open_boundary_eachstep!(system::OpenBoundarySPHSystem, v_ode, u_ @trixi_timeit timer() "check domain" check_domain!(system, v, u, v_ode, u_ode, semi) - @trixi_timeit timer() "update buffer" foreach_system(semi) do system - update_system_buffer!(system.buffer) - end + # Update buffer + update_system_buffer!(system.buffer) + update_system_buffer!(system.fluid_system.buffer) end update_open_boundary_eachstep!(system, v_ode, u_ode, semi, t) = system @@ -206,10 +206,8 @@ function evaluate_characteristics!(system, v, u, v_ode, u_ode, semi, t) set_zero!(characteristics) set_zero!(volume) - # Use all other systems for the characteristics - foreach_system(semi) do neighbor_system - evaluate_characteristics!(system, neighbor_system, v, u, v_ode, u_ode, semi, t) - end + # Evaluate the characteristic variables with the fluid system + evaluate_characteristics!(system, system.fluid_system, v, u, v_ode, u_ode, semi, t) # Only some of the in-/outlet particles are in the influence of the fluid particles. # Thus, we find the characteristics for the particle which are outside the influence @@ -252,8 +250,6 @@ function evaluate_characteristics!(system, v, u, v_ode, u_ode, semi, t) return system end -evaluate_characteristics!(system, neighbor_system, v, u, v_ode, u_ode, semi, t) = system - function evaluate_characteristics!(system, neighbor_system::FluidSystem, v, u, v_ode, u_ode, semi, t) (; volume, sound_speed, characteristics, flow_direction, @@ -345,51 +341,31 @@ end end function check_domain!(system, v, u, v_ode, u_ode, semi) - (; boundary_zone) = system + (; boundary_zone, fluid_system) = system - # Find next fluid system with a `SystemBuffer` - next_system = next_fluid_system(semi.systems) + u_fluid = wrap_u(u_ode, fluid_system, semi) + v_fluid = wrap_v(v_ode, fluid_system, semi) - u_fluid = wrap_u(u_ode, next_system, semi) - v_fluid = wrap_v(v_ode, next_system, semi) + neighborhood_search = get_neighborhood_search(system, fluid_system, semi) for particle in each_moving_particle(system) particle_coords = current_coords(u, system, particle) - # Check if the particle position is outside the boundary zone + # Check if boundary particle is outside the boundary zone if !is_in_boundary_zone(boundary_zone, particle_coords) - transform_particle!(system, next_system, boundary_zone, particle, + transform_particle!(system, fluid_system, boundary_zone, particle, v, u, v_fluid, u_fluid) end - end - - # Check all the other fluid systems - foreach_system(semi) do fluid_system - check_domain!(system, fluid_system, v, u, v_ode, u_ode, semi) - end -end - -function check_domain!(system, neighbor_system, v, u, v_ode, u_ode, semi) - return system -end - -function check_domain!(system, fluid_system::FluidSystem, v, u, v_ode, u_ode, semi) - (; boundary_zone) = system - - u_fluid = wrap_u(u_ode, fluid_system, semi) - v_fluid = wrap_v(v_ode, fluid_system, semi) - - neighborhood_search = get_neighborhood_search(system, fluid_system, semi) - # Loop over all pairs of particles and neighbors within the kernel cutoff - for_particle_neighbor(system, fluid_system, u, u_fluid, neighborhood_search, - parallel=false) do particle, neighbor, pos_diff, distance - fluid_coords = current_coords(u_fluid, fluid_system, neighbor) + # Check the neighboring fluid particles whether they're entering the boundary zone + for neighbor in PointNeighbors.eachneighbor(particle_coords, neighborhood_search) + fluid_coords = current_coords(u_fluid, fluid_system, neighbor) - # Check if neighboring fluid particle is in boundary zone - if is_in_boundary_zone(boundary_zone, fluid_coords) - transform_particle!(fluid_system, system, boundary_zone, neighbor, - v, u, v_fluid, u_fluid) + # Check if neighboring fluid particle is in boundary zone + if is_in_boundary_zone(boundary_zone, fluid_coords) + transform_particle!(fluid_system, system, boundary_zone, neighbor, + v, u, v_fluid, u_fluid) + end end end @@ -498,14 +474,3 @@ end function wrap_reference_function(constant_vector_, ::Val{NDIMS}) where {NDIMS} return constant_vector(coords, t) = SVector{NDIMS}(constant_vector_) end - -@inline function next_fluid_system(systems) - for system_index in eachindex(systems) - system = systems[system_index] - if system isa FluidSystem && system.buffer isa SystemBuffer - return system - end - end - - return throw(ArgumentError("When simulating with `OpenBoundarySPHSystem`, a `FluidSystem` with a `SystemBuffer` is needed")) -end diff --git a/test/systems/open_boundary_system.jl b/test/systems/open_boundary_system.jl index a0f3ba8e7..2b17c429d 100644 --- a/test/systems/open_boundary_system.jl +++ b/test/systems/open_boundary_system.jl @@ -12,7 +12,8 @@ "or, for a constant fluid velocity, a vector of length 2 for a 2D problem holding this velocity" reference_velocity = 1.0 - @test_throws ArgumentError(error_str) OpenBoundarySPHSystem(inflow, 1.0; + @test_throws ArgumentError(error_str) OpenBoundarySPHSystem(inflow; sound_speed=1.0; + fluid_system=FluidSystemMock(), reference_velocity) error_str = "`reference_pressure` must be either a function mapping " * @@ -20,7 +21,8 @@ "a vector holding the pressure of each particle, or a scalar" reference_pressure = [1.0, 1.0] - @test_throws ArgumentError(error_str) OpenBoundarySPHSystem(inflow, 1.0; + @test_throws ArgumentError(error_str) OpenBoundarySPHSystem(inflow; sound_speed=1.0; + fluid_system=FluidSystemMock(), reference_pressure) error_str = "`reference_density` must be either a function mapping " * @@ -28,13 +30,15 @@ "a vector holding the density of each particle, or a scalar" reference_density = [1.0, 1.0] - @test_throws ArgumentError(error_str) OpenBoundarySPHSystem(inflow, 1.0; + @test_throws ArgumentError(error_str) OpenBoundarySPHSystem(inflow; sound_speed=1.0; + fluid_system=FluidSystemMock(), reference_density) end @testset "show" begin inflow = InFlow(; plane=([0.0, 0.0], [0.0, 1.0]), particle_spacing=0.05, flow_direction=(1.0, 0.0), density=1.0, open_boundary_layers=4) - system = OpenBoundarySPHSystem(inflow, 1.0) + system = OpenBoundarySPHSystem(inflow; sound_speed=1.0, + fluid_system=FluidSystemMock()) show_compact = "OpenBoundarySPHSystem{2}(InFlow) with 80 particles" @test repr(system) == show_compact @@ -55,7 +59,8 @@ outflow = OutFlow(; plane=([0.0, 0.0], [0.0, 1.0]), particle_spacing=0.05, flow_direction=(1.0, 0.0), density=1.0, open_boundary_layers=4) - system = OpenBoundarySPHSystem(outflow, 1.0) + system = OpenBoundarySPHSystem(outflow; sound_speed=1.0, + fluid_system=FluidSystemMock()) show_compact = "OpenBoundarySPHSystem{2}(OutFlow) with 80 particles" @test repr(system) == show_compact From 1b970e552eda8590fe6eb9e54660efb9ec295983 Mon Sep 17 00:00:00 2001 From: LasNikas Date: Thu, 6 Jun 2024 17:48:05 +0200 Subject: [PATCH 088/107] fix tests --- test/general/buffer.jl | 8 +++++-- .../open_boundary/characteristic_variables.jl | 11 +++++----- test/systems/open_boundary_system.jl | 21 ++++++++++++------- 3 files changed, 25 insertions(+), 15 deletions(-) diff --git a/test/general/buffer.jl b/test/general/buffer.jl index 8dabd3212..9f4bf0fb6 100644 --- a/test/general/buffer.jl +++ b/test/general/buffer.jl @@ -1,8 +1,12 @@ @testset verbose=true "SystemBuffer" begin + # Mock fluid system + struct FluidSystemMock3 <: TrixiParticles.FluidSystem{2, Nothing} end + inflow = InFlow(; plane=([0.0, 0.0], [0.0, 1.0]), particle_spacing=0.2, open_boundary_layers=2, density=1.0, flow_direction=[1.0, 0.0]) - system = OpenBoundarySPHSystem(inflow, 1.0) - system_buffer = OpenBoundarySPHSystem(inflow, 1.0; buffer_size=5) + system = OpenBoundarySPHSystem(inflow; sound_speed=1.0, fluid_system=FluidSystemMock3()) + system_buffer = OpenBoundarySPHSystem(inflow; sound_speed=1.0, buffer_size=5, + fluid_system=FluidSystemMock3()) n_particles = nparticles(system) diff --git a/test/schemes/boundary/open_boundary/characteristic_variables.jl b/test/schemes/boundary/open_boundary/characteristic_variables.jl index 206f00781..a43cd80c4 100644 --- a/test/schemes/boundary/open_boundary/characteristic_variables.jl +++ b/test/schemes/boundary/open_boundary/characteristic_variables.jl @@ -45,11 +45,6 @@ ] @testset "$(nameof(typeof(boundary_zone)))" for boundary_zone in boundary_zones - boundary_system = OpenBoundarySPHSystem(boundary_zone, sound_speed; - reference_velocity, - reference_pressure, - reference_density) - sign_ = (boundary_zone isa InFlow) ? 1 : -1 fluid = extrude_geometry(plane_points; particle_spacing, n_extrude=4, density, pressure, @@ -60,6 +55,12 @@ density_calculator=ContinuityDensity(), smoothing_length, sound_speed) + boundary_system = OpenBoundarySPHSystem(boundary_zone; sound_speed, + fluid_system, + reference_velocity, + reference_pressure, + reference_density) + semi = Semidiscretization(fluid_system, boundary_system) ode = semidiscretize(semi, (0.0, 5.0)) diff --git a/test/systems/open_boundary_system.jl b/test/systems/open_boundary_system.jl index 2b17c429d..b0b87f80f 100644 --- a/test/systems/open_boundary_system.jl +++ b/test/systems/open_boundary_system.jl @@ -3,6 +3,9 @@ plane = ([0.0, 0.0], [0.0, 1.0]) flow_direction = (1.0, 0.0) + # Mock fluid system + struct FluidSystemMock2 <: TrixiParticles.FluidSystem{2, Nothing} end + inflow = InFlow(; plane, particle_spacing=0.1, flow_direction, density=1.0, open_boundary_layers=2) @@ -12,8 +15,8 @@ "or, for a constant fluid velocity, a vector of length 2 for a 2D problem holding this velocity" reference_velocity = 1.0 - @test_throws ArgumentError(error_str) OpenBoundarySPHSystem(inflow; sound_speed=1.0; - fluid_system=FluidSystemMock(), + @test_throws ArgumentError(error_str) OpenBoundarySPHSystem(inflow; sound_speed=1.0, + fluid_system=FluidSystemMock2(), reference_velocity) error_str = "`reference_pressure` must be either a function mapping " * @@ -21,8 +24,8 @@ "a vector holding the pressure of each particle, or a scalar" reference_pressure = [1.0, 1.0] - @test_throws ArgumentError(error_str) OpenBoundarySPHSystem(inflow; sound_speed=1.0; - fluid_system=FluidSystemMock(), + @test_throws ArgumentError(error_str) OpenBoundarySPHSystem(inflow; sound_speed=1.0, + fluid_system=FluidSystemMock2(), reference_pressure) error_str = "`reference_density` must be either a function mapping " * @@ -30,15 +33,15 @@ "a vector holding the density of each particle, or a scalar" reference_density = [1.0, 1.0] - @test_throws ArgumentError(error_str) OpenBoundarySPHSystem(inflow; sound_speed=1.0; - fluid_system=FluidSystemMock(), + @test_throws ArgumentError(error_str) OpenBoundarySPHSystem(inflow; sound_speed=1.0, + fluid_system=FluidSystemMock2(), reference_density) end @testset "show" begin inflow = InFlow(; plane=([0.0, 0.0], [0.0, 1.0]), particle_spacing=0.05, flow_direction=(1.0, 0.0), density=1.0, open_boundary_layers=4) system = OpenBoundarySPHSystem(inflow; sound_speed=1.0, - fluid_system=FluidSystemMock()) + fluid_system=FluidSystemMock2()) show_compact = "OpenBoundarySPHSystem{2}(InFlow) with 80 particles" @test repr(system) == show_compact @@ -48,6 +51,7 @@ │ ════════════════════════ │ │ #particles: ………………………………………………… 80 │ │ #buffer_particles: ……………………………… 0 │ + │ fluid system: …………………………………………… FluidSystemMock2 │ │ boundary: ……………………………………………………… InFlow │ │ flow direction: ……………………………………… [1.0, 0.0] │ │ prescribed velocity: ………………………… constant_vector │ @@ -60,7 +64,7 @@ outflow = OutFlow(; plane=([0.0, 0.0], [0.0, 1.0]), particle_spacing=0.05, flow_direction=(1.0, 0.0), density=1.0, open_boundary_layers=4) system = OpenBoundarySPHSystem(outflow; sound_speed=1.0, - fluid_system=FluidSystemMock()) + fluid_system=FluidSystemMock2()) show_compact = "OpenBoundarySPHSystem{2}(OutFlow) with 80 particles" @test repr(system) == show_compact @@ -70,6 +74,7 @@ │ ════════════════════════ │ │ #particles: ………………………………………………… 80 │ │ #buffer_particles: ……………………………… 0 │ + │ fluid system: …………………………………………… FluidSystemMock2 │ │ boundary: ……………………………………………………… OutFlow │ │ flow direction: ……………………………………… [1.0, 0.0] │ │ prescribed velocity: ………………………… constant_vector │ From db97c6c7fef8cd4c65d35ac99423998f8fa86d1e Mon Sep 17 00:00:00 2001 From: LasNikas Date: Fri, 7 Jun 2024 10:20:09 +0200 Subject: [PATCH 089/107] implement suggestions --- docs/Project.toml | 2 +- examples/fluid/pipe_flow_2d.jl | 1 + src/schemes/boundary/open_boundary/system.jl | 37 ++++++++++--------- .../fluid/entropically_damped_sph/system.jl | 2 +- .../fluid/weakly_compressible_sph/system.jl | 2 +- 5 files changed, 23 insertions(+), 21 deletions(-) diff --git a/docs/Project.toml b/docs/Project.toml index ab1dd531a..7ada97297 100644 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -2,8 +2,8 @@ Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed" TrixiBase = "9a0f1c46-06d5-4909-a5a3-ce25d3fa3284" -TrixiParticles = "66699cd8-9c01-4e9d-a059-b96c86d16b3a" [compat] Documenter = "1" OrdinaryDiffEq = "6" +TrixiBase = "0.1" diff --git a/examples/fluid/pipe_flow_2d.jl b/examples/fluid/pipe_flow_2d.jl index 5a8739bdd..acd6bdf90 100644 --- a/examples/fluid/pipe_flow_2d.jl +++ b/examples/fluid/pipe_flow_2d.jl @@ -81,6 +81,7 @@ open_boundary_in = OpenBoundarySPHSystem(inflow; sound_speed, fluid_system, outflow = OutFlow(; plane=([domain_size[1], 0.0], [domain_size[1], domain_size[2]]), flow_direction, open_boundary_layers, density=fluid_density, particle_spacing) + open_boundary_out = OpenBoundarySPHSystem(outflow; sound_speed, fluid_system, buffer_size=n_buffer_particles, reference_pressure=pressure, diff --git a/src/schemes/boundary/open_boundary/system.jl b/src/schemes/boundary/open_boundary/system.jl index c733e4a2f..e5dfa8577 100644 --- a/src/schemes/boundary/open_boundary/system.jl +++ b/src/schemes/boundary/open_boundary/system.jl @@ -16,7 +16,7 @@ about the method see [Open Boundary System](@ref open_boundary). # Keywords - `sound_speed`: Speed of sound. - `fluid_system`: The corresponding fluid system -- `buffer_size`: Number of buffer particles. +- `buffer_size=0`: Number of buffer particles. - `reference_velocity`: Reference velocity is either a function mapping each particle's coordinates and time to its velocity, an array where the ``i``-th column holds the velocity of particle ``i`` or, for a constant fluid velocity, @@ -53,7 +53,7 @@ struct OpenBoundarySPHSystem{BZ, NDIMS, ELTYPE <: Real, IC, FS, ARRAY1D, ARRAY2D update_callback_used :: Ref{Bool} function OpenBoundarySPHSystem(boundary_zone::Union{InFlow, OutFlow}; sound_speed, - fluid_system::FluidSystem, buffer_size::Integer=0, + fluid_system::FluidSystem, buffer_size::Integer, reference_velocity=zeros(ndims(boundary_zone)), reference_pressure=0.0, reference_density=first(boundary_zone.initial_condition.density)) @@ -177,13 +177,13 @@ function update_open_boundary_eachstep!(system::OpenBoundarySPHSystem, v_ode, u_ u = wrap_u(u_ode, system, semi) v = wrap_v(v_ode, system, semi) - # Update density, pressure and velocity depending on the characteristic variables. + # Update density, pressure and velocity based on the characteristic variables. # See eq. 13-15 in Lastiwka (2009) https://doi.org/10.1002/fld.1971 @trixi_timeit timer() "update quantities" update_quantities!(system, v, u, t) @trixi_timeit timer() "check domain" check_domain!(system, v, u, v_ode, u_ode, semi) - # Update buffer + # Update buffers update_system_buffer!(system.buffer) update_system_buffer!(system.fluid_system.buffer) end @@ -210,8 +210,8 @@ function evaluate_characteristics!(system, v, u, v_ode, u_ode, semi, t) evaluate_characteristics!(system, system.fluid_system, v, u, v_ode, u_ode, semi, t) # Only some of the in-/outlet particles are in the influence of the fluid particles. - # Thus, we find the characteristics for the particle which are outside the influence - # using the average of the values of the previous time step. + # Thus, we compute the characteristics for the particles that are outside the influence + # of fluid particles by using the average of the values of the previous time step. # See eq. 27 in Negi (2020) https://doi.org/10.1016/j.cma.2020.113119 @threaded for particle in each_moving_particle(system) @@ -315,6 +315,7 @@ end (; density, pressure, characteristics, flow_direction, sound_speed, reference_velocity, reference_pressure, reference_density) = system + # Update quantities based on the characteristic variables @threaded for particle in each_moving_particle(system) particle_position = current_coords(u, system, particle) @@ -353,8 +354,8 @@ function check_domain!(system, v, u, v_ode, u_ode, semi) # Check if boundary particle is outside the boundary zone if !is_in_boundary_zone(boundary_zone, particle_coords) - transform_particle!(system, fluid_system, boundary_zone, particle, - v, u, v_fluid, u_fluid) + convert_particle!(system, fluid_system, boundary_zone, particle, + v, u, v_fluid, u_fluid) end # Check the neighboring fluid particles whether they're entering the boundary zone @@ -363,8 +364,8 @@ function check_domain!(system, v, u, v_ode, u_ode, semi) # Check if neighboring fluid particle is in boundary zone if is_in_boundary_zone(boundary_zone, fluid_coords) - transform_particle!(fluid_system, system, boundary_zone, neighbor, - v, u, v_fluid, u_fluid) + convert_particle!(fluid_system, system, boundary_zone, neighbor, + v, u, v_fluid, u_fluid) end end end @@ -373,18 +374,18 @@ function check_domain!(system, v, u, v_ode, u_ode, semi) end # Outflow particle is outside the boundary zone -@inline function transform_particle!(system::OpenBoundarySPHSystem, fluid_system, - boundary_zone::OutFlow, particle, v, u, - v_fluid, u_fluid) +@inline function convert_particle!(system::OpenBoundarySPHSystem, fluid_system, + boundary_zone::OutFlow, particle, v, u, + v_fluid, u_fluid) deactivate_particle!(system, particle, u) return system end # Inflow particle is outside the boundary zone -@inline function transform_particle!(system::OpenBoundarySPHSystem, fluid_system, - boundary_zone::InFlow, particle, v, u, - v_fluid, u_fluid) +@inline function convert_particle!(system::OpenBoundarySPHSystem, fluid_system, + boundary_zone::InFlow, particle, v, u, + v_fluid, u_fluid) (; spanning_set) = boundary_zone # Activate a new particle in simulation domain @@ -399,8 +400,8 @@ end end # Fluid particle is in boundary zone -@inline function transform_particle!(fluid_system::FluidSystem, system, - boundary_zone, particle, v, u, v_fluid, u_fluid) +@inline function convert_particle!(fluid_system::FluidSystem, system, + boundary_zone, particle, v, u, v_fluid, u_fluid) # Activate particle in boundary zone transfer_particle!(system, fluid_system, particle, v, u, v_fluid, u_fluid) diff --git a/src/schemes/fluid/entropically_damped_sph/system.jl b/src/schemes/fluid/entropically_damped_sph/system.jl index a787262d0..4093e8ccb 100644 --- a/src/schemes/fluid/entropically_damped_sph/system.jl +++ b/src/schemes/fluid/entropically_damped_sph/system.jl @@ -29,7 +29,7 @@ See [Entropically Damped Artificial Compressibility for SPH](@ref edac) for more corresponding [density calculator](@ref density_calculator) is chosen. - `density_calculator`: [Density calculator](@ref density_calculator) (default: [`SummationDensity`](@ref)) - `buffer_size`: Number of buffer particles. - This is only needed when simulating with [`OpenBoundarySPHSystem`](@ref). + This is needed when simulating with [`OpenBoundarySPHSystem`](@ref). - `source_terms`: Additional source terms for this system. Has to be either `nothing` (by default), or a function of `(coords, velocity, density, pressure)` (which are the quantities of a single particle), returning a `Tuple` diff --git a/src/schemes/fluid/weakly_compressible_sph/system.jl b/src/schemes/fluid/weakly_compressible_sph/system.jl index 3627211c1..a8e28670b 100644 --- a/src/schemes/fluid/weakly_compressible_sph/system.jl +++ b/src/schemes/fluid/weakly_compressible_sph/system.jl @@ -28,7 +28,7 @@ See [Weakly Compressible SPH](@ref wcsph) for more details on the method. - `density_diffusion`: Density diffusion terms for this system. See [`DensityDiffusion`](@ref). - `acceleration`: Acceleration vector for the system. (default: zero vector) - `buffer_size`: Number of buffer particles. - This is only needed when simulating with [`OpenBoundarySPHSystem`](@ref). + This is needed when simulating with [`OpenBoundarySPHSystem`](@ref). - `correction`: Correction method used for this system. (default: no correction, see [Corrections](@ref corrections)) - `source_terms`: Additional source terms for this system. Has to be either `nothing` (by default), or a function of `(coords, velocity, density, pressure)` From c12d8de39118e1f2ba67996da2787428e025ef39 Mon Sep 17 00:00:00 2001 From: LasNikas Date: Fri, 7 Jun 2024 10:40:18 +0200 Subject: [PATCH 090/107] fix tests --- Project.toml | 2 +- test/schemes/boundary/open_boundary/characteristic_variables.jl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Project.toml b/Project.toml index 25ada5ac1..ea1bc9aa5 100644 --- a/Project.toml +++ b/Project.toml @@ -35,7 +35,6 @@ FastPow = "0.1" ForwardDiff = "0.10" JSON = "0.21" MuladdMacro = "0.2" -PointNeighbors = "0.2" Polyester = "0.7.5" RecipesBase = "1" Reexport = "1" @@ -44,5 +43,6 @@ StaticArrays = "1" StrideArrays = "0.1" TimerOutputs = "0.5" TrixiBase = "0.1" +PointNeighbors = "0.2" WriteVTK = "1" julia = "1.9" diff --git a/test/schemes/boundary/open_boundary/characteristic_variables.jl b/test/schemes/boundary/open_boundary/characteristic_variables.jl index a43cd80c4..b17b78176 100644 --- a/test/schemes/boundary/open_boundary/characteristic_variables.jl +++ b/test/schemes/boundary/open_boundary/characteristic_variables.jl @@ -56,7 +56,7 @@ smoothing_length, sound_speed) boundary_system = OpenBoundarySPHSystem(boundary_zone; sound_speed, - fluid_system, + fluid_system, buffer_size=0, reference_velocity, reference_pressure, reference_density) From 5647c202523510b0a64288789fcd435aad037b4f Mon Sep 17 00:00:00 2001 From: LasNikas Date: Fri, 7 Jun 2024 12:53:30 +0200 Subject: [PATCH 091/107] change the order of functions --- src/schemes/boundary/open_boundary/system.jl | 88 ++++++++++---------- 1 file changed, 44 insertions(+), 44 deletions(-) diff --git a/src/schemes/boundary/open_boundary/system.jl b/src/schemes/boundary/open_boundary/system.jl index e5dfa8577..5a0ddb55a 100644 --- a/src/schemes/boundary/open_boundary/system.jl +++ b/src/schemes/boundary/open_boundary/system.jl @@ -160,6 +160,36 @@ end return system.pressure[particle] end +@inline function update_quantities!(system::OpenBoundarySPHSystem, v, u, t) + (; density, pressure, characteristics, flow_direction, sound_speed, + reference_velocity, reference_pressure, reference_density) = system + + # Update quantities based on the characteristic variables + @threaded for particle in each_moving_particle(system) + particle_position = current_coords(u, system, particle) + + J1 = characteristics[1, particle] + J2 = characteristics[2, particle] + J3 = characteristics[3, particle] + + rho_ref = reference_density(particle_position, t) + density[particle] = rho_ref + ((-J1 + 0.5 * (J2 + J3)) / sound_speed^2) + + p_ref = reference_pressure(particle_position, t) + pressure[particle] = p_ref + 0.5 * (J2 + J3) + + v_ref = reference_velocity(particle_position, t) + rho = density[particle] + v_ = v_ref + ((J2 - J3) / (2 * sound_speed * rho)) * flow_direction + + for dim in 1:ndims(system) + v[dim, particle] = v_[dim] + end + end + + return system +end + function update_final!(system::OpenBoundarySPHSystem, v, u, v_ode, u_ode, semi, t; update_from_callback=false) if !update_from_callback && !(system.update_callback_used[]) @@ -171,25 +201,6 @@ function update_final!(system::OpenBoundarySPHSystem, v, u, v_ode, u_ode, semi, semi, t) end -# This function is called by the `UpdateCallback`, as the integrator array might be modified -function update_open_boundary_eachstep!(system::OpenBoundarySPHSystem, v_ode, u_ode, - semi, t) - u = wrap_u(u_ode, system, semi) - v = wrap_v(v_ode, system, semi) - - # Update density, pressure and velocity based on the characteristic variables. - # See eq. 13-15 in Lastiwka (2009) https://doi.org/10.1002/fld.1971 - @trixi_timeit timer() "update quantities" update_quantities!(system, v, u, t) - - @trixi_timeit timer() "check domain" check_domain!(system, v, u, v_ode, u_ode, semi) - - # Update buffers - update_system_buffer!(system.buffer) - update_system_buffer!(system.fluid_system.buffer) -end - -update_open_boundary_eachstep!(system, v_ode, u_ode, semi, t) = system - # ==== Characteristics # J1: Associated with convection and entropy and propagates at flow velocity. # J2: Propagates downstream to the local flow @@ -311,36 +322,25 @@ end return characteristics end -@inline function update_quantities!(system::OpenBoundarySPHSystem, v, u, t) - (; density, pressure, characteristics, flow_direction, sound_speed, - reference_velocity, reference_pressure, reference_density) = system - - # Update quantities based on the characteristic variables - @threaded for particle in each_moving_particle(system) - particle_position = current_coords(u, system, particle) - - J1 = characteristics[1, particle] - J2 = characteristics[2, particle] - J3 = characteristics[3, particle] - - rho_ref = reference_density(particle_position, t) - density[particle] = rho_ref + ((-J1 + 0.5 * (J2 + J3)) / sound_speed^2) - - p_ref = reference_pressure(particle_position, t) - pressure[particle] = p_ref + 0.5 * (J2 + J3) +# This function is called by the `UpdateCallback`, as the integrator array might be modified +function update_open_boundary_eachstep!(system::OpenBoundarySPHSystem, v_ode, u_ode, + semi, t) + u = wrap_u(u_ode, system, semi) + v = wrap_v(v_ode, system, semi) - v_ref = reference_velocity(particle_position, t) - rho = density[particle] - v_ = v_ref + ((J2 - J3) / (2 * sound_speed * rho)) * flow_direction + # Update density, pressure and velocity based on the characteristic variables. + # See eq. 13-15 in Lastiwka (2009) https://doi.org/10.1002/fld.1971 + @trixi_timeit timer() "update quantities" update_quantities!(system, v, u, t) - for dim in 1:ndims(system) - v[dim, particle] = v_[dim] - end - end + @trixi_timeit timer() "check domain" check_domain!(system, v, u, v_ode, u_ode, semi) - return system + # Update buffers + update_system_buffer!(system.buffer) + update_system_buffer!(system.fluid_system.buffer) end +update_open_boundary_eachstep!(system, v_ode, u_ode, semi, t) = system + function check_domain!(system, v, u, v_ode, u_ode, semi) (; boundary_zone, fluid_system) = system From b2f7ace186c224b7cd57145e1e5595dd34411ae1 Mon Sep 17 00:00:00 2001 From: LasNikas Date: Fri, 7 Jun 2024 13:06:05 +0200 Subject: [PATCH 092/107] modify example --- examples/fluid/pipe_flow_2d.jl | 28 +++++++++++--------- src/schemes/boundary/open_boundary/system.jl | 4 +-- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/examples/fluid/pipe_flow_2d.jl b/examples/fluid/pipe_flow_2d.jl index acd6bdf90..1c47005c0 100644 --- a/examples/fluid/pipe_flow_2d.jl +++ b/examples/fluid/pipe_flow_2d.jl @@ -1,13 +1,14 @@ -# TODO: Description +# 2D channel flow simulation with open boundaries. + using TrixiParticles using OrdinaryDiffEq # ========================================================================================== # ==== Resolution -domain_length_factor = 0.05 +particle_spacing = 0.05 # Make sure that the kernel support of fluid particles at a boundary is always fully sampled -boundary_layers = 4 +boundary_layers = 3 # Make sure that the kernel support of fluid particles at an open boundary is always # fully sampled. @@ -26,12 +27,13 @@ flow_direction = [1.0, 0.0] reynolds_number = 100 const prescribed_velocity = 2.0 -particle_spacing = domain_length_factor * domain_size[1] - boundary_size = (domain_size[1] + 2 * particle_spacing * open_boundary_layers, domain_size[2]) fluid_density = 1000.0 + +# For this particular example, it is necessary to have a background pressure. +# Otherwise the suction at the outflow is to big and the simulation becomes unstable. pressure = 1000.0 sound_speed = 10 * prescribed_velocity @@ -53,8 +55,8 @@ n_buffer_particles = 4 * pipe.n_particles_per_dimension[2] smoothing_length = 3.0 * particle_spacing smoothing_kernel = WendlandC2Kernel{2}() -nu = prescribed_velocity * domain_size[2] / reynolds_number -alpha = 8 * nu / (smoothing_length * sound_speed) +kinematic_viscosity = prescribed_velocity * domain_size[2] / reynolds_number +alpha = 8 * kinematic_viscosity / (smoothing_length * sound_speed) fluid_density_calculator = ContinuityDensity() viscosity = ArtificialViscosityMonaghan(; alpha, beta=0.0) @@ -67,7 +69,10 @@ fluid_system = WeaklyCompressibleSPHSystem(pipe.fluid, fluid_density_calculator, # ========================================================================================== # ==== Open Boundary function velocity_function(pos, t) - return SVector(prescribed_velocity, 0.0) # SVector(0.5prescribed_velocity * sin(2pi * t) + prescribed_velocity, 0) + # Use this for a time-dependent inflow velocity + # return SVector(0.5prescribed_velocity * sin(2pi * t) + prescribed_velocity, 0) + + return SVector(prescribed_velocity, 0.0) end inflow = InFlow(; plane=([0.0, 0.0], [0.0, domain_size[2]]), flow_direction, @@ -100,11 +105,8 @@ boundary_system = BoundarySPHSystem(pipe.boundary, boundary_model) # ========================================================================================== # ==== Simulation -semi = Semidiscretization(fluid_system, - open_boundary_in, - open_boundary_out, - boundary_system, - neighborhood_search=GridNeighborhoodSearch) +semi = Semidiscretization(fluid_system, open_boundary_in, open_boundary_out, + boundary_system, neighborhood_search=GridNeighborhoodSearch) ode = semidiscretize(semi, tspan) diff --git a/src/schemes/boundary/open_boundary/system.jl b/src/schemes/boundary/open_boundary/system.jl index 5a0ddb55a..65a816d3f 100644 --- a/src/schemes/boundary/open_boundary/system.jl +++ b/src/schemes/boundary/open_boundary/system.jl @@ -1,6 +1,6 @@ @doc raw""" OpenBoundarySPHSystem(boundary_zone::Union{InFlow, OutFlow}; sound_speed, - buffer_size::Integer=0, + buffer_size::Integer, reference_velocity=zeros(ndims(boundary_zone)), reference_pressure=0.0, reference_density=first(boundary_zone.initial_condition.density)) @@ -16,7 +16,7 @@ about the method see [Open Boundary System](@ref open_boundary). # Keywords - `sound_speed`: Speed of sound. - `fluid_system`: The corresponding fluid system -- `buffer_size=0`: Number of buffer particles. +- `buffer_size`: Number of buffer particles. - `reference_velocity`: Reference velocity is either a function mapping each particle's coordinates and time to its velocity, an array where the ``i``-th column holds the velocity of particle ``i`` or, for a constant fluid velocity, From 2f32f91754fbf0f3129d45e8a7d156309653038b Mon Sep 17 00:00:00 2001 From: LasNikas Date: Fri, 7 Jun 2024 13:20:16 +0200 Subject: [PATCH 093/107] fix tests --- test/systems/open_boundary_system.jl | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/test/systems/open_boundary_system.jl b/test/systems/open_boundary_system.jl index b0b87f80f..b00f22da1 100644 --- a/test/systems/open_boundary_system.jl +++ b/test/systems/open_boundary_system.jl @@ -16,6 +16,7 @@ reference_velocity = 1.0 @test_throws ArgumentError(error_str) OpenBoundarySPHSystem(inflow; sound_speed=1.0, + buffer_size=0, fluid_system=FluidSystemMock2(), reference_velocity) @@ -25,6 +26,7 @@ reference_pressure = [1.0, 1.0] @test_throws ArgumentError(error_str) OpenBoundarySPHSystem(inflow; sound_speed=1.0, + buffer_size=0, fluid_system=FluidSystemMock2(), reference_pressure) @@ -34,13 +36,14 @@ reference_density = [1.0, 1.0] @test_throws ArgumentError(error_str) OpenBoundarySPHSystem(inflow; sound_speed=1.0, + buffer_size=0, fluid_system=FluidSystemMock2(), reference_density) end @testset "show" begin inflow = InFlow(; plane=([0.0, 0.0], [0.0, 1.0]), particle_spacing=0.05, flow_direction=(1.0, 0.0), density=1.0, open_boundary_layers=4) - system = OpenBoundarySPHSystem(inflow; sound_speed=1.0, + system = OpenBoundarySPHSystem(inflow; sound_speed=1.0, buffer_size=0, fluid_system=FluidSystemMock2()) show_compact = "OpenBoundarySPHSystem{2}(InFlow) with 80 particles" @@ -63,7 +66,7 @@ outflow = OutFlow(; plane=([0.0, 0.0], [0.0, 1.0]), particle_spacing=0.05, flow_direction=(1.0, 0.0), density=1.0, open_boundary_layers=4) - system = OpenBoundarySPHSystem(outflow; sound_speed=1.0, + system = OpenBoundarySPHSystem(outflow; sound_speed=1.0, buffer_size=0, fluid_system=FluidSystemMock2()) show_compact = "OpenBoundarySPHSystem{2}(OutFlow) with 80 particles" From 6799dc7c91331e942deeac77d8f131f8a72ca804 Mon Sep 17 00:00:00 2001 From: LasNikas Date: Fri, 7 Jun 2024 13:29:59 +0200 Subject: [PATCH 094/107] fix test again --- test/general/buffer.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/general/buffer.jl b/test/general/buffer.jl index 9f4bf0fb6..2ae7f9ec0 100644 --- a/test/general/buffer.jl +++ b/test/general/buffer.jl @@ -4,7 +4,8 @@ inflow = InFlow(; plane=([0.0, 0.0], [0.0, 1.0]), particle_spacing=0.2, open_boundary_layers=2, density=1.0, flow_direction=[1.0, 0.0]) - system = OpenBoundarySPHSystem(inflow; sound_speed=1.0, fluid_system=FluidSystemMock3()) + system = OpenBoundarySPHSystem(inflow; sound_speed=1.0, fluid_system=FluidSystemMock3(), + buffer_size=0) system_buffer = OpenBoundarySPHSystem(inflow; sound_speed=1.0, buffer_size=5, fluid_system=FluidSystemMock3()) From 172da98ba6bb68e9004c4cf5794844107faed292 Mon Sep 17 00:00:00 2001 From: LasNikas Date: Fri, 7 Jun 2024 13:32:43 +0200 Subject: [PATCH 095/107] implement doc suggestions --- docs/src/systems/boundary.md | 31 ++++++++++---------- src/schemes/boundary/open_boundary/system.jl | 18 ++++++------ 2 files changed, 24 insertions(+), 25 deletions(-) diff --git a/docs/src/systems/boundary.md b/docs/src/systems/boundary.md index 889c2098b..0b08a64df 100644 --- a/docs/src/systems/boundary.md +++ b/docs/src/systems/boundary.md @@ -235,9 +235,18 @@ Pages = [joinpath("schemes", "boundary", "monaghan_kajtar", "monaghan_kajtar.jl" In: Journal of Computational Physics 300 (2015), pages 5–19. [doi: 10.1016/J.JCP.2015.07.033](https://doi.org/10.1016/J.JCP.2015.07.033) -# [Open Boundary System](@id open_boundary) +# [Open Boundaries](@id open_boundary) + +```@autodocs +Modules = [TrixiParticles] +Pages = [joinpath("schemes", "boundary", "open_boundary", "system.jl")] +``` + +```@autodocs +Modules = [TrixiParticles] +Pages = [joinpath("schemes", "boundary", "open_boundary", "boundary_zones.jl")] +``` -TODO: Make the entire doc nicer and clearer The difficulty in non-reflecting boundary conditions, also called open boundaries, is to determine the appropriate boundary values of the exact characteristics of the Euler equations. Assuming the flow near the boundaries is normal to the boundary @@ -262,7 +271,7 @@ where the subscript "ref" denotes the reference flow near the boundaries, which Specifying the reference variables is **not** equivalent to prescription of ``\rho``, ``v`` and ``p`` directly, since the perturbation from the reference flow is allowed. -Lastiwka et al (2009) applied the method of characteristic to SPH and determine the number of variables that should be +Lastiwka et al. (2009) applied the method of characteristic to SPH and determine the number of variables that should be **prescribed** at the boundary and the number which should be **propagated** from the fluid domain to the boundary: Flow enters the domain through an @@ -279,7 +288,7 @@ domain, or in other words, to carry the information of the fluid to the boundari ```math f_i = \frac{\sum_j^N f_j W_{ij}}{\sum_j^N W_{ij}}, ``` -where the ``i``th particle is a boundary particle, ``f`` is either ``J_1``, ``J_2`` or ``J_3`` and ``N`` is the set of +where the ``i``-th particle is a boundary particle, ``f`` is either ``J_1``, ``J_2`` or ``J_3`` and ``N`` is the set of neighboring fluid particles. To express pressure ``p``, density ``\rho`` and velocity ``v`` as functions of the characteristic variables, the system of equations @@ -295,19 +304,9 @@ p - p_{\text{ref}} = \frac{1}{2} \left( J_2 + J_3 \right). ``` Thus, determined ``J_1``, ``J_2`` and ``J_3``, we can easily solve for the actual variables for each particle. -```@autodocs -Modules = [TrixiParticles] -Pages = [joinpath("schemes", "boundary", "open_boundary", "boundary_zones.jl")] -``` - -```@autodocs -Modules = [TrixiParticles] -Pages = [joinpath("schemes", "boundary", "open_boundary", "system.jl")] -``` - ### References -- M. B. Giles "Nonreflecting boundary conditions for Euler equation calculations". - In: AIAA Journal , Vol. 28, No. 12 pages 2050--2058 +- M. B. Giles. "Nonreflecting boundary conditions for Euler equation calculations". + In: AIAA Journal , 28.12 pages 2050--2058. [doi: 10.2514/3.10521](https://doi.org/10.2514/3.10521) - M. Lastiwka, M. Basa, N. J. Quinlan. "Permeable and non-reflecting boundary conditions in SPH". diff --git a/src/schemes/boundary/open_boundary/system.jl b/src/schemes/boundary/open_boundary/system.jl index 65a816d3f..90a315685 100644 --- a/src/schemes/boundary/open_boundary/system.jl +++ b/src/schemes/boundary/open_boundary/system.jl @@ -18,17 +18,17 @@ about the method see [Open Boundary System](@ref open_boundary). - `fluid_system`: The corresponding fluid system - `buffer_size`: Number of buffer particles. - `reference_velocity`: Reference velocity is either a function mapping each particle's coordinates - and time to its velocity, an array where the ``i``-th column holds - the velocity of particle ``i`` or, for a constant fluid velocity, - a vector holding this velocity. Velocity is constant zero by default. + and time to its velocity, an array where the ``i``-th column holds + the velocity of particle ``i`` or, for a constant fluid velocity, + a vector holding this velocity. Velocity is constant zero by default. - `reference_pressure`: Reference pressure is either a function mapping each particle's coordinates - and time to its pressure, a vector holding the pressure of each particle, - or a scalar for a constant pressure over all particles. - Pressure is constant zero by default. + and time to its pressure, a vector holding the pressure of each particle, + or a scalar for a constant pressure over all particles. + Pressure is constant zero by default. - `reference_density`: Reference density is either a function mapping each particle's coordinates - and time to its density, a vector holding the density of each particle, - or a scalar for a constant density over all particles. - Density is the density of the first particle in the initial condition by default. + and time to its density, a vector holding the density of each particle, + or a scalar for a constant density over all particles. + Density is the density of the first particle in the initial condition by default. !!! warning "Experimental Implementation" This is an experimental feature and may change in any future releases. From 19c3089ba8b59334b34e11737540549c3cf69c0e Mon Sep 17 00:00:00 2001 From: LasNikas Date: Fri, 7 Jun 2024 13:39:36 +0200 Subject: [PATCH 096/107] modify dos --- docs/src/systems/boundary.md | 2 ++ src/schemes/boundary/open_boundary/system.jl | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/src/systems/boundary.md b/docs/src/systems/boundary.md index 0b08a64df..a8d4c3ac5 100644 --- a/docs/src/systems/boundary.md +++ b/docs/src/systems/boundary.md @@ -247,6 +247,8 @@ Modules = [TrixiParticles] Pages = [joinpath("schemes", "boundary", "open_boundary", "boundary_zones.jl")] ``` +### [Method of characteristics](@id method_of_characteristics) + The difficulty in non-reflecting boundary conditions, also called open boundaries, is to determine the appropriate boundary values of the exact characteristics of the Euler equations. Assuming the flow near the boundaries is normal to the boundary diff --git a/src/schemes/boundary/open_boundary/system.jl b/src/schemes/boundary/open_boundary/system.jl index 90a315685..af79a9ee7 100644 --- a/src/schemes/boundary/open_boundary/system.jl +++ b/src/schemes/boundary/open_boundary/system.jl @@ -7,8 +7,8 @@ Open boundary system for in- and outflow particles. These open boundaries use the characteristic variables to propagate the appropriate values -to the outlet or inlet and have been proposed by Lastiwka et al (2009). For more information -about the method see [Open Boundary System](@ref open_boundary). +to the outlet or inlet and have been proposed by Lastiwka et al. (2009). For more information +about the method see [description below](@ref method_of_characteristics). # Arguments - `boundary_zone`: Use [`InFlow`](@ref) for an inflow and [`OutFlow`](@ref) for an outflow boundary. From f340064ca45138edad9085a70133b88750b328e3 Mon Sep 17 00:00:00 2001 From: LasNikas Date: Fri, 7 Jun 2024 13:42:58 +0200 Subject: [PATCH 097/107] fix typos --- docs/src/systems/boundary.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/src/systems/boundary.md b/docs/src/systems/boundary.md index a8d4c3ac5..8f3805c94 100644 --- a/docs/src/systems/boundary.md +++ b/docs/src/systems/boundary.md @@ -252,11 +252,11 @@ Pages = [joinpath("schemes", "boundary", "open_boundary", "boundary_zones.jl")] The difficulty in non-reflecting boundary conditions, also called open boundaries, is to determine the appropriate boundary values of the exact characteristics of the Euler equations. Assuming the flow near the boundaries is normal to the boundary -and free of shock waves and significant viscous effects, it can be shown that three characteristics variables exist: +and free of shock waves and significant viscous effects, it can be shown that three characteristic variables exist: - ``J_1``, associated with convection of entropy and propagates at flow velocity, - ``J_2``, downstream-running characteristics, -- ``J_3``, Upstream-running characteristics. +- ``J_3``, upstream-running characteristics. Giles (1990) derived those variables based on a linearized set of governing equations: ```math From 992cda3cb8eefe48ea48a3d120a1971645224cf2 Mon Sep 17 00:00:00 2001 From: LasNikas Date: Mon, 17 Jun 2024 08:34:35 +0200 Subject: [PATCH 098/107] implement suggestions --- docs/src/systems/boundary.md | 4 ++-- examples/fluid/pipe_flow_2d.jl | 2 +- test/general/buffer.jl | 31 ++++++++++++++-------------- test/systems/open_boundary_system.jl | 4 ++-- 4 files changed, 21 insertions(+), 20 deletions(-) diff --git a/docs/src/systems/boundary.md b/docs/src/systems/boundary.md index 8f3805c94..b1e264967 100644 --- a/docs/src/systems/boundary.md +++ b/docs/src/systems/boundary.md @@ -308,7 +308,7 @@ Thus, determined ``J_1``, ``J_2`` and ``J_3``, we can easily solve for the actua ### References - M. B. Giles. "Nonreflecting boundary conditions for Euler equation calculations". - In: AIAA Journal , 28.12 pages 2050--2058. + In: AIAA Journal, 28.12 pages 2050--2058. [doi: 10.2514/3.10521](https://doi.org/10.2514/3.10521) - M. Lastiwka, M. Basa, N. J. Quinlan. "Permeable and non-reflecting boundary conditions in SPH". @@ -316,5 +316,5 @@ Thus, determined ``J_1``, ``J_2`` and ``J_3``, we can easily solve for the actua [doi: 10.1002/fld.1971](https://doi.org/10.1002/fld.1971) - P. Negi, P. Ramachandran, A. Haftu. "An improved non-reflecting outlet boundary condition for weakly-compressible SPH". - In: Computer Methods in Applied Mechanics and Engineering 367, (2020), pages 113119. + In: Computer Methods in Applied Mechanics and Engineering 367, (2020), pages 113--119. [doi: 10.1016/j.cma.2020.113119](https://doi.org/10.1016/j.cma.2020.113119) diff --git a/examples/fluid/pipe_flow_2d.jl b/examples/fluid/pipe_flow_2d.jl index 1c47005c0..bce83874b 100644 --- a/examples/fluid/pipe_flow_2d.jl +++ b/examples/fluid/pipe_flow_2d.jl @@ -106,7 +106,7 @@ boundary_system = BoundarySPHSystem(pipe.boundary, boundary_model) # ========================================================================================== # ==== Simulation semi = Semidiscretization(fluid_system, open_boundary_in, open_boundary_out, - boundary_system, neighborhood_search=GridNeighborhoodSearch) + boundary_system) ode = semidiscretize(semi, tspan) diff --git a/test/general/buffer.jl b/test/general/buffer.jl index 2ae7f9ec0..7a8371ea7 100644 --- a/test/general/buffer.jl +++ b/test/general/buffer.jl @@ -1,4 +1,4 @@ -@testset verbose=true "SystemBuffer" begin +@testset verbose=true "`SystemBuffer`" begin # Mock fluid system struct FluidSystemMock3 <: TrixiParticles.FluidSystem{2, Nothing} end @@ -12,32 +12,31 @@ n_particles = nparticles(system) @testset "Iterators" begin - @test Base.OneTo(n_particles) == TrixiParticles.each_moving_particle(system) + @test TrixiParticles.each_moving_particle(system) == 1:n_particles - @test Base.OneTo(n_particles) == TrixiParticles.each_moving_particle(system_buffer) + @test TrixiParticles.each_moving_particle(system_buffer) == 1:n_particles - particle_ID = TrixiParticles.activate_next_particle(system_buffer) + particle_id = TrixiParticles.activate_next_particle(system_buffer) TrixiParticles.update_system_buffer!(system_buffer.buffer) - @test Base.OneTo(n_particles + 1) == - TrixiParticles.each_moving_particle(system_buffer) + @test TrixiParticles.each_moving_particle(system_buffer) == 1:(n_particles + 1) - TrixiParticles.deactivate_particle!(system_buffer, particle_ID, - ones(2, particle_ID)) + TrixiParticles.deactivate_particle!(system_buffer, particle_id, + ones(2, particle_id)) TrixiParticles.update_system_buffer!(system_buffer.buffer) - @test Base.OneTo(n_particles) == TrixiParticles.each_moving_particle(system_buffer) + @test TrixiParticles.each_moving_particle(system_buffer) == 1:n_particles - particle_ID = 5 - TrixiParticles.deactivate_particle!(system_buffer, particle_ID, - ones(2, particle_ID)) + particle_id = 5 + TrixiParticles.deactivate_particle!(system_buffer, particle_id, + ones(2, particle_id)) TrixiParticles.update_system_buffer!(system_buffer.buffer) - @test setdiff(Base.OneTo(n_particles), particle_ID) == - TrixiParticles.each_moving_particle(system_buffer) + @test TrixiParticles.each_moving_particle(system_buffer) == + setdiff(1:n_particles, particle_id) end @testset "Allocate Buffer" begin @@ -46,7 +45,7 @@ ic_with_buffer = TrixiParticles.allocate_buffer(initial_condition, buffer) - @test nparticles(initial_condition) + 7 == nparticles(ic_with_buffer) + @test nparticles(ic_with_buffer) == nparticles(initial_condition) + 7 masses = initial_condition.mass[1] .* ones(nparticles(ic_with_buffer)) @test masses == ic_with_buffer.mass @@ -58,8 +57,10 @@ @test pressures == ic_with_buffer.pressure @testset "Illegal Input" begin + # The rectangular patch has a perturbed, non-constant density ic = rectangular_patch(0.1, (3, 3)) buffer = TrixiParticles.SystemBuffer(9, 7) + error_str = "`initial_condition.density` needs to be constant when using `SystemBuffer`" @test_throws ArgumentError(error_str) TrixiParticles.allocate_buffer(ic, buffer) end diff --git a/test/systems/open_boundary_system.jl b/test/systems/open_boundary_system.jl index b00f22da1..1158aaff0 100644 --- a/test/systems/open_boundary_system.jl +++ b/test/systems/open_boundary_system.jl @@ -1,4 +1,4 @@ -@testset verbose=true "OpenBoundarySPHSystem" begin +@testset verbose=true "`OpenBoundarySPHSystem`" begin @testset verbose=true "Illegal Inputs" begin plane = ([0.0, 0.0], [0.0, 1.0]) flow_direction = (1.0, 0.0) @@ -40,7 +40,7 @@ fluid_system=FluidSystemMock2(), reference_density) end - @testset "show" begin + @testset "`show`" begin inflow = InFlow(; plane=([0.0, 0.0], [0.0, 1.0]), particle_spacing=0.05, flow_direction=(1.0, 0.0), density=1.0, open_boundary_layers=4) system = OpenBoundarySPHSystem(inflow; sound_speed=1.0, buffer_size=0, From ed69a401d7a37209e44adbd4094dc22295c35474 Mon Sep 17 00:00:00 2001 From: LasNikas Date: Tue, 18 Jun 2024 08:24:01 +0200 Subject: [PATCH 099/107] implement suggestions --- docs/src/systems/boundary.md | 11 +++--- examples/fluid/pipe_flow_2d.jl | 4 +-- .../boundary/open_boundary/boundary_zones.jl | 36 ++++++++++--------- src/schemes/boundary/open_boundary/system.jl | 10 +++--- 4 files changed, 32 insertions(+), 29 deletions(-) diff --git a/docs/src/systems/boundary.md b/docs/src/systems/boundary.md index b1e264967..ae4b9b676 100644 --- a/docs/src/systems/boundary.md +++ b/docs/src/systems/boundary.md @@ -273,20 +273,19 @@ where the subscript "ref" denotes the reference flow near the boundaries, which Specifying the reference variables is **not** equivalent to prescription of ``\rho``, ``v`` and ``p`` directly, since the perturbation from the reference flow is allowed. -Lastiwka et al. (2009) applied the method of characteristic to SPH and determine the number of variables that should be +Lastiwka et al. (2009) applied the method of characteristic to SPH and determined the number of variables that should be **prescribed** at the boundary and the number which should be **propagated** from the fluid domain to the boundary: -Flow enters the domain through an -- **inflow** boundary: +- For an **inflow** boundary: - Prescribe *downstream*-running characteristics ``J_1`` and ``J_2`` - Transmit ``J_3`` from the fluid domain (allow ``J_3`` to propagate upstream to the boundary). -- **outflow** boundary: +- For an **outflow** boundary: - Prescribe *upstream*-running characteristic ``J_3`` - Transmit ``J_1`` and ``J_2`` from the fluid domain. Prescribing is done by simply setting the characteristics to zero. To transmit the characteristics from the fluid -domain, or in other words, to carry the information of the fluid to the boundaries, Negi (2020) use a Shepard Interpolation +domain, or in other words, to carry the information of the fluid to the boundaries, Negi et al. (2020) use a Shepard Interpolation ```math f_i = \frac{\sum_j^N f_j W_{ij}}{\sum_j^N W_{ij}}, ``` @@ -304,7 +303,7 @@ u - u_{\text{ref}}= \frac{1}{2\rho c_s} \left( J_2 - J_3 \right), ```math p - p_{\text{ref}} = \frac{1}{2} \left( J_2 + J_3 \right). ``` -Thus, determined ``J_1``, ``J_2`` and ``J_3``, we can easily solve for the actual variables for each particle. +With ``J_1``, ``J_2`` and ``J_3`` determined, we can easily solve for the actual variables for each particle. ### References - M. B. Giles. "Nonreflecting boundary conditions for Euler equation calculations". diff --git a/examples/fluid/pipe_flow_2d.jl b/examples/fluid/pipe_flow_2d.jl index bce83874b..1bd609ffa 100644 --- a/examples/fluid/pipe_flow_2d.jl +++ b/examples/fluid/pipe_flow_2d.jl @@ -12,8 +12,8 @@ boundary_layers = 3 # Make sure that the kernel support of fluid particles at an open boundary is always # fully sampled. -# Due to the dynamics at the inlets and outlets, it is recommended to use -# `open_boundary_layers > boundary_layers` +# Note: Due to the dynamics at the inlets and outlets of open boundaries, +# it is recommended to use `open_boundary_layers > boundary_layers` open_boundary_layers = 6 # ========================================================================================== diff --git a/src/schemes/boundary/open_boundary/boundary_zones.jl b/src/schemes/boundary/open_boundary/boundary_zones.jl index 3286905cb..c8d65da77 100644 --- a/src/schemes/boundary/open_boundary/boundary_zones.jl +++ b/src/schemes/boundary/open_boundary/boundary_zones.jl @@ -12,15 +12,17 @@ There are three ways to specify the actual shape of the inflow: be filled with inflow particles. 2. Pass a 1D shape in 2D or a 2D shape in 3D, which is then extruded in upstream direction to create the inflow particles. - In 2D, the shape must be either an initial condition with 2D coordinates, which lies - on the line specified by `plane`, or an initial condition with 1D coordinates, which lies - on the line specified by `plane` when a y-coordinate of `0` is added. - In 3D, the shape must be either an initial condition with 3D coordinates, which lies - in the rectangle specified by `plane`, or an initial condition with 2D coordinates, - which lies in the rectangle specified by `plane` when a z-coordinate of `0` is added. - Note that particles outside the boundary zone box will be removed. + - In 2D, the shape must be either an initial condition with 2D coordinates, which lies + on the line specified by `plane`, or an initial condition with 1D coordinates, which lies + on the line specified by `plane` when a y-coordinate of `0` is added. + - In 3D, the shape must be either an initial condition with 3D coordinates, which lies + in the rectangle specified by `plane`, or an initial condition with 2D coordinates, + which lies in the rectangle specified by `plane` when a z-coordinate of `0` is added. 3. Pass a 2D initial condition in 2D or a 3D initial condition in 3D, which will be used - for the inflow particles. Note that particles outside the boundary zone box will be removed. + for the inflow particles. + +!!! note "Note" + Particles outside the boundary zone box will be removed. # Keywords - `plane`: Tuple of points defining a part of the surface of the domain. @@ -146,15 +148,17 @@ There are three ways to specify the actual shape of the outflow: be filled with outflow particles. 2. Pass a 1D shape in 2D or a 2D shape in 3D, which is then extruded in downstream direction to create the outflow particles. - In 2D, the shape must be either an initial condition with 2D coordinates, which lies - on the line specified by `plane`, or an initial condition with 1D coordinates, which lies - on the line specified by `plane` when a y-coordinate of `0` is added. - In 3D, the shape must be either an initial condition with 3D coordinates, which lies - in the rectangle specified by `plane`, or an initial condition with 2D coordinates, - which lies in the rectangle specified by `plane` when a z-coordinate of `0` is added. - Note that particles outside the boundary zone box will be removed. + - In 2D, the shape must be either an initial condition with 2D coordinates, which lies + on the line specified by `plane`, or an initial condition with 1D coordinates, which lies + on the line specified by `plane` when a y-coordinate of `0` is added. + - In 3D, the shape must be either an initial condition with 3D coordinates, which lies + in the rectangle specified by `plane`, or an initial condition with 2D coordinates, + which lies in the rectangle specified by `plane` when a z-coordinate of `0` is added. 3. Pass a 2D initial condition in 2D or a 3D initial condition in 3D, which will be used - for the outflow particles. Note that particles outside the boundary zone box will be removed. + for the outflow particles. + +!!! note "Note" + Particles outside the boundary zone box will be removed. # Keywords - `plane`: Tuple of points defining a part of the surface of the domain. diff --git a/src/schemes/boundary/open_boundary/system.jl b/src/schemes/boundary/open_boundary/system.jl index af79a9ee7..a8e1fd326 100644 --- a/src/schemes/boundary/open_boundary/system.jl +++ b/src/schemes/boundary/open_boundary/system.jl @@ -1,9 +1,9 @@ @doc raw""" - OpenBoundarySPHSystem(boundary_zone::Union{InFlow, OutFlow}; sound_speed, - buffer_size::Integer, - reference_velocity=zeros(ndims(boundary_zone)), - reference_pressure=0.0, - reference_density=first(boundary_zone.initial_condition.density)) + OpenBoundarySPHSystem(boundary_zone::Union{InFlow, OutFlow}; sound_speed, + fluid_system::FluidSystem, buffer_size::Integer, + reference_velocity=zeros(ndims(boundary_zone)), + reference_pressure=0.0, + reference_density=first(boundary_zone.initial_condition.density)) Open boundary system for in- and outflow particles. These open boundaries use the characteristic variables to propagate the appropriate values From 01819b45f4b6a7047022cef5ff2b5e4ca8061b88 Mon Sep 17 00:00:00 2001 From: LasNikas Date: Tue, 18 Jun 2024 09:00:19 +0200 Subject: [PATCH 100/107] add EDAC to the example --- examples/fluid/pipe_flow_2d.jl | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/examples/fluid/pipe_flow_2d.jl b/examples/fluid/pipe_flow_2d.jl index 1bd609ffa..3d642696e 100644 --- a/examples/fluid/pipe_flow_2d.jl +++ b/examples/fluid/pipe_flow_2d.jl @@ -55,17 +55,26 @@ n_buffer_particles = 4 * pipe.n_particles_per_dimension[2] smoothing_length = 3.0 * particle_spacing smoothing_kernel = WendlandC2Kernel{2}() +fluid_density_calculator = ContinuityDensity() + kinematic_viscosity = prescribed_velocity * domain_size[2] / reynolds_number -alpha = 8 * kinematic_viscosity / (smoothing_length * sound_speed) -fluid_density_calculator = ContinuityDensity() -viscosity = ArtificialViscosityMonaghan(; alpha, beta=0.0) +viscosity = ViscosityAdami(nu=kinematic_viscosity) -fluid_system = WeaklyCompressibleSPHSystem(pipe.fluid, fluid_density_calculator, - state_equation, smoothing_kernel, - smoothing_length, viscosity=viscosity, +fluid_system = EntropicallyDampedSPHSystem(pipe.fluid, smoothing_kernel, smoothing_length, + sound_speed, viscosity=viscosity, + density_calculator=fluid_density_calculator, buffer_size=n_buffer_particles) +# Alternatively the WCSPH scheme can be used +# alpha = 8 * kinematic_viscosity / (smoothing_length * sound_speed) +# viscosity = ArtificialViscosityMonaghan(; alpha, beta=0.0) + +# fluid_system = WeaklyCompressibleSPHSystem(pipe.fluid, fluid_density_calculator, +# state_equation, smoothing_kernel, +# smoothing_length, viscosity=viscosity, +# buffer_size=n_buffer_particles) + # ========================================================================================== # ==== Open Boundary function velocity_function(pos, t) From 417a5b3967f4636789359faf51b0d95df9387c6a Mon Sep 17 00:00:00 2001 From: LasNikas Date: Wed, 19 Jun 2024 07:17:19 +0200 Subject: [PATCH 101/107] implement suggestions --- .../open_boundary/characteristic_variables.jl | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/test/schemes/boundary/open_boundary/characteristic_variables.jl b/test/schemes/boundary/open_boundary/characteristic_variables.jl index b17b78176..1fe20722a 100644 --- a/test/schemes/boundary/open_boundary/characteristic_variables.jl +++ b/test/schemes/boundary/open_boundary/characteristic_variables.jl @@ -13,7 +13,7 @@ smoothing_length = 1.2particle_spacing # Prescribed quantities - reference_velocity = (pos, t) -> [1.0, 0.0] * t + reference_velocity = (pos, t) -> SVector(t, 0.0) reference_pressure = (pos, t) -> 50_000.0 * t reference_density = (pos, t) -> 1000.0 * t @@ -21,7 +21,7 @@ plane_points_1 = [[0.0, 0.0], [0.5, -0.5], [1.0, 0.5]] plane_points_2 = [[0.0, 1.0], [0.2, 2.0], [2.3, 0.5]] - @testset "Points $(i)" for i in eachindex(plane_points_1) + @testset "Points $i" for i in eachindex(plane_points_1) n_influenced = influenced_particles[i] plane_points = [plane_points_1[i], plane_points_2[i]] @@ -32,7 +32,7 @@ -normalize([-plane_size[2], plane_size[1]]), ] - @testset "Flow Direction $(j)" for j in eachindex(flow_directions) + @testset "Flow Direction $j" for j in eachindex(flow_directions) flow_direction = flow_directions[j] inflow = InFlow(; plane=plane_points, particle_spacing, density, flow_direction, open_boundary_layers) @@ -44,7 +44,7 @@ outflow, ] - @testset "$(nameof(typeof(boundary_zone)))" for boundary_zone in boundary_zones + @testset "`$(nameof(typeof(boundary_zone)))`" for boundary_zone in boundary_zones sign_ = (boundary_zone isa InFlow) ? 1 : -1 fluid = extrude_geometry(plane_points; particle_spacing, n_extrude=4, density, pressure, @@ -88,8 +88,8 @@ (pressure - reference_pressure(0, t)) end - # First evaluation - # Particles not influenced by the fluid have zero values + # First evaluation. + # Particles not influenced by the fluid have zero values. t1 = 2.0 TrixiParticles.evaluate_characteristics!(boundary_system, v, u, v0_ode, u0_ode, semi, t1) @@ -108,8 +108,8 @@ @test all(isapprox.(evaluated_vars1[3, :], 0.0)) end - # Second evaluation - # Particles not influenced by the fluid have previous values + # Second evaluation. + # Particles not influenced by the fluid have previous values. t2 = 3.0 TrixiParticles.evaluate_characteristics!(boundary_system, v, u, v0_ode, u0_ode, semi, t2) From b0f076e4c9d8ce81702a697476bfa673bc6e6066 Mon Sep 17 00:00:00 2001 From: LasNikas Date: Wed, 19 Jun 2024 11:05:53 +0200 Subject: [PATCH 102/107] modify tests --- test/Project.toml | 1 - .../boundary/open_boundary/boundary_zone.jl | 68 +++++++++---------- test/test_util.jl | 1 - 3 files changed, 34 insertions(+), 36 deletions(-) diff --git a/test/Project.toml b/test/Project.toml index 8412db44c..ef78271e3 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -6,7 +6,6 @@ GLM = "38e38edf-8417-5370-95a0-9cbb8c7f171a" Glob = "c27321d9-0574-5035-807b-f59d2c89b15c" JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" -Measurements = "eff96d63-e80a-5855-80a2-b1b0885c5ab7" OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed" Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" Polyester = "f517fe37-dbe3-4b94-8317-1923a5111588" diff --git a/test/schemes/boundary/open_boundary/boundary_zone.jl b/test/schemes/boundary/open_boundary/boundary_zone.jl index 41db0a719..e4ea50baa 100644 --- a/test/schemes/boundary/open_boundary/boundary_zone.jl +++ b/test/schemes/boundary/open_boundary/boundary_zone.jl @@ -6,7 +6,7 @@ plane_points_1 = [[0.0, 0.0], [0.5, -0.5], [1.0, 0.5]] plane_points_2 = [[0.0, 1.0], [0.2, 2.0], [2.3, 0.5]] - @testset "Points $(i)" for i in eachindex(plane_points_1) + @testset verbose=true "Points $(i)" for i in eachindex(plane_points_1) point_1 = plane_points_1[i] point_2 = plane_points_2[i] @@ -17,7 +17,7 @@ -normalize([-plane_size[2], plane_size[1]]), ] - @testset "Flow Direction $(j)" for j in eachindex(flow_directions) + @testset verbose=true "Flow Direction $(j)" for j in eachindex(flow_directions) inflow = InFlow(; plane=(point_1, point_2), particle_spacing, flow_direction=flow_directions[j], density=1.0, open_boundary_layers) @@ -30,7 +30,7 @@ outflow, ] - @testset "$boundary_zone" for boundary_zone in boundary_zones + @testset verbose=true "$(nameof(typeof(boundary_zone)))" for boundary_zone in boundary_zones zone_width = open_boundary_layers * boundary_zone.initial_condition.particle_spacing sign_ = (boundary_zone isa InFlow) ? -1 : 1 @@ -38,9 +38,10 @@ @test plane_points_1[i] == boundary_zone.zone_origin @test plane_points_2[i] - boundary_zone.zone_origin == boundary_zone.spanning_set[2] - @test sign_ * flow_directions[j] ≈ - normalize(boundary_zone.spanning_set[1]) - @test zone_width ≈ norm(boundary_zone.spanning_set[1]) + @test isapprox(sign_ * flow_directions[j], + normalize(boundary_zone.spanning_set[1]), atol=1e-14) + @test isapprox(zone_width, norm(boundary_zone.spanning_set[1]), + atol=1e-14) end end end @@ -63,7 +64,7 @@ [0.3113730847835541, 0.25057315826416016, -0.02374829351902008], ] - @testset "Points $(i)" for i in eachindex(plane_points_1) + @testset verbose=true "Points $(i)" for i in eachindex(plane_points_1) point_1 = plane_points_1[i] point_2 = plane_points_2[i] point_3 = plane_points_3[i] @@ -76,7 +77,7 @@ -normalize(cross(edge1, edge2)), ] - @testset "Flow Direction $(j)" for j in eachindex(flow_directions) + @testset verbose=true "Flow Direction $(j)" for j in eachindex(flow_directions) inflow = InFlow(; plane=(point_1, point_2, point_3), particle_spacing, flow_direction=flow_directions[j], density=1.0, open_boundary_layers) @@ -89,7 +90,7 @@ outflow, ] - @testset "$boundary_zone" for boundary_zone in boundary_zones + @testset verbose=true "$(nameof(typeof(boundary_zone)))" for boundary_zone in boundary_zones zone_width = open_boundary_layers * boundary_zone.initial_condition.particle_spacing sign_ = (boundary_zone isa InFlow) ? -1 : 1 @@ -99,9 +100,10 @@ boundary_zone.spanning_set[2] @test plane_points_3[i] - boundary_zone.zone_origin == boundary_zone.spanning_set[3] - @test sign_ * flow_directions[j] ≈ - normalize(boundary_zone.spanning_set[1]) - @test zone_width ≈ norm(boundary_zone.spanning_set[1]) + @test isapprox(sign_ * flow_directions[j], + normalize(boundary_zone.spanning_set[1]), atol=1e-14) + @test isapprox(zone_width, norm(boundary_zone.spanning_set[1]), + atol=1e-14) end end end @@ -123,26 +125,25 @@ outflow, ] - @testset "$(nameof(typeof(boundary_zone)))" for boundary_zone in boundary_zones - perturb_ = boundary_zone isa InFlow ? eps() : -eps() + @testset verbose=true "$(nameof(typeof(boundary_zone)))" for boundary_zone in boundary_zones + perturb_ = boundary_zone isa InFlow ? sqrt(eps()) : -sqrt(eps()) - point_3 = boundary_zone.spanning_set[1] + boundary_zone.zone_origin + point1 = plane_points[1] + point2 = plane_points[2] + point3 = boundary_zone.spanning_set[1] + boundary_zone.zone_origin query_points = Dict( "Behind" => ([-1.0, -1.0], false), "Before" => ([2.0, 2.0], false), - "On Point 1" => (plane_points[1], true), - "On Point 2" => (plane_points[2], true), - "On Point 3" => (point_3, true), - "Closely On Point 1" => (plane_points[1] .+ perturb_ * flow_direction, - false)) + "Closely On Point 1" => (point1 + perturb_ * flow_direction, false), + "Closely On Point 2" => (point2 + perturb_ * flow_direction, false), + "Closely On Point 3" => (point3 - perturb_ * flow_direction, false)) - @testset "$k" for k in keys(query_points) + @testset verbose=true "$k" for k in keys(query_points) (particle_position, evaluation) = query_points[k] @test evaluation == - TrixiParticles.is_in_boundary_zone(boundary_zone, - particle_position .± eps()) + TrixiParticles.is_in_boundary_zone(boundary_zone, particle_position) end end end @@ -164,24 +165,23 @@ outflow, ] - @testset "$(nameof(typeof(boundary_zone)))" for boundary_zone in boundary_zones + @testset verbose=true "$(nameof(typeof(boundary_zone)))" for boundary_zone in boundary_zones perturb_ = boundary_zone isa InFlow ? eps() : -eps() + point4 = boundary_zone.spanning_set[1] + boundary_zone.zone_origin + query_points = Dict( "Behind" => ([-1.0, -1.0, 1.2], false), "Before" => ([2.0, 2.0, -1.2], false), - "On Point 1" => (point1, true), - "On Point 2" => (point2, true), - "On Point 3" => (point3, true), - "On Point 4" => (boundary_zone.spanning_set[1] + boundary_zone.zone_origin, - true), - "Closely On Point 1" => (point1 .+ perturb_ * flow_direction, false)) - - @testset "$k" for k in keys(query_points) + "Closely On Point 1" => (point1 + perturb_ * flow_direction, false), + "Closely On Point 2" => (point2 + perturb_ * flow_direction, false), + "Closely On Point 3" => (point3 + perturb_ * flow_direction, false), + "Closely On Point 4" => (point4 - perturb_ * flow_direction, false)) + + @testset verbose=true "$k" for k in keys(query_points) (particle_position, evaluation) = query_points[k] @test evaluation == - TrixiParticles.is_in_boundary_zone(boundary_zone, - particle_position .± eps()) + TrixiParticles.is_in_boundary_zone(boundary_zone, particle_position) end end end diff --git a/test/test_util.jl b/test/test_util.jl index f061b32e7..5937cc68f 100644 --- a/test/test_util.jl +++ b/test/test_util.jl @@ -7,7 +7,6 @@ using DataFrames: DataFrame using JSON: JSON using QuadGK: quadgk # For integration in smoothing kernel tests using Random: Random # For rectangular patch -using Measurements: ± using Polyester: disable_polyester_threads # For `count_rhs_allocations` """ From 7a45ddfad65bd39933d5dcbb59bc055c581282aa Mon Sep 17 00:00:00 2001 From: LasNikas Date: Wed, 19 Jun 2024 11:20:15 +0200 Subject: [PATCH 103/107] adapt docs --- .../boundary/open_boundary/boundary_zones.jl | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/schemes/boundary/open_boundary/boundary_zones.jl b/src/schemes/boundary/open_boundary/boundary_zones.jl index c8d65da77..586d565b1 100644 --- a/src/schemes/boundary/open_boundary/boundary_zones.jl +++ b/src/schemes/boundary/open_boundary/boundary_zones.jl @@ -9,17 +9,17 @@ The specified plane (line in 2D or rectangle in 3D) will be extruded in upstream direction (the direction opposite to `flow_direction`) to create a box for the boundary zone. There are three ways to specify the actual shape of the inflow: 1. Don't pass `initial_condition` or `extrude_geometry`. The boundary zone box will then - be filled with inflow particles. -2. Pass a 1D shape in 2D or a 2D shape in 3D, which is then extruded in upstream direction - to create the inflow particles. + be filled with inflow particles (default). +2. Specify `extrude_geometry` by passing a 1D shape in 2D or a 2D shape in 3D, + which is then extruded in upstream direction to create the inflow particles. - In 2D, the shape must be either an initial condition with 2D coordinates, which lies on the line specified by `plane`, or an initial condition with 1D coordinates, which lies on the line specified by `plane` when a y-coordinate of `0` is added. - In 3D, the shape must be either an initial condition with 3D coordinates, which lies in the rectangle specified by `plane`, or an initial condition with 2D coordinates, which lies in the rectangle specified by `plane` when a z-coordinate of `0` is added. -3. Pass a 2D initial condition in 2D or a 3D initial condition in 3D, which will be used - for the inflow particles. +3. Specify `initial_condition` by passing a 2D initial condition in 2D or a 3D initial condition in 3D, + which will be used for the inflow particles. !!! note "Note" Particles outside the boundary zone box will be removed. @@ -145,17 +145,17 @@ The specified plane (line in 2D or rectangle in 3D) will be extruded in downstre direction (the direction in `flow_direction`) to create a box for the boundary zone. There are three ways to specify the actual shape of the outflow: 1. Don't pass `initial_condition` or `extrude_geometry`. The boundary zone box will then - be filled with outflow particles. -2. Pass a 1D shape in 2D or a 2D shape in 3D, which is then extruded in downstream direction - to create the outflow particles. + be filled with outflow particles (default). +2. Specify `extrude_geometry` by passing a 1D shape in 2D or a 2D shape in 3D, + which is then extruded in downstream direction to create the outflow particles. - In 2D, the shape must be either an initial condition with 2D coordinates, which lies on the line specified by `plane`, or an initial condition with 1D coordinates, which lies on the line specified by `plane` when a y-coordinate of `0` is added. - In 3D, the shape must be either an initial condition with 3D coordinates, which lies in the rectangle specified by `plane`, or an initial condition with 2D coordinates, which lies in the rectangle specified by `plane` when a z-coordinate of `0` is added. -3. Pass a 2D initial condition in 2D or a 3D initial condition in 3D, which will be used - for the outflow particles. +3. Specify `initial_condition` by passing a 2D initial condition in 2D or a 3D initial condition in 3D, + which will be used for the outflow particles. !!! note "Note" Particles outside the boundary zone box will be removed. From 57e2639dc7025594ee58299692185c3874c92e99 Mon Sep 17 00:00:00 2001 From: LasNikas Date: Wed, 19 Jun 2024 11:32:57 +0200 Subject: [PATCH 104/107] add `initial_callback_flag` --- src/general/semidiscretization.jl | 6 ++++++ src/general/system.jl | 3 +++ src/schemes/boundary/open_boundary/system.jl | 6 ++++++ 3 files changed, 15 insertions(+) diff --git a/src/general/semidiscretization.jl b/src/general/semidiscretization.jl index c9b7e111a..f2d5bb18d 100644 --- a/src/general/semidiscretization.jl +++ b/src/general/semidiscretization.jl @@ -293,6 +293,9 @@ function semidiscretize(semi, tspan; reset_threads=true, data_type=nothing) # Initialize this system initialize!(system, neighborhood_search) + + # Only for systems requiring a mandatory callback + initial_callback_flag!(system) end end @@ -355,6 +358,9 @@ function restart_with!(semi, sol; reset_threads=true) u = wrap_u(sol.u[end].x[2], system, semi) restart_with!(system, v, u) + + # Only for systems requiring a mandatory callback + initial_callback_flag!(system) end return semi diff --git a/src/general/system.jl b/src/general/system.jl index 5c937ce80..77625d45b 100644 --- a/src/general/system.jl +++ b/src/general/system.jl @@ -119,3 +119,6 @@ end function update_final!(system, v, u, v_ode, u_ode, semi, t; update_from_callback=false) return system end + +# Only for systems requiring a mandatory callback +initial_callback_flag!(system) = system diff --git a/src/schemes/boundary/open_boundary/system.jl b/src/schemes/boundary/open_boundary/system.jl index a8e1fd326..4ba927e64 100644 --- a/src/schemes/boundary/open_boundary/system.jl +++ b/src/schemes/boundary/open_boundary/system.jl @@ -146,6 +146,12 @@ function Base.show(io::IO, ::MIME"text/plain", system::OpenBoundarySPHSystem) end end +function initial_callback_flag!(system::OpenBoundarySPHSystem) + system.update_callback_used[] = false + + return system +end + update_callback_used!(system::OpenBoundarySPHSystem) = system.update_callback_used[] = true @inline source_terms(system::OpenBoundarySPHSystem) = nothing From 9c80e3fd42cb0ad72c6655dd000e547e7b7136f1 Mon Sep 17 00:00:00 2001 From: LasNikas Date: Wed, 19 Jun 2024 11:46:41 +0200 Subject: [PATCH 105/107] add to `NEWS.md` and `README.md` --- NEWS.md | 10 +++++++--- README.md | 2 +- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/NEWS.md b/NEWS.md index ffe272e8a..4f846f0f5 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,8 +1,8 @@ # Changelog TrixiParticles.jl follows the interpretation of [semantic versioning (semver)](https://julialang.github.io/Pkg.jl/dev/compatibility/#Version-specifier-format-1) -used in the Julia ecosystem. Notable changes will be documented in this file for human readability. -We aim at 3 to 4 month between major release versions and about 2 weeks between minor versions. +used in the Julia ecosystem. Notable changes will be documented in this file for human readability. +We aim at 3 to 4 month between major release versions and about 2 weeks between minor versions. ## Version 0.2.x @@ -14,11 +14,15 @@ We aim at 3 to 4 month between major release versions and about 2 weeks between ### Deprecated +## Version 0.1.3 + +### Added +Open boundaries using the method of characteristics based on the work of Lastiwka et al., "Permeable and non-reflecting boundary conditions in SPH" (2009) was added for WCSPH and EDAC. ## Version 0.1.2 ### Added -A surface tension and adhesion model based on the work by Akinci et al., "Versatile Surface Tension and Adhesion for SPH Fluids" (2013) was added to WCSPH +A surface tension and adhesion model based on the work by Akinci et al., "Versatile Surface Tension and Adhesion for SPH Fluids" (2013) was added to WCSPH. ## Version 0.1.1 diff --git a/README.md b/README.md index b40e68fbc..76b288ed2 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ Its features include: ## Features - Incompressible Navier-Stokes - Methods: Weakly Compressible Smoothed Particle Hydrodynamics (WCSPH), Entropically Damped Artificial Compressibility (EDAC) - - Models: Surface Tension + - Models: Surface Tension, Open Boundaries - Solid-body mechanics - Methods: Total Lagrangian SPH (TLSPH), Discrete Element Method (DEM) - Fluid-Structure Interaction From 4fed7adcf2168740468575e8c8bb54dc5bf405b5 Mon Sep 17 00:00:00 2001 From: LasNikas Date: Wed, 19 Jun 2024 14:10:25 +0200 Subject: [PATCH 106/107] implement suggestions --- NEWS.md | 2 +- src/general/semidiscretization.jl | 4 ++-- src/general/system.jl | 2 +- src/schemes/boundary/open_boundary/system.jl | 2 +- test/schemes/boundary/open_boundary/boundary_zone.jl | 8 ++++---- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/NEWS.md b/NEWS.md index 4f846f0f5..5d7a295d8 100644 --- a/NEWS.md +++ b/NEWS.md @@ -17,7 +17,7 @@ We aim at 3 to 4 month between major release versions and about 2 weeks between ## Version 0.1.3 ### Added -Open boundaries using the method of characteristics based on the work of Lastiwka et al., "Permeable and non-reflecting boundary conditions in SPH" (2009) was added for WCSPH and EDAC. +Open boundaries using the method of characteristics based on the work of Lastiwka et al., "Permeable and non-reflecting boundary conditions in SPH" (2009) were added for WCSPH and EDAC. ## Version 0.1.2 diff --git a/src/general/semidiscretization.jl b/src/general/semidiscretization.jl index f2d5bb18d..8aac73a63 100644 --- a/src/general/semidiscretization.jl +++ b/src/general/semidiscretization.jl @@ -295,7 +295,7 @@ function semidiscretize(semi, tspan; reset_threads=true, data_type=nothing) initialize!(system, neighborhood_search) # Only for systems requiring a mandatory callback - initial_callback_flag!(system) + reset_callback_flag(system) end end @@ -360,7 +360,7 @@ function restart_with!(semi, sol; reset_threads=true) restart_with!(system, v, u) # Only for systems requiring a mandatory callback - initial_callback_flag!(system) + reset_callback_flag(system) end return semi diff --git a/src/general/system.jl b/src/general/system.jl index 77625d45b..814782631 100644 --- a/src/general/system.jl +++ b/src/general/system.jl @@ -121,4 +121,4 @@ function update_final!(system, v, u, v_ode, u_ode, semi, t; update_from_callback end # Only for systems requiring a mandatory callback -initial_callback_flag!(system) = system +reset_callback_flag(system) = system diff --git a/src/schemes/boundary/open_boundary/system.jl b/src/schemes/boundary/open_boundary/system.jl index 4ba927e64..43c0a6ff1 100644 --- a/src/schemes/boundary/open_boundary/system.jl +++ b/src/schemes/boundary/open_boundary/system.jl @@ -146,7 +146,7 @@ function Base.show(io::IO, ::MIME"text/plain", system::OpenBoundarySPHSystem) end end -function initial_callback_flag!(system::OpenBoundarySPHSystem) +function reset_callback_flag(system::OpenBoundarySPHSystem) system.update_callback_used[] = false return system diff --git a/test/schemes/boundary/open_boundary/boundary_zone.jl b/test/schemes/boundary/open_boundary/boundary_zone.jl index e4ea50baa..7a34a4bca 100644 --- a/test/schemes/boundary/open_boundary/boundary_zone.jl +++ b/test/schemes/boundary/open_boundary/boundary_zone.jl @@ -6,7 +6,7 @@ plane_points_1 = [[0.0, 0.0], [0.5, -0.5], [1.0, 0.5]] plane_points_2 = [[0.0, 1.0], [0.2, 2.0], [2.3, 0.5]] - @testset verbose=true "Points $(i)" for i in eachindex(plane_points_1) + @testset verbose=true "Points $i" for i in eachindex(plane_points_1) point_1 = plane_points_1[i] point_2 = plane_points_2[i] @@ -17,7 +17,7 @@ -normalize([-plane_size[2], plane_size[1]]), ] - @testset verbose=true "Flow Direction $(j)" for j in eachindex(flow_directions) + @testset verbose=true "Flow Direction $j" for j in eachindex(flow_directions) inflow = InFlow(; plane=(point_1, point_2), particle_spacing, flow_direction=flow_directions[j], density=1.0, open_boundary_layers) @@ -64,7 +64,7 @@ [0.3113730847835541, 0.25057315826416016, -0.02374829351902008], ] - @testset verbose=true "Points $(i)" for i in eachindex(plane_points_1) + @testset verbose=true "Points $i" for i in eachindex(plane_points_1) point_1 = plane_points_1[i] point_2 = plane_points_2[i] point_3 = plane_points_3[i] @@ -77,7 +77,7 @@ -normalize(cross(edge1, edge2)), ] - @testset verbose=true "Flow Direction $(j)" for j in eachindex(flow_directions) + @testset verbose=true "Flow Direction $j" for j in eachindex(flow_directions) inflow = InFlow(; plane=(point_1, point_2, point_3), particle_spacing, flow_direction=flow_directions[j], density=1.0, open_boundary_layers) From b0d65634fd560025a96d6713bb952defe80b332e Mon Sep 17 00:00:00 2001 From: LasNikas Date: Wed, 19 Jun 2024 14:31:44 +0200 Subject: [PATCH 107/107] fix typo --- src/general/semidiscretization.jl | 4 ++-- src/general/system.jl | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/general/semidiscretization.jl b/src/general/semidiscretization.jl index 8aac73a63..73c1fe56d 100644 --- a/src/general/semidiscretization.jl +++ b/src/general/semidiscretization.jl @@ -295,7 +295,7 @@ function semidiscretize(semi, tspan; reset_threads=true, data_type=nothing) initialize!(system, neighborhood_search) # Only for systems requiring a mandatory callback - reset_callback_flag(system) + reset_callback_flag!(system) end end @@ -360,7 +360,7 @@ function restart_with!(semi, sol; reset_threads=true) restart_with!(system, v, u) # Only for systems requiring a mandatory callback - reset_callback_flag(system) + reset_callback_flag!(system) end return semi diff --git a/src/general/system.jl b/src/general/system.jl index 814782631..c3f10caad 100644 --- a/src/general/system.jl +++ b/src/general/system.jl @@ -121,4 +121,4 @@ function update_final!(system, v, u, v_ode, u_ode, semi, t; update_from_callback end # Only for systems requiring a mandatory callback -reset_callback_flag(system) = system +reset_callback_flag!(system) = system