Skip to content

Commit e36bd9b

Browse files
authored
Merge branch 'main' into dev
2 parents b9d091c + a724d36 commit e36bd9b

14 files changed

Lines changed: 251 additions & 98 deletions

File tree

docs/src/refs.bib

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ @article{Balsara1995
108108
pages = {357-372},
109109
year = {1995},
110110
issn = {0021-9991},
111-
doi = {https://doi.org/10.1016/S0021-9991(95)90221-X},
111+
doi = {10.1016/S0021-9991(95)90221-X},
112112
url = {https://www.sciencedirect.com/science/article/pii/S002199919590221X},
113113
author = {Dinshaw S. Balsara},
114114
}
@@ -406,6 +406,18 @@ @Article{Li1996
406406
publisher = {Elsevier BV},
407407
}
408408

409+
@article{Lin2015,
410+
author = {Lin, Jun and Naceur, Hakim and Coutellier, Daniel and Laksimi, Abdel},
411+
journal = {Engineering Computations},
412+
title = {Geometrically nonlinear analysis of two-dimensional structures using an improved smoothed particle hydrodynamics method},
413+
year = {2015},
414+
issn = {0264-4401},
415+
volume = {32},
416+
number = {3},
417+
pages = {779--805},
418+
doi = {10.1108/EC-12-2013-0306},
419+
}
420+
409421
@Article{Liu2006,
410422
author = {Liu, M.B. and Liu, G.R.},
411423
journal = {Applied Numerical Mathematics},
@@ -544,7 +556,7 @@ @article{Morris2000
544556
number = {3},
545557
pages = {333-353},
546558
keywords = {interfacial flow, meshless methods, surface tension},
547-
doi = {https://doi.org/10.1002/1097-0363(20000615)33:3<333::AID-FLD11>3.0.CO;2-7},
559+
doi = {10.1002/1097-0363(20000615)33:3<333::AID-FLD11>3.0.CO;2-7},
548560
year = {2000}
549561
}
550562

@@ -735,8 +747,6 @@ @Article{Wendland1995
735747
publisher = {Springer Science and Business Media LLC},
736748
}
737749

738-
@Comment{jabref-meta: databaseType:bibtex;}
739-
740750
@book{Lange2005,
741751
author = {{Lange's Handbook of Chemistry}},
742752
title = {Lange's Handbook of Chemistry},

docs/src/systems/fluid.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ by Balsara ([Balsara1995](@cite)) or Morris ([Morris1997](@cite)).
5555

5656
##### Mathematical Formulation
5757

58-
The force exerted by particle `b` on particle `a` due to artificial viscosity is given by:
58+
The force exerted by particle ``b`` on particle ``a`` due to artificial viscosity is given by:
5959

6060
```math
6161
F_{ab}^{\text{AV}} = - m_a m_b \Pi_{ab} \nabla W_{ab}

docs/src/systems/total_lagrangian_sph.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,3 +102,30 @@ where the error vector is defined as
102102
Modules = [TrixiParticles]
103103
Pages = [joinpath("schemes", "solid", "total_lagrangian_sph", "penalty_force.jl")]
104104
```
105+
106+
## Viscosity
107+
108+
Another technique that is used to correct the hourglass instability is artificial viscosity.
109+
Hereby, a viscosity term designed for fluids (see [Viscosity](@ref viscosity_sph)) is applied.
110+
First, the force ``f_{ab}^{\text{fluid}}`` exerted by particle ``b`` on particle ``a``
111+
due to artificial viscosity is computed as if both particles were fluid particles
112+
(see [Viscosity](@ref viscosity_sph) for the relevant equations).
113+
Then, according to [Lin et al. (2015)](@cite Lin2015), this force can be applied to TLSPH
114+
with the following conversion:
115+
```math
116+
f_{ab}^{\text{AV}} = \det(F_a) F_a^{-1} f_{ab}^{\text{fluid}},
117+
```
118+
where ``F_a`` is the deformation gradient at particle ``a``.
119+
120+
We found that artificial viscosity is not effective at correcting the incorrect
121+
particle positions due to hourglass modes.
122+
It does however prevent particles from oscillating between different incorrect positions,
123+
which develops into an instability if uncorrected.
124+
We still recommend penalty force over artificial viscosity to correct hourglass modes
125+
as penalty force is specifically designed to correct the incorrect particle positions.
126+
127+
In some FSI simulations, notably when very thin structures or structures with low material
128+
density are present, instabilities in the fluid can be induced by the structure.
129+
In these cases, artificial viscosity is effective at stabilizing the fluid close to the
130+
structure, and we recommend using it in combination with penalty force to both
131+
prevent hourglass modes and stabilize the fluid close to the fluid-structure interface.

examples/solid/oscillating_beam_2d.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ solid_system = TotalLagrangianSPHSystem(solid, smoothing_kernel, smoothing_lengt
6363
material.E, material.nu,
6464
n_fixed_particles=nparticles(fixed_particles),
6565
acceleration=(0.0, -gravity),
66-
penalty_force=nothing)
66+
penalty_force=nothing, viscosity=nothing)
6767

6868
# ==========================================================================================
6969
# ==== Simulation

src/schemes/fluid/viscosity.jl

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
2-
# Unpack the neighboring systems viscosity to dispatch on the viscosity type
1+
# Unpack the neighboring systems viscosity to dispatch on the viscosity type.
2+
# This function is only necessary to allow `nothing` as viscosity.
3+
# Otherwise, we could just apply the viscosity as a function directly.
34
@propagate_inbounds function dv_viscosity(particle_system, neighbor_system,
45
v_particle_system, v_neighbor_system,
56
particle, neighbor, pos_diff, distance,
@@ -98,6 +99,7 @@ end
9899

99100
smoothing_length_particle = smoothing_length(particle_system, particle)
100101
smoothing_length_neighbor = smoothing_length(particle_system, neighbor)
102+
smoothing_length_average = (smoothing_length_particle + smoothing_length_neighbor) / 2
101103

102104
nu_a = kinematic_viscosity(particle_system,
103105
viscosity_model(neighbor_system, particle_system),
@@ -106,7 +108,6 @@ end
106108
viscosity_model(particle_system, neighbor_system),
107109
smoothing_length_neighbor, sound_speed)
108110

109-
smoothing_length_average = (smoothing_length_particle + smoothing_length_neighbor) / 2
110111
pi_ab = viscosity(sound_speed, v_diff, pos_diff, distance, rho_mean, rho_a, rho_b,
111112
smoothing_length_average, grad_kernel, nu_a, nu_b)
112113

src/schemes/solid/total_lagrangian_sph/penalty_force.jl

Lines changed: 19 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -14,45 +14,35 @@ struct PenaltyForceGanzenmueller{ELTYPE}
1414
end
1515
end
1616

17-
@inline function calc_penalty_force!(dv, particle, neighbor, initial_pos_diff,
18-
initial_distance, system, m_a, m_b, rho_a, rho_b,
19-
penalty_force::PenaltyForceGanzenmueller)
20-
(; young_modulus) = system
21-
22-
current_pos_diff = current_coords(system, particle) -
23-
current_coords(system, neighbor)
24-
current_distance = norm(current_pos_diff)
17+
@inline function dv_penalty_force(penalty_force::Nothing,
18+
particle, neighbor, initial_pos_diff, initial_distance,
19+
current_pos_diff, current_distance,
20+
system, m_a, m_b, rho_a, rho_b)
21+
return zero(initial_pos_diff)
22+
end
2523

26-
volume_particle = m_a / rho_a
27-
volume_neighbor = m_b / rho_b
24+
@inline function dv_penalty_force(penalty_force::PenaltyForceGanzenmueller,
25+
particle, neighbor, initial_pos_diff, initial_distance,
26+
current_pos_diff, current_distance,
27+
system, m_a, m_b, rho_a, rho_b)
28+
volume_a = m_a / rho_a
29+
volume_b = m_b / rho_b
2830

2931
kernel_weight = smoothing_kernel(system, initial_distance, particle)
3032

31-
J_a = deformation_gradient(system, particle)
32-
J_b = deformation_gradient(system, neighbor)
33+
F_a = deformation_gradient(system, particle)
34+
F_b = deformation_gradient(system, neighbor)
3335

3436
# Use the symmetry of epsilon to simplify computations
35-
eps_sum = (J_a + J_b) * initial_pos_diff - 2 * current_pos_diff
37+
eps_sum = (F_a + F_b) * initial_pos_diff - 2 * current_pos_diff
3638
delta_sum = dot(eps_sum, current_pos_diff) / current_distance
3739

38-
E = young_modulus_per_particle(young_modulus, particle)
40+
E = young_modulus(system, particle)
3941

40-
f = (penalty_force.alpha / 2) * volume_particle * volume_neighbor *
42+
f = (penalty_force.alpha / 2) * volume_a * volume_b *
4143
kernel_weight / initial_distance^2 * E * delta_sum * current_pos_diff /
4244
current_distance
4345

44-
@inbounds for i in 1:ndims(system)
45-
# Divide force by mass to obtain acceleration
46-
dv[i, particle] += f[i] / m_a
47-
end
48-
49-
return dv
50-
end
51-
52-
function young_modulus_per_particle(young_modulus::AbstractVector, particle)
53-
return young_modulus[particle]
54-
end
55-
56-
function young_modulus_per_particle(young_modulus, particle)
57-
return young_modulus
46+
# Divide force by mass to obtain acceleration
47+
return f / m_a
5848
end

src/schemes/solid/total_lagrangian_sph/rhs.jl

Lines changed: 38 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -3,56 +3,61 @@ function interact!(dv, v_particle_system, u_particle_system,
33
v_neighbor_system, u_neighbor_system,
44
particle_system::TotalLagrangianSPHSystem,
55
neighbor_system::TotalLagrangianSPHSystem, semi)
6-
interact_solid_solid!(dv, particle_system, neighbor_system, semi)
6+
# Different solids do not interact with each other (yet)
7+
particle_system !== neighbor_system && return dv
8+
9+
interact_solid_solid!(dv, v_particle_system, particle_system, semi)
710
end
811

912
# Function barrier without dispatch for unit testing
10-
@inline function interact_solid_solid!(dv, particle_system, neighbor_system, semi)
11-
(; penalty_force) = particle_system
12-
13-
# Different solids do not interact with each other (yet)
14-
if particle_system !== neighbor_system
15-
return dv
16-
end
13+
@inline function interact_solid_solid!(dv, v_system, system, semi)
14+
(; penalty_force) = system
1715

1816
# Everything here is done in the initial coordinates
19-
system_coords = initial_coordinates(particle_system)
20-
neighbor_coords = initial_coordinates(neighbor_system)
17+
system_coords = initial_coordinates(system)
2118

2219
# Loop over all pairs of particles and neighbors within the kernel cutoff.
2320
# For solid-solid interaction, this has to happen in the initial coordinates.
24-
foreach_point_neighbor(particle_system, neighbor_system, system_coords, neighbor_coords,
25-
semi;
26-
points=each_moving_particle(particle_system)) do particle,
27-
neighbor,
28-
initial_pos_diff,
29-
initial_distance
21+
foreach_point_neighbor(system, system, system_coords, system_coords, semi;
22+
points=each_moving_particle(system)) do particle, neighbor,
23+
initial_pos_diff,
24+
initial_distance
3025
# Only consider particles with a distance > 0.
3126
initial_distance < sqrt(eps()) && return
3227

33-
rho_a = particle_system.material_density[particle]
34-
rho_b = neighbor_system.material_density[neighbor]
28+
rho_a = @inbounds system.material_density[particle]
29+
rho_b = @inbounds system.material_density[neighbor]
3530

36-
grad_kernel = smoothing_kernel_grad(particle_system, initial_pos_diff,
31+
grad_kernel = smoothing_kernel_grad(system, initial_pos_diff,
3732
initial_distance, particle)
3833

39-
m_a = particle_system.mass[particle]
40-
m_b = neighbor_system.mass[neighbor]
34+
m_a = @inbounds system.mass[particle]
35+
m_b = @inbounds system.mass[neighbor]
4136

42-
dv_particle = m_b *
43-
(pk1_corrected(particle_system, particle) / rho_a^2 +
44-
pk1_corrected(neighbor_system, neighbor) / rho_b^2) *
45-
grad_kernel
37+
current_pos_diff = @inbounds current_coords(system, particle) -
38+
current_coords(system, neighbor)
39+
current_distance = norm(current_pos_diff)
4640

47-
@inbounds for i in 1:ndims(particle_system)
48-
dv[i, particle] += dv_particle[i]
49-
end
41+
dv_stress = m_b *
42+
(pk1_corrected(system, particle) / rho_a^2 +
43+
pk1_corrected(system, neighbor) / rho_b^2) * grad_kernel
5044

51-
calc_penalty_force!(dv, particle, neighbor, initial_pos_diff,
52-
initial_distance, particle_system, m_a, m_b, rho_a, rho_b,
53-
penalty_force)
45+
dv_penalty_force_ = dv_penalty_force(penalty_force, particle, neighbor,
46+
initial_pos_diff, initial_distance,
47+
current_pos_diff, current_distance,
48+
system, m_a, m_b, rho_a, rho_b)
49+
50+
dv_viscosity = dv_viscosity_tlsph(system, v_system, particle, neighbor,
51+
current_pos_diff, current_distance,
52+
m_a, m_b, rho_a, rho_b, grad_kernel)
53+
54+
for i in 1:ndims(system)
55+
@inbounds dv[i,
56+
particle] += dv_stress[i] + dv_penalty_force_[i] +
57+
dv_viscosity[i]
58+
end
5459

55-
# TODO continuity equation?
60+
# TODO continuity equation for boundary model with `ContinuityDensity`?
5661
end
5762

5863
return dv
@@ -90,10 +95,10 @@ function interact!(dv, v_particle_system, u_particle_system,
9095

9196
rho_a = current_density(v_particle_system, particle_system, particle)
9297
rho_b = current_density(v_neighbor_system, neighbor_system, neighbor)
93-
rho_mean = (rho_a + rho_b) / 2
9498

9599
# Use kernel from the fluid system in order to get the same force here in
96100
# solid-fluid interaction as for fluid-solid interaction.
101+
# TODO this will not use corrections if the fluid uses corrections.
97102
grad_kernel = smoothing_kernel_grad(neighbor_system, pos_diff, distance, particle)
98103

99104
# In fluid-solid interaction, use the "hydrodynamic pressure" of the solid particles

src/schemes/solid/total_lagrangian_sph/system.jl

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ See [Total Lagrangian SPH](@ref tlsph) for more details on the method.
3030
fluid-structure interaction (see [Boundary Models](@ref boundary_models)).
3131
- `penalty_force`: Penalty force to ensure regular particle position under large deformations
3232
(see [`PenaltyForceGanzenmueller`](@ref)).
33+
- `viscosity`: Artificial viscosity model to stabilize both the TLSPH and the FSI.
34+
Currently, only [`ArtificialViscosityMonaghan`](@ref) is supported.
3335
- `acceleration`: Acceleration vector for the system. (default: zero vector)
3436
- `source_terms`: Additional source terms for this system. Has to be either `nothing`
3537
(by default), or a function of `(coords, velocity, density, pressure)`
@@ -55,7 +57,7 @@ See [Total Lagrangian SPH](@ref tlsph) for more details on the method.
5557
where `beam` and `fixed_particles` are of type `InitialCondition`.
5658
"""
5759
struct TotalLagrangianSPHSystem{BM, NDIMS, ELTYPE <: Real, IC, ARRAY1D, ARRAY2D, ARRAY3D,
58-
YM, PR, LL, LM, K, PF, ST} <: SolidSystem{NDIMS}
60+
YM, PR, LL, LM, K, PF, V, ST} <: SolidSystem{NDIMS}
5961
initial_condition :: IC
6062
initial_coordinates :: ARRAY2D # Array{ELTYPE, 2}: [dimension, particle]
6163
current_coordinates :: ARRAY2D # Array{ELTYPE, 2}: [dimension, particle]
@@ -74,6 +76,7 @@ struct TotalLagrangianSPHSystem{BM, NDIMS, ELTYPE <: Real, IC, ARRAY1D, ARRAY2D,
7476
acceleration :: SVector{NDIMS, ELTYPE}
7577
boundary_model :: BM
7678
penalty_force :: PF
79+
viscosity :: V
7780
source_terms :: ST
7881
buffer :: Nothing
7982
end
@@ -84,7 +87,8 @@ function TotalLagrangianSPHSystem(initial_condition,
8487
n_fixed_particles=0, boundary_model=nothing,
8588
acceleration=ntuple(_ -> 0.0,
8689
ndims(smoothing_kernel)),
87-
penalty_force=nothing, source_terms=nothing)
90+
penalty_force=nothing, viscosity=nothing,
91+
source_terms=nothing)
8892
NDIMS = ndims(initial_condition)
8993
ELTYPE = eltype(initial_condition)
9094
n_particles = nparticles(initial_condition)
@@ -119,7 +123,7 @@ function TotalLagrangianSPHSystem(initial_condition,
119123
n_moving_particles, young_modulus, poisson_ratio,
120124
lame_lambda, lame_mu, smoothing_kernel,
121125
smoothing_length, acceleration_, boundary_model,
122-
penalty_force, source_terms, nothing)
126+
penalty_force, viscosity, source_terms, nothing)
123127
end
124128

125129
function Base.show(io::IO, system::TotalLagrangianSPHSystem)
@@ -130,6 +134,7 @@ function Base.show(io::IO, system::TotalLagrangianSPHSystem)
130134
print(io, ", ", system.acceleration)
131135
print(io, ", ", system.boundary_model)
132136
print(io, ", ", system.penalty_force)
137+
print(io, ", ", system.viscosity)
133138
print(io, ") with ", nparticles(system), " particles")
134139
end
135140

@@ -159,7 +164,8 @@ function Base.show(io::IO, ::MIME"text/plain", system::TotalLagrangianSPHSystem)
159164
summary_line(io, "smoothing kernel", system.smoothing_kernel |> typeof |> nameof)
160165
summary_line(io, "acceleration", system.acceleration)
161166
summary_line(io, "boundary model", system.boundary_model)
162-
summary_line(io, "penalty force", system.penalty_force |> typeof |> nameof)
167+
summary_line(io, "penalty force", system.penalty_force)
168+
summary_line(io, "viscosity", system.viscosity)
163169
summary_footer(io)
164170
end
165171
end
@@ -230,6 +236,32 @@ end
230236
extract_smatrix(system.pk1_corrected, system, particle)
231237
end
232238

239+
function young_modulus(system::TotalLagrangianSPHSystem, particle)
240+
return young_modulus(system, system.young_modulus, particle)
241+
end
242+
243+
function young_modulus(::TotalLagrangianSPHSystem, young_modulus, particle)
244+
return young_modulus
245+
end
246+
247+
function young_modulus(::TotalLagrangianSPHSystem,
248+
young_modulus::AbstractVector, particle)
249+
return young_modulus[particle]
250+
end
251+
252+
function poisson_ratio(system::TotalLagrangianSPHSystem, particle)
253+
return poisson_ratio(system, system.poisson_ratio, particle)
254+
end
255+
256+
function poisson_ratio(::TotalLagrangianSPHSystem, poisson_ratio, particle)
257+
return poisson_ratio
258+
end
259+
260+
function poisson_ratio(::TotalLagrangianSPHSystem,
261+
poisson_ratio::AbstractVector, particle)
262+
return poisson_ratio[particle]
263+
end
264+
233265
function initialize!(system::TotalLagrangianSPHSystem, semi)
234266
(; correction_matrix) = system
235267

@@ -345,12 +377,6 @@ end
345377
return lame_lambda * tr(E) * I + 2 * lame_mu * E
346378
end
347379

348-
@inline function calc_penalty_force!(dv, particle, neighbor, initial_pos_diff,
349-
initial_distance, system, m_a, m_b, rho_a, rho_b,
350-
::Nothing)
351-
return dv
352-
end
353-
354380
function write_u0!(u0, system::TotalLagrangianSPHSystem)
355381
(; initial_condition) = system
356382

0 commit comments

Comments
 (0)