Skip to content

Commit 59b2ee8

Browse files
authored
Merge branch 'main' into oriented-bbox
2 parents b8beca6 + 433e394 commit 59b2ee8

File tree

17 files changed

+467
-117
lines changed

17 files changed

+467
-117
lines changed

NEWS.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,13 @@ TrixiParticles.jl follows the interpretation of
44
[semantic versioning (semver)](https://julialang.github.io/Pkg.jl/dev/compatibility/#Version-specifier-format-1)
55
used in the Julia ecosystem. Notable changes will be documented in this file for human readability.
66

7+
## Version 0.4.2
8+
9+
### Features
10+
11+
- Added `OscillatingMotion2D` to create an oscillating `PrescribedMotion` combining
12+
translation and rotation (#915).
13+
714
## Version 0.4.1
815

916
### Features

docs/src/systems/boundary.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@
88
BoundaryDEMSystem
99
```
1010

11-
```@docs
12-
PrescribedMotion
11+
```@autodocs
12+
Modules = [TrixiParticles]
13+
Pages = [joinpath("schemes", "boundary", "prescribed_motion.jl")]
1314
```
1415

1516

examples/structure/oscillating_beam_2d.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,8 @@ structure_system = TotalLagrangianSPHSystem(structure, smoothing_kernel, smoothi
6363
material.E, material.nu,
6464
n_clamped_particles=nparticles(clamped_particles),
6565
acceleration=(0.0, -gravity),
66-
penalty_force=nothing, viscosity=nothing)
66+
penalty_force=nothing, viscosity=nothing,
67+
clamped_particles_motion=nothing)
6768

6869
# ==========================================================================================
6970
# ==== Simulation

src/TrixiParticles.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ export BoundaryModelMonaghanKajtar, BoundaryModelDummyParticles, AdamiPressureEx
8989
BernoulliPressureExtrapolation
9090
export FirstOrderMirroring, ZerothOrderMirroring, SimpleMirroring
9191
export HertzContactModel, LinearContactModel
92-
export PrescribedMotion
92+
export PrescribedMotion, OscillatingMotion2D
9393
export examples_dir, validation_dir
9494
export trixi2vtk, vtk2trixi
9595
export RectangularTank, RectangularShape, SphereShape, ComplexShape

src/general/semidiscretization.jl

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -402,10 +402,14 @@ end
402402
function initialize_neighborhood_searches!(semi)
403403
foreach_system(semi) do system
404404
foreach_system(semi) do neighbor
405+
# TODO Initialize after adapting to the GPU.
406+
# Currently, this cannot use `semi.parallelization_backend`
407+
# because data is still on the CPU.
405408
PointNeighbors.initialize!(get_neighborhood_search(system, neighbor, semi),
406409
initial_coordinates(system),
407410
initial_coordinates(neighbor),
408-
eachindex_y=each_active_particle(neighbor))
411+
eachindex_y=each_active_particle(neighbor),
412+
parallelization_backend=PolyesterBackend())
409413
end
410414
end
411415

src/io/write_vtk.jl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,9 @@ function write2vtk!(vtk, v, u, t, system::TotalLagrangianSPHSystem)
381381
initial_coords(system, particle)
382382
for particle in eachparticle(system)]
383383

384+
vtk["is_clamped"] = vcat(fill(0, system.n_integrated_particles),
385+
fill(1, nparticles(system) - system.n_integrated_particles))
386+
384387
vtk["lame_lambda"] = system.lame_lambda
385388
vtk["lame_mu"] = system.lame_mu
386389
vtk["young_modulus"] = system.young_modulus

src/schemes/boundary/prescribed_motion.jl

Lines changed: 103 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@
1111
if the neighborhood search will be updated.
1212
1313
# Keyword Arguments
14-
- `moving_particles`: Indices of moving particles. Default is each particle in the system.
14+
- `moving_particles`: Indices of moving particles. Default is each particle in the system
15+
for the [`WallBoundarySystem`](@ref) and all clamped particles
16+
for the [`TotalLagrangianSPHSystem`](@ref).
1517
1618
# Examples
1719
```jldoctest; output = false
@@ -48,7 +50,9 @@ function PrescribedMotion(movement_function, is_moving; moving_particles=nothing
4850
return PrescribedMotion(movement_function, is_moving, moving_particles)
4951
end
5052

51-
function initialize!(prescribed_motion::PrescribedMotion, initial_condition)
53+
function initialize_prescribed_motion!(prescribed_motion::PrescribedMotion,
54+
initial_condition,
55+
n_clamped_particles=nparticles(initial_condition))
5256
# Test `movement_function` return type
5357
pos = extract_svector(initial_condition.coordinates,
5458
Val(size(initial_condition.coordinates, 1)), 1)
@@ -57,23 +61,34 @@ function initialize!(prescribed_motion::PrescribedMotion, initial_condition)
5761
"Returning regular `Vector`s causes allocations and significant performance overhead."
5862
end
5963

60-
# Empty `moving_particles` means all particles are moving
64+
# Empty `moving_particles` means all clamped particles are moving.
65+
# For boundaries, all particles are considered clamped.
6166
if isempty(prescribed_motion.moving_particles)
6267
# Default is an empty vector, since the number of particles is not known when
6368
# instantiating `PrescribedMotion`.
64-
resize!(prescribed_motion.moving_particles, nparticles(initial_condition))
65-
prescribed_motion.moving_particles .= collect(1:nparticles(initial_condition))
69+
resize!(prescribed_motion.moving_particles, n_clamped_particles)
70+
71+
# Clamped particles for TLSPH are the last `n_clamped_particles` in the system
72+
first_particle = nparticles(initial_condition) - n_clamped_particles + 1
73+
clamped_particles = first_particle:nparticles(initial_condition)
74+
prescribed_motion.moving_particles .= collect(clamped_particles)
6675
end
76+
77+
return prescribed_motion
78+
end
79+
80+
function initialize_prescribed_motion!(::Nothing, initial_condition,
81+
n_clamped_particles=nparticles(initial_condition))
82+
return nothing
6783
end
6884

69-
function (prescribed_motion::PrescribedMotion)(system, t, semi)
70-
(; coordinates, cache) = system
85+
function (prescribed_motion::PrescribedMotion)(coordinates, velocity, acceleration,
86+
ismoving, system, semi, t)
7187
(; movement_function, is_moving, moving_particles) = prescribed_motion
72-
(; acceleration, velocity) = cache
7388

74-
system.ismoving[] = is_moving(t)
89+
ismoving[] = is_moving(t)
7590

76-
is_moving(t) || return system
91+
is_moving(t) || return nothing
7792

7893
@threaded semi for particle in moving_particles
7994
pos_original = initial_coords(system, particle)
@@ -90,11 +105,85 @@ function (prescribed_motion::PrescribedMotion)(system, t, semi)
90105
end
91106
end
92107

93-
return system
108+
return nothing
94109
end
95110

96-
function (prescribed_motion::Nothing)(system::AbstractSystem, t, semi)
97-
system.ismoving[] = false
111+
"""
112+
OscillatingMotion2D(; frequency, translation_vector, rotation_angle, rotation_center,
113+
rotation_phase_offset=0, tspan=(-Inf, Inf),
114+
ramp_up_tspan=(0.0, 0.0), moving_particles=nothing)
115+
116+
Create a [`PrescribedMotion`](@ref) for a 2D oscillating motion of particles.
117+
The motion is a combination of a translation and a rotation around a center point
118+
with the same frequency. Note that a phase offset can be specified for a rotation
119+
that is out of sync with the translation.
120+
121+
Create a [`PrescribedMotion`](@ref) for 2D oscillatory particle motion
122+
that combines a translation and a rotation about a specified center.
123+
Both use the same frequency; an optional phase offset allows the rotation
124+
to be out of phase with the translation.
125+
126+
# Keywords
127+
- `frequency`: Frequency of the oscillation in Hz.
128+
- `translation_vector`: Vector specifying the amplitude and direction of the translation.
129+
- `rotation_angle`: Maximum rotation angle in radians.
130+
- `rotation_center`: Center point of the rotation as an `SVector`.
131+
132+
# Keywords (optional)
133+
- `rotation_phase_offset=0`: Phase offset of the rotation in number of periods (`1` = 1 period).
134+
- `tspan=(-Inf, Inf)`: Time span in which the motion is active. Outside of this time span,
135+
particles remain at their last position.
136+
- `ramp_up_tspan`: Time span in which the motion is smoothly ramped up from zero
137+
to full amplitude.
138+
Outside of this time span, the motion has full amplitude.
139+
Default is no ramp-up.
140+
- `moving_particles`: Indices of moving particles. Default is each particle in the system
141+
for the [`WallBoundarySystem`](@ref) and all clamped particles
142+
for the [`TotalLagrangianSPHSystem`](@ref).
143+
144+
# Examples
145+
```jldoctest; output = false, filter = r"PrescribedMotion{.*"
146+
# Oscillating motion with frequency 1 Hz, translation amplitude 1 in x-direction,
147+
# rotation angle 90 degrees (pi/2) around the origin.
148+
frequency = 1.0
149+
translation_vector = SVector(1.0, 0.0)
150+
rotation_angle = pi / 2
151+
rotation_center = SVector(0.0, 0.0)
152+
153+
motion = OscillatingMotion2D(frequency, translation_vector, rotation_angle,
154+
rotation_center)
155+
156+
# output
157+
PrescribedMotion{...}
158+
"""
159+
function OscillatingMotion2D(; frequency, translation_vector, rotation_angle,
160+
rotation_center, rotation_phase_offset=0, tspan=(-Inf, Inf),
161+
ramp_up_tspan=(0.0, 0.0), moving_particles=nothing)
162+
@inline function movement_function(x, t)
163+
if isfinite(tspan[1])
164+
t = t - tspan[1]
165+
end
166+
167+
sin_scaled = sin(frequency * 2pi * t)
168+
translation = sin_scaled * translation_vector
169+
x_centered = x .- rotation_center
170+
sin_scaled_offset = sin(2pi * (frequency * t - rotation_phase_offset))
171+
angle = rotation_angle * sin_scaled_offset
172+
rotated = SVector(x_centered[1] * cos(angle) - x_centered[2] * sin(angle),
173+
x_centered[1] * sin(angle) + x_centered[2] * cos(angle))
174+
175+
result = rotated .+ rotation_center .+ translation
176+
177+
if ramp_up_tspan[2] > ramp_up_tspan[1] && ramp_up_tspan[1] <= t <= ramp_up_tspan[2]
178+
# Apply a smoothstep ramp-up during the ramp-up time span
179+
t_rel = (t - ramp_up_tspan[1]) / (ramp_up_tspan[2] - ramp_up_tspan[1])
180+
ramp_factor = 3 * t_rel^2 - 2 * t_rel^3
181+
return result * ramp_factor + (1 - ramp_factor) * x
182+
end
183+
return result
184+
end
185+
186+
is_moving(t) = tspan[1] <= t <= tspan[2]
98187

99-
return system
188+
return PrescribedMotion(movement_function, is_moving; moving_particles)
100189
end

src/schemes/boundary/wall_boundary/system.jl

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ The interaction between fluid and boundary particles is specified by the boundar
99
- `initial_condition`: Initial condition (see [`InitialCondition`](@ref))
1010
- `boundary_model`: Boundary model (see [Boundary Models](@ref boundary_models))
1111
12-
# Keyword Arguments
12+
# Keywords
1313
- `prescribed_motion`: For moving boundaries, a [`PrescribedMotion`](@ref) can be passed.
1414
- `adhesion_coefficient`: Coefficient specifying the adhesion of a fluid to the surface.
1515
Note: currently it is assumed that all fluids have the same adhesion coefficient.
@@ -42,12 +42,11 @@ function WallBoundarySystem(initial_condition, model; prescribed_motion=nothing,
4242
coordinates = copy(initial_condition.coordinates)
4343

4444
ismoving = Ref(!isnothing(prescribed_motion))
45-
initialize!(prescribed_motion, initial_condition)
45+
initialize_prescribed_motion!(prescribed_motion, initial_condition)
4646

4747
cache = create_cache_boundary(prescribed_motion, initial_condition)
4848
cache = (cache..., color=Int(color_value))
4949

50-
# Because of dispatches boundary model needs to be first!
5150
return WallBoundarySystem(initial_condition, coordinates, model, prescribed_motion,
5251
ismoving, adhesion_coefficient, cache)
5352
end
@@ -105,7 +104,7 @@ end
105104
return current_velocity(v, system, system.prescribed_motion, particle)
106105
end
107106

108-
@inline function current_velocity(v, system, movement, particle)
107+
@inline function current_velocity(v, system, prescribed_motion, particle)
109108
(; cache, ismoving) = system
110109

111110
if ismoving[]
@@ -115,7 +114,7 @@ end
115114
return zero(SVector{ndims(system), eltype(system)})
116115
end
117116

118-
@inline function current_velocity(v, system, movement::Nothing, particle)
117+
@inline function current_velocity(v, system, prescribed_motion::Nothing, particle)
119118
return zero(SVector{ndims(system), eltype(system)})
120119
end
121120

@@ -127,7 +126,8 @@ end
127126
return current_acceleration(system, system.prescribed_motion, particle)
128127
end
129128

130-
@inline function current_acceleration(system, ::PrescribedMotion, particle)
129+
@inline function current_acceleration(system::WallBoundarySystem, ::PrescribedMotion,
130+
particle)
131131
(; cache, ismoving) = system
132132

133133
if ismoving[]
@@ -137,7 +137,7 @@ end
137137
return zero(SVector{ndims(system), eltype(system)})
138138
end
139139

140-
@inline function current_acceleration(system, ::Nothing, particle)
140+
@inline function current_acceleration(system::WallBoundarySystem, ::Nothing, particle)
141141
return zero(SVector{ndims(system), eltype(system)})
142142
end
143143

@@ -177,7 +177,21 @@ end
177177
function update_positions!(system::WallBoundarySystem, v, u, v_ode, u_ode, semi, t)
178178
(; prescribed_motion) = system
179179

180-
prescribed_motion(system, t, semi)
180+
apply_prescribed_motion!(system, prescribed_motion, semi, t)
181+
end
182+
183+
function apply_prescribed_motion!(system::WallBoundarySystem,
184+
prescribed_motion::PrescribedMotion, semi, t)
185+
(; ismoving, coordinates, cache) = system
186+
(; acceleration, velocity) = cache
187+
188+
prescribed_motion(coordinates, velocity, acceleration, ismoving, system, semi, t)
189+
190+
return system
191+
end
192+
193+
function apply_prescribed_motion!(system::WallBoundarySystem, ::Nothing, semi, t)
194+
return system
181195
end
182196

183197
function update_quantities!(system::WallBoundarySystem, v, u, v_ode, u_ode, semi, t)

src/schemes/fluid/entropically_damped_sph/system.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ See [Entropically Damped Artificial Compressibility for SPH](@ref edac) for more
2222
- `smoothing_length`: Smoothing length to be used for this system.
2323
See [Smoothing Kernels](@ref smoothing_kernel).
2424
25-
# Keyword Arguments
25+
# Keywords
2626
- `viscosity`: Viscosity model for this system (default: no viscosity).
2727
Recommended: [`ViscosityAdami`](@ref).
2828
- `acceleration`: Acceleration vector for the system. (default: zero vector)

src/schemes/fluid/surface_normal_sph.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
55
Color field based computation of the interface normals.
66
7-
# Keyword Arguments
7+
# Keywords
88
- `boundary_contact_threshold=0.1`: If this threshold is reached the fluid is assumed to be in contact with the boundary.
99
- `interface_threshold=0.01`: Threshold for normals to be removed as being invalid.
1010
- `ideal_density_threshold=0.0`: Assume particles are inside if they are above this threshold, which is relative to the `ideal_neighbor_count`.

0 commit comments

Comments
 (0)