Skip to content

Commit 61ea456

Browse files
author
LasNikas
committed
adapt docs
1 parent f30f019 commit 61ea456

File tree

4 files changed

+244
-31
lines changed

4 files changed

+244
-31
lines changed

examples/fluid/play_ground.jl

Lines changed: 233 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,233 @@
1+
# Flow past a circular cylinder (vortex street), Tafuni et al. (2018).
2+
# Other literature using this validation:
3+
# Vacandio et al. (2013), Marrone et al. (2013), Calhoun (2002), Liu et al. (1998)
4+
5+
using TrixiParticles
6+
using OrdinaryDiffEq
7+
8+
# ==========================================================================================
9+
# ==== Resolution
10+
factor_d = 0.08 # Resolution in the paper is `0.01` (5M particles)
11+
12+
const cylinder_diameter = 0.1
13+
particle_spacing = factor_d * cylinder_diameter
14+
15+
# Make sure that the kernel support of fluid particles at a boundary is always fully sampled
16+
boundary_layers = 4
17+
18+
# Make sure that the kernel support of fluid particles at an open boundary is always
19+
# fully sampled.
20+
# Note: Due to the dynamics at the inlets and outlets of open boundaries,
21+
# it is recommended to use `open_boundary_layers > boundary_layers`
22+
open_boundary_layers = 8
23+
24+
# ==========================================================================================
25+
# ==== Experiment Setup
26+
tspan = (0.0, 1.5)
27+
28+
# Boundary geometry and initial fluid particle positions
29+
domain_size = (25 * cylinder_diameter, 20 * cylinder_diameter)
30+
31+
flow_direction = [1.0, 0.0]
32+
reynolds_number = 200
33+
const prescribed_velocity = 1.0
34+
const fluid_density = 1000.0
35+
sound_speed = 10 * prescribed_velocity
36+
37+
boundary_size = (domain_size[1] + 2 * particle_spacing * open_boundary_layers,
38+
domain_size[2])
39+
40+
pipe = RectangularTank(particle_spacing, domain_size, boundary_size, fluid_density,
41+
n_layers=boundary_layers, velocity=[prescribed_velocity, 0.0],
42+
faces=(false, false, true, true))
43+
44+
# Shift pipe walls in negative x-direction for the inflow
45+
pipe.boundary.coordinates[1, :] .-= particle_spacing * open_boundary_layers
46+
47+
n_buffer_particles = 10 * pipe.n_particles_per_dimension[2]^(ndims(pipe.fluid) - 1)
48+
49+
cylinder_center = (5 * cylinder_diameter, domain_size[2] / 2)
50+
cylinder = SphereShape(particle_spacing, cylinder_diameter / 2,
51+
cylinder_center, fluid_density, sphere_type=RoundSphere())
52+
53+
fluid = setdiff(pipe.fluid, cylinder)
54+
55+
# ==========================================================================================
56+
# ==== Fluid
57+
wcsph = true
58+
59+
h_factor = 1.5
60+
smoothing_length = h_factor * particle_spacing
61+
smoothing_kernel = WendlandC2Kernel{2}()
62+
63+
fluid_density_calculator = ContinuityDensity()
64+
65+
kinematic_viscosity = prescribed_velocity * cylinder_diameter / reynolds_number
66+
67+
state_equation = StateEquationCole(; sound_speed, reference_density=fluid_density,
68+
exponent=7)
69+
viscosity = ViscosityAdami(nu=kinematic_viscosity)
70+
71+
if wcsph
72+
density_diffusion = DensityDiffusionMolteniColagrossi(delta=0.1)
73+
74+
fluid_system = WeaklyCompressibleSPHSystem(fluid, fluid_density_calculator,
75+
state_equation, smoothing_kernel,
76+
density_diffusion=density_diffusion,
77+
smoothing_length, viscosity=viscosity,
78+
pressure_acceleration=tensile_instability_control,
79+
buffer_size=n_buffer_particles)
80+
else
81+
state_equation = nothing
82+
fluid_system = EntropicallyDampedSPHSystem(fluid, smoothing_kernel, smoothing_length,
83+
sound_speed, viscosity=viscosity,
84+
density_calculator=fluid_density_calculator,
85+
buffer_size=n_buffer_particles)
86+
end
87+
88+
# ==========================================================================================
89+
# ==== Open Boundary
90+
function velocity_function2d(pos, t)
91+
return SVector(prescribed_velocity, 0.0)
92+
end
93+
94+
open_boundary_model = BoundaryModelTafuni()
95+
96+
boundary_type_in = InFlow()
97+
plane_in = ([0.0, 0.0], [0.0, domain_size[2]])
98+
inflow = BoundaryZone(; plane=plane_in, plane_normal=flow_direction, open_boundary_layers,
99+
density=fluid_density, particle_spacing,
100+
boundary_type=boundary_type_in)
101+
102+
reference_velocity_in = velocity_function2d
103+
# At the inlet, neither pressure nor density are prescribed; instead,
104+
# these values are extrapolated from the fluid domain
105+
reference_pressure_in = nothing
106+
reference_density_in = nothing
107+
open_boundary_in = OpenBoundarySPHSystem(inflow; fluid_system,
108+
boundary_model=open_boundary_model,
109+
buffer_size=n_buffer_particles,
110+
reference_density=reference_density_in,
111+
reference_pressure=reference_pressure_in,
112+
reference_velocity=reference_velocity_in)
113+
114+
boundary_type_out = OutFlow()
115+
116+
plane_out = ([pipe.fluid_size[1], 0.0], [pipe.fluid_size[1], domain_size[2]])
117+
outflow = BoundaryZone(; plane=plane_out, plane_normal=(-flow_direction),
118+
open_boundary_layers, density=fluid_density, particle_spacing,
119+
boundary_type=boundary_type_out)
120+
121+
# At the outlet, we allow the flow to exit freely without imposing any boundary conditions
122+
reference_velocity_out = nothing
123+
reference_pressure_out = nothing
124+
reference_density_out = nothing
125+
open_boundary_out = OpenBoundarySPHSystem(outflow; fluid_system,
126+
boundary_model=open_boundary_model,
127+
buffer_size=n_buffer_particles,
128+
reference_density=reference_density_out,
129+
reference_pressure=reference_pressure_out,
130+
reference_velocity=reference_velocity_out)
131+
# ==========================================================================================
132+
# ==== Boundary
133+
boundary_model = BoundaryModelDummyParticles(pipe.boundary.density, pipe.boundary.mass,
134+
AdamiPressureExtrapolation(),
135+
state_equation=state_equation,
136+
smoothing_kernel, smoothing_length)
137+
138+
boundary_system_wall = BoundarySPHSystem(pipe.boundary, boundary_model)
139+
140+
boundary_model_cylinder = BoundaryModelDummyParticles(cylinder.density, cylinder.mass,
141+
AdamiPressureExtrapolation(),
142+
state_equation=state_equation,
143+
viscosity=viscosity,
144+
smoothing_kernel, smoothing_length)
145+
146+
boundary_system_cylinder = BoundarySPHSystem(cylinder, boundary_model_cylinder)
147+
148+
# ==========================================================================================
149+
# ==== Postprocessing
150+
circle = SphereShape(particle_spacing, (cylinder_diameter + particle_spacing) / 2,
151+
cylinder_center, fluid_density, n_layers=1,
152+
sphere_type=RoundSphere())
153+
154+
# Points for pressure interpolation, located at the wall interface
155+
const data_points = copy(circle.coordinates)
156+
const center = SVector(cylinder_center)
157+
158+
calculate_lift_force(system, v_ode, u_ode, semi, t) = nothing
159+
function calculate_lift_force(system::TrixiParticles.FluidSystem, v_ode, u_ode, semi, t)
160+
force = zero(SVector{ndims(system), eltype(system)})
161+
162+
values = interpolate_points(data_points, semi, system, v_ode, u_ode; cut_off_bnd=false,
163+
clip_negative_pressure=false)
164+
pressure = Array(values.pressure)
165+
166+
for i in axes(data_points, 2)
167+
point = TrixiParticles.current_coords(data_points, system, i)
168+
169+
# F = ∑ -p_i * A_i * n_i
170+
force -= pressure[i] * particle_spacing .*
171+
TrixiParticles.normalize(point - center)
172+
end
173+
174+
return 2 * force[2] / (fluid_density * prescribed_velocity^2 * cylinder_diameter)
175+
end
176+
177+
calculate_drag_force(system, v_ode, u_ode, semi, t) = nothing
178+
function calculate_drag_force(system::TrixiParticles.FluidSystem, v_ode, u_ode, semi, t)
179+
force = zero(SVector{ndims(system), eltype(system)})
180+
181+
values = interpolate_points(data_points, semi, system, v_ode, u_ode; cut_off_bnd=false,
182+
clip_negative_pressure=false)
183+
pressure = Array(values.pressure)
184+
185+
for i in axes(data_points, 2)
186+
point = TrixiParticles.current_coords(data_points, system, i)
187+
188+
# F = ∑ -p_i * A_i * n_i
189+
force -= pressure[i] * particle_spacing .*
190+
TrixiParticles.normalize(point - center)
191+
end
192+
193+
return 2 * force[1] / (fluid_density * prescribed_velocity^2 * cylinder_diameter)
194+
end
195+
196+
# ==========================================================================================
197+
# ==== Simulation
198+
min_corner = minimum(pipe.boundary.coordinates .- 5 * particle_spacing, dims=2)
199+
max_corner = maximum(pipe.boundary.coordinates .+ 5 * particle_spacing, dims=2)
200+
cell_list = FullGridCellList(; min_corner, max_corner)
201+
202+
neighborhood_search = GridNeighborhoodSearch{2}(; cell_list,
203+
update_strategy=ParallelUpdate())
204+
205+
semi = Semidiscretization(fluid_system, open_boundary_in, open_boundary_out,
206+
boundary_system_wall, boundary_system_cylinder;
207+
neighborhood_search=neighborhood_search,
208+
parallelization_backend=PolyesterBackend())
209+
210+
ode = semidiscretize(semi, tspan)
211+
212+
info_callback = InfoCallback(interval=100)
213+
214+
output_directory = "out"
215+
216+
saving_callback = SolutionSavingCallback(; dt=0.02, prefix="", output_directory)
217+
218+
pp_callback = PostprocessCallback(; dt=0.02,
219+
f_l=calculate_lift_force, f_d=calculate_drag_force,
220+
output_directory, filename="resulting_force",
221+
write_csv=true, write_file_interval=10)
222+
223+
extra_callback = nothing
224+
225+
callbacks = CallbackSet(info_callback, UpdateCallback(), saving_callback,
226+
ParticleShiftingCallback(), # To obtain a near-uniform particle distribution in the wake
227+
pp_callback, extra_callback)
228+
229+
sol = solve(ode, RDPK3SpFSAL35(),
230+
abstol=1e-6, # Default abstol is 1e-6 (may need to be tuned to prevent boundary penetration)
231+
reltol=1e-4, # Default reltol is 1e-3 (may need to be tuned to prevent boundary penetration)
232+
dtmax=1e-2, # Limit stepsize to prevent crashing
233+
save_everystep=false, callback=callbacks);

src/schemes/boundary/open_boundary/method_of_characteristics.jl

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,7 @@ For more information about the method see [description below](@ref method_of_cha
99
1010
# Keywords
1111
- `extrapolate_reference_values=false`: If `true`, the reference values are extrapolated
12-
from the fluid domain to the boundary particles. This is useful for open boundaries where
13-
the reference values are not known a priori.
12+
from the fluid domain to the boundary particles.
1413
**Note:** This feature is experimental and has not been fully validated yet.
1514
As of now, we are not aware of any published literature supporting its use.
1615
"""

src/schemes/boundary/open_boundary/mirroring.jl

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,10 @@ function extrapolate_values!(system, v_open_boundary, v_fluid, u_open_boundary,
150150
density[particle] = reference_value(reference_density, density[particle],
151151
particle_coords, t)
152152
else
153-
inverse_state_equation!(density, state_equation, pressure, particle)
153+
f_d = L_inv * extrapolated_density_correction[]
154+
df_d = f_d[two_to_end]
155+
156+
density[particle] = f_d[1] + dot(pos_diff, df_d)
154157
end
155158
end
156159

src/schemes/boundary/open_boundary/system.jl

Lines changed: 6 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,10 @@ Open boundary system for in- and outflow particles.
2727
or a scalar for a constant density over all particles.
2828
2929
!!! note "Note"
30-
When using the [`BoundaryModelTafuni()`](@ref), the reference values (`reference_velocity`,
31-
`reference_pressure`, `reference_density`) can also be set to `nothing`
32-
since this model allows for either assigning physical quantities a priori or extrapolating them
33-
from the fluid domaim to the buffer zones (inflow and outflow) using ghost nodes.
30+
The reference values (`reference_velocity`, `reference_pressure`, `reference_density`)
31+
can also be set to `nothing`.
32+
In this case, they will either be extrapolated from the fluid domain ([BoundaryModelTafuni](@ref BoundaryModelTafuni))
33+
or evolved using the characteristic flow variables ([BoundaryModelLastiwka](@ref BoundaryModelLastiwka)).
3434
3535
!!! warning "Experimental Implementation"
3636
This is an experimental feature and may change in future releases.
@@ -83,9 +83,6 @@ function OpenBoundarySPHSystem(boundary_zone::BoundaryZone;
8383
reference_density=nothing)
8484
(; initial_condition) = boundary_zone
8585

86-
check_reference_values!(boundary_model, reference_density, reference_pressure,
87-
reference_velocity)
88-
8986
buffer = SystemBuffer(nparticles(initial_condition), buffer_size)
9087

9188
initial_condition = allocate_buffer(initial_condition, buffer)
@@ -261,6 +258,8 @@ function update_open_boundary_eachstep!(system::OpenBoundarySPHSystem, v_ode, u_
261258
u = wrap_u(u_ode, system, semi)
262259
v = wrap_v(v_ode, system, semi)
263260

261+
@trixi_timeit timer() "check domain" check_domain!(system, v, u, v_ode, u_ode, semi)
262+
264263
# Update density, pressure and velocity based on the characteristic variables.
265264
# See eq. 13-15 in Lastiwka (2009) https://doi.org/10.1002/fld.1971
266265
@trixi_timeit timer() "update boundary quantities" update_boundary_quantities!(system,
@@ -270,8 +269,6 @@ function update_open_boundary_eachstep!(system::OpenBoundarySPHSystem, v_ode, u_
270269
u_ode,
271270
semi, t)
272271

273-
@trixi_timeit timer() "check domain" check_domain!(system, v, u, v_ode, u_ode, semi)
274-
275272
return system
276273
end
277274

@@ -443,25 +440,6 @@ end
443440
# instead of using the method of characteristics
444441
reference_value(value::Nothing, quantity, position, t) = quantity
445442

446-
function check_reference_values!(boundary_model, reference_density, reference_pressure,
447-
reference_velocity)
448-
return boundary_model
449-
end
450-
451-
function check_reference_values!(boundary_model::BoundaryModelLastiwka,
452-
reference_density, reference_pressure, reference_velocity)
453-
454-
# TODO
455-
return boundary_model
456-
boundary_model.extrapolate_reference_values && return boundary_model
457-
458-
if any(isnothing.([reference_density, reference_pressure, reference_velocity]))
459-
throw(ArgumentError("for `BoundaryModelLastiwka` all reference values must be specified"))
460-
end
461-
462-
return boundary_model
463-
end
464-
465443
# To account for boundary effects in the viscosity term of the RHS, use the viscosity model
466444
# of the neighboring particle systems.
467445
@inline function viscosity_model(system::OpenBoundarySPHSystem,

0 commit comments

Comments
 (0)