Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
117 commits
Select commit Hold shift + click to select a range
f1400fd
Update vtk2trixi function to return `NamedTuple` instead of `InitialC…
marcelschurer Oct 17, 2025
217f711
Refactor vtk2trixi function to accept custom fields
marcelschurer Oct 17, 2025
0fa5900
Enhance vtk2trixi function to support scalar and vector custom quanti…
marcelschurer Oct 20, 2025
66f83a3
Merge branch 'main' into vtk2trixi-return-named-tuple
marcelschurer Oct 20, 2025
38a9b2a
Fix typo in documentation for vtk2trixi function
marcelschurer Oct 21, 2025
5d1192a
Fix capitalization in comments
marcelschurer Oct 23, 2025
0713bdd
Merge branch 'main' into vtk2trixi-return-named-tuple
marcelschurer Oct 23, 2025
2cf2b1c
Merge branch 'main' into vtk2trixi-return-named-tuple
marcelschurer Nov 10, 2025
eb98b4f
Merge branch 'main' into vtk2trixi-return-named-tuple
marcelschurer Nov 14, 2025
1d33e8b
Merge branch 'main' into vtk2trixi-return-named-tuple
LasNikas Nov 20, 2025
0b22696
Merge branch 'main' into vtk2trixi-return-named-tuple
svchb Nov 21, 2025
7e51a81
add ELTYPE
Nov 22, 2025
cac637d
Merge branch 'main' into read-with-eltype
Nov 22, 2025
ffa4a1c
Merge branch 'main' into vtk2trixi-return-named-tuple
marcelschurer Dec 3, 2025
c51f2ac
Merge branch 'vtk2trixi-return-named-tuple' of https://github.com/mar…
marcelschurer Dec 3, 2025
2b2fb72
Fix formatting in documentation
marcelschurer Dec 3, 2025
d460b88
Merge branch 'main' into vtk2trixi-return-named-tuple
marcelschurer Dec 3, 2025
a621cca
Merge branch 'main' into read-with-eltype
Dec 8, 2025
1b889b4
Merge branch 'main' into read-with-eltype
Dec 8, 2025
b043bd1
add `coordinates_eltype`
Dec 8, 2025
de55ebd
Merge branch 'main' into read-with-eltype
Dec 9, 2025
9515f84
Merge branch 'main' into vtk2trixi-return-named-tuple
marcelschurer Dec 9, 2025
a9b0f2f
Corrected failing doctest output
marcelschurer Dec 9, 2025
0359425
first prototype
Dec 10, 2025
fd15671
write Q
Dec 10, 2025
364e24e
gpu fix
Dec 10, 2025
c1b0abf
add checks
Dec 10, 2025
eeebcc2
add docs
Dec 10, 2025
d8b5b00
Corrected failing doctest output
marcelschurer Dec 10, 2025
d21a549
adapt pressure model
Dec 10, 2025
b4020c8
use `foreach_no_alloc`
Dec 11, 2025
55be6a6
fix unit tests
Dec 11, 2025
4fe3c7d
Merge branch 'flow-rate-per-boundary-zone' into fix_pressure_model
Dec 11, 2025
a431873
fix unit tests
Dec 11, 2025
b27e54d
Merge branch 'flow-rate-per-boundary-zone' into fix_pressure_model
Dec 11, 2025
9339bcb
fix unit tests
Dec 11, 2025
5aa8f30
Merge branch 'flow-rate-per-boundary-zone' into fix_pressure_model
Dec 11, 2025
d8cda93
fix doc tests
Dec 11, 2025
be8a23e
better docs
Dec 11, 2025
8aff117
use stored type
Dec 12, 2025
868b449
add docs
Dec 12, 2025
6e390c2
add tests
Dec 12, 2025
f3a981b
Merge branch 'flow-rate-per-boundary-zone' into fix_pressure_model
Dec 12, 2025
6121e7d
fix formatting
Dec 12, 2025
dc02bd8
Merge branch 'flow-rate-per-boundary-zone' into fix_pressure_model
Dec 13, 2025
7369f71
fix eltype
Dec 13, 2025
3682dd8
Merge branch 'flow-rate-per-boundary-zone' into fix_pressure_model
Dec 13, 2025
3a97e49
Merge branch 'main' into fix_pressure_model
Dec 15, 2025
4dcece2
Merge branch 'main' into flow-rate-per-boundary-zone
Dec 15, 2025
38e376a
Merge branch 'main' into read-with-eltype
Dec 15, 2025
f347da8
Merge branch 'main' into vtk2trixi-return-named-tuple
LasNikas Dec 16, 2025
b25415f
Merge remote-tracking branch 'marcel/vtk2trixi-return-named-tuple' in…
Dec 16, 2025
a912326
revise #959
Dec 16, 2025
29b5b1a
fix buffer
Jan 6, 2026
daceea2
first poc
Jan 6, 2026
039dd13
Merge branch 'poc-restart' into restart-from-vtu
Jan 6, 2026
e9750b0
add show
Jan 6, 2026
695fe6c
remove mass
Jan 6, 2026
3acfe6c
Merge branch 'poc-restart' into restart-from-vtu
Jan 6, 2026
2d8bce8
add preconditioning
Jan 6, 2026
616a2dc
fix inactive particles
Jan 6, 2026
a80518c
fix zone IDs
Jan 6, 2026
439cb6b
add test
Jan 6, 2026
f3049a4
make it gpu compatible
Jan 6, 2026
1c7cd38
add gpu tests
Jan 6, 2026
c605502
fix tests
Jan 7, 2026
5987957
Merge branch 'poc-restart' into restart-from-vtu
Jan 7, 2026
1cada77
add checks
Jan 7, 2026
100590e
add example
Jan 7, 2026
358848d
add docs
Jan 7, 2026
2b56dc8
fix typo
Jan 7, 2026
63b760a
Merge branch 'main' into flow-rate-per-boundary-zone
Jan 7, 2026
7c08761
implement suggestions
Jan 7, 2026
90402fb
Merge branch 'main' into read-with-eltype
Jan 7, 2026
4a6bca1
implement suggestions
Jan 7, 2026
bbeade4
Merge branch 'flow-rate-per-boundary-zone' into fix_pressure_model
Jan 7, 2026
f8f788c
implement suggestions
Jan 7, 2026
ce0febf
Merge branch 'main' into read-with-eltype
Jan 7, 2026
9e4276a
use strings instead of RestartConditin
Jan 7, 2026
7564985
add test mixed types
Jan 7, 2026
2e744db
Merge branch 'main' into flow-rate-per-boundary-zone
Jan 7, 2026
b831fa5
Merge branch 'flow-rate-per-boundary-zone' into fix_pressure_model
Jan 7, 2026
6848fbf
Merge branch 'fix_pressure_model' into restart-from-vtu
Jan 7, 2026
c4ce276
Merge branch 'main' into poc-restart
Jan 7, 2026
5c600c4
Merge branch 'read-with-eltype' into poc-restart
Jan 7, 2026
54190e6
Merge branch 'poc-restart' into restart-from-vtu
Jan 7, 2026
16fcfba
Merge branch 'main' into vtk2trixi-return-named-tuple
Jan 10, 2026
cfba71c
add NEWS entry
Jan 10, 2026
2dcbc76
revise
Jan 10, 2026
0d587cd
fix doc test
Jan 10, 2026
f316d3d
Merge branch 'main' into restart-from-vtu
Jan 10, 2026
bb4e7da
Merge branch 'vtk2trixi-return-named-tuple' into restart-from-vtu
Jan 10, 2026
48a79e1
rm test file
Jan 10, 2026
f264c9a
fix merge bugs
Jan 10, 2026
df63263
fix preconditioning
Jan 10, 2026
e26a569
Merge branch 'main' into restart-from-vtu
Jan 13, 2026
47bc4c2
don't read IC
Jan 13, 2026
2ca0551
Merge branch 'main' into vtk2trixi-return-named-tuple
Jan 13, 2026
5afcc47
Merge branch 'main' into restart-from-vtu
Jan 15, 2026
ae5496a
fix merge bug
Jan 15, 2026
143e9dc
Merge branch 'dev' into vtk2trixi-return-named-tuple
Jan 19, 2026
cf0a4a2
Merge branch 'main' into vtk2trixi-return-named-tuple
Jan 20, 2026
a1fc021
fix NEWS entry
Jan 20, 2026
32872b0
Merge branch 'dev' into vtk2trixi-return-named-tuple
Jan 21, 2026
ab1476b
Merge branch 'vtk2trixi-return-named-tuple' into restart-from-vtu
Jan 21, 2026
8c50353
fix merge bug
Jan 22, 2026
6fa813a
Merge branch 'vtk2trixi-return-named-tuple' into restart-from-vtu
Jan 22, 2026
4b3b911
fix formatting
Jan 22, 2026
55635fc
better name
Jan 22, 2026
f02d724
add more tests
Jan 22, 2026
2542c15
Merge branch 'main' into restart-from-vtu
Apr 17, 2026
21853d3
Merge branch 'dev' into restart-from-vtu
Apr 17, 2026
6221cbc
revise example
Apr 17, 2026
16ee9d1
Merge branch 'dev' into restart-from-vtu
Apr 20, 2026
d69528d
Merge branch 'dev' into restart-from-vtu
Apr 22, 2026
ce37610
Merge branch 'dev' into restart-from-vtu
LasNikas Apr 28, 2026
68a7f28
Merge branch 'main' into restart-from-vtu
LasNikas Apr 29, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions examples/postprocessing/restart_poiseuille_flow_2d.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# ==========================================================================================
# Restart Example: Poiseuille Flow 2D
#
# This example demonstrates how to restart a simulation.
# We first run a simulation of 2D Poiseuille flow up to t=0.3s, then restart from the
# saved state and continue the simulation until t=0.6s.
# ==========================================================================================
using TrixiParticles

trixi_include(@__MODULE__,
joinpath(examples_dir(), "fluid", "poiseuille_flow_2d.jl"),
tspan=(0.0, 0.3), sound_speed_factor=10, particle_spacing=4e-5)

# Get latest iteration
iter = saving_callback.condition.index[] - 1

restart_file_fluid = joinpath("out", "fluid_1_$iter.vtu")
restart_file_open_boundary = joinpath("out", "open_boundary_1_$iter.vtu")
restart_file_boundary = joinpath("out", "boundary_1_$iter.vtu")

ode_restart = semidiscretize(semi, (0.3, 0.6);
restart_with=(restart_file_fluid,
restart_file_open_boundary,
restart_file_boundary))

saving_callback = SolutionSavingCallback(dt=0.02, prefix="restart")

callbacks = CallbackSet(info_callback, saving_callback, UpdateCallback())

sol_restart = solve(ode_restart, RDPK3SpFSAL35(), abstol=1e-5, reltol=1e-3, dtmax=1e-2,
save_everystep=false, callback=callbacks)
1 change: 1 addition & 0 deletions src/TrixiParticles.jl
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ include("general/semidiscretization.jl")
include("general/gpu.jl")
include("preprocessing/preprocessing.jl")
include("io/io.jl")
include("general/restart.jl")
include("visualization/recipes_plots.jl")

export Semidiscretization, semidiscretize, restart_with!
Expand Down
119 changes: 119 additions & 0 deletions src/general/restart.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
function set_initial_conditions!(v0_ode, u0_ode, semi, restart_with::Tuple{Vararg{String}})
# Check number of systems
if length(semi.systems) != length(restart_with)
throw(ArgumentError("Number of systems in `semi` does not match number of restart files provided " *
"in `restart_with`"))
end

# Check that systems match
expected_system_names = system_names(semi.systems)
foreach_system(semi) do system
system_index = system_indices(system, semi)
filename = restart_with[system_index]
expected_system_name = expected_system_names[system_index]
if !occursin(expected_system_name, basename(splitext(filename)[1]))
throw(ArgumentError("Filename '$filename' for system $system_index does not contain expected name '$expected_system_name'. " *
"Expected a VTK file for system of type $(nameof(typeof(system)))."))
end
end

# Set initial conditions
foreach_noalloc(semi.systems, restart_with) do (system, restart_file)
v0_system = wrap_v(v0_ode, system, semi)
u0_system = wrap_u(u0_ode, system, semi)

restart_data = vtk2trixi(restart_file; create_initial_condition=false)
v_restart = restart_v(system, restart_data)
u_restart = restart_u(system, restart_data)

v0_system .= Adapt.adapt(semi.parallelization_backend, v_restart)
u0_system .= Adapt.adapt(semi.parallelization_backend, u_restart)

restore_previous_state!(system, restart_file)
end
end

function time_span(tspan, restart_with::Tuple{Vararg{String}})
restart_data = vtk2trixi(first(restart_with))
t_restart = convert(eltype(tspan), restart_data.time)

if !isapprox(tspan[1], t_restart)
@info "Adjusting initial time from $(tspan[1]) to restart time $t_restart"
end

return (t_restart, tspan[2])
end
Comment on lines +36 to +45
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should check if all the files start from the same time.


function write_density_and_pressure!(v_restart, system, density_calculator,
pressure, density)
return v_restart
end

function write_density_and_pressure!(v_restart, system,
density_calculator::ContinuityDensity,
pressure, density)
v_restart[size(v_restart, 1), :] = density

return v_restart
end

function write_density_and_pressure!(v_restart, system::EntropicallyDampedSPHSystem,
density_calculator::ContinuityDensity,
pressure, density)
v_restart[size(v_restart, 1), :] = density
v_restart[size(v_restart, 1) - 1, :] = pressure

return v_restart
end

restore_previous_state!(system, restart_file) = system

function initialize_neighborhood_searches!(semi, u0_ode,
restart_with::Tuple{Vararg{String}})
foreach_system(semi) do system
foreach_system(semi) do neighbor
initialize_neighborhood_search!(semi, system, neighbor, u0_ode)
end
end

return semi
end

function initialize_neighborhood_search!(semi, system, neighbor, u0_ode)
# TODO Initialize after adapting to the GPU.
# Currently, this cannot use `semi.parallelization_backend`
# because data is still on the CPU.
PointNeighbors.initialize!(get_neighborhood_search(system, neighbor, semi),
initial_restart_coordinates(system, u0_ode, semi),
initial_restart_coordinates(neighbor, u0_ode, semi),
eachindex_y=each_active_particle(neighbor),
parallelization_backend=PolyesterBackend())
return semi
end

function initialize_neighborhood_search!(semi, system::TotalLagrangianSPHSystem,
neighbor::TotalLagrangianSPHSystem, u0_ode)
# For TLSPH, the self-interaction NHS is already initialized in the system constructor
return semi
end

function initial_restart_coordinates(system, u0_ode, semi)
# Transfer to CPU if data is on the GPU. Do nothing if already on CPU.
return transfer2cpu(wrap_u(u0_ode, system, semi))
end

function initial_restart_coordinates(system::Union{WallBoundarySystem,
AbstractStructureSystem}, u0_ode, semi)
return initial_coordinates(system)
end

function initialize!(semi::Semidiscretization, restart_with::Tuple{Vararg{String}})
foreach_system(semi) do system
# Initialize this system
initialize_restart!(system, semi)
end

return semi
end

initialize_restart!(system, semi) = initialize!(system, semi)
74 changes: 62 additions & 12 deletions src/general/semidiscretization.jl
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ end
end

"""
semidiscretize(semi, tspan; reset_threads=true)
semidiscretize(semi, tspan; reset_threads=true, restart_with=nothing)

Create an `ODEProblem` from the semidiscretization with the specified `tspan`.

Expand All @@ -193,6 +193,10 @@ Create an `ODEProblem` from the semidiscretization with the specified `tspan`.
- `tspan`: The time span over which the simulation will be run.

# Keywords
- `restart_with`: Can be used to restart the simulation from VTK solution files (see [`SolutionSavingCallback`](@ref)).
This has to be a tuple of filenames, one for each system in the [`Semidiscretization`](@ref).
The order of the filenames has to match the order of the systems in the [`Semidiscretization`](@ref).
Comment on lines +197 to +198
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unclear meaning of this sentences.

If no restart is desired, use `nothing` (default).
- `reset_threads`: A boolean flag to reset Polyester.jl threads before the simulation (default: `true`).
After an error within a threaded loop, threading might be disabled. Resetting the threads before the simulation
ensures that threading is enabled again for the simulation.
Expand All @@ -219,7 +223,7 @@ timespan: (0.0, 1.0)
u0: ([...], [...]) *this line is ignored by filter*
```
"""
function semidiscretize(semi, tspan; reset_threads=true)
function semidiscretize(semi, tspan; reset_threads=true, restart_with=nothing)
(; systems) = semi

# Check that all systems have the same eltype
Expand Down Expand Up @@ -267,14 +271,11 @@ function semidiscretize(semi, tspan; reset_threads=true)
end

# Set initial condition
foreach_system_wrapped(semi, v0_ode, u0_ode) do system, v0_system, u0_system
write_u0!(u0_system, system)
write_v0!(v0_system, system)
end
set_initial_conditions!(v0_ode, u0_ode, semi, restart_with)

# TODO initialize after adapting to the GPU.
# Requires https://github.com/trixi-framework/PointNeighbors.jl/pull/86.
initialize_neighborhood_searches!(semi)
initialize_neighborhood_searches!(semi, u0_ode, restart_with)

if semi.parallelization_backend isa KernelAbstractions.GPU
# Convert all arrays in the systems to the correct array type.
Expand Down Expand Up @@ -304,15 +305,31 @@ function semidiscretize(semi, tspan; reset_threads=true)
end

# Initialize all particle systems
foreach_system(semi_new) do system
# Initialize this system
initialize!(system, semi_new)
end
initialize!(semi_new, restart_with)

# Reset callback flag that will be set by the `UpdateCallback`
semi_new.update_callback_used[] = false

return DynamicalODEProblem(kick!, drift!, v0_ode, u0_ode, tspan, semi_new)
return DynamicalODEProblem(kick!, drift!, v0_ode, u0_ode,
time_span(tspan, restart_with), semi_new)
end

function set_initial_conditions!(v0_ode, u0_ode, semi, restart_with::Nothing)
foreach_system_wrapped(semi, v0_ode, u0_ode) do system, v0_system, u0_system
write_u0!(u0_system, system)
write_v0!(v0_system, system)
end
end

time_span(tspan, restart_with::Nothing) = tspan

function initialize!(semi::Semidiscretization, restart_with::Nothing)
foreach_system(semi) do system
# Initialize this system
initialize!(system, semi)
end

return semi
end

"""
Expand Down Expand Up @@ -348,6 +365,39 @@ function restart_with!(semi, sol; reset_threads=true)
return semi
end

function initialize_neighborhood_searches!(semi, u0_ode, restart_with::Nothing)
initialize_neighborhood_searches!(semi)
end

function initialize_neighborhood_searches!(semi)
foreach_system(semi) do system
foreach_system(semi) do neighbor
initialize_neighborhood_search!(semi, system, neighbor)
end
end

return semi
end

function initialize_neighborhood_search!(semi, system, neighbor)
# TODO Initialize after adapting to the GPU.
# Currently, this cannot use `semi.parallelization_backend`
# because data is still on the CPU.
PointNeighbors.initialize!(get_neighborhood_search(system, neighbor, semi),
initial_coordinates(system),
initial_coordinates(neighbor),
eachindex_y=each_active_particle(neighbor),
parallelization_backend=PolyesterBackend())

return semi
end

function initialize_neighborhood_search!(semi, system::TotalLagrangianSPHSystem,
neighbor::TotalLagrangianSPHSystem)
# For TLSPH, the self-interaction NHS is already initialized in the system constructor
return semi
end

# We have to pass `system` here for type stability,
# since the type of `system` determines the return type.
@inline function wrap_v(v_ode, system, semi)
Expand Down
10 changes: 10 additions & 0 deletions src/io/write_vtk.jl
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,16 @@ function write2vtk!(vtk, v, u, t, system::OpenBoundarySystem)
for particle in eachparticle(system)]
vtk["pressure"] = [current_pressure(v, system, particle)
for particle in eachparticle(system)]
vtk["zone_id"] = [system.boundary_zone_indices[particle]
for particle in eachparticle(system)]

if any(pm -> isa(pm, AbstractPressureModel), system.cache.pressure_reference_values)
for (i, pressure_model) in enumerate(system.cache.pressure_reference_values)
if pressure_model isa AbstractPressureModel
vtk["boundary_zone_pressure_$i"] = system.cache.pressure_reference_values[i].pressure[]
end
end
end

if system.calculate_flow_rate
Q_total = zero(eltype(system))
Expand Down
65 changes: 65 additions & 0 deletions src/schemes/boundary/open_boundary/system.jl
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,9 @@ function initialize!(system::OpenBoundarySystem, semi)
return system
end

# Skip during restart, as boundary zone indices are updated in `restore_previous_state!`
initialize_restart!(system::OpenBoundarySystem, semi) = system

function create_cache_open_boundary(boundary_model, fluid_system, initial_condition,
density_diffusion, calculate_flow_rate, boundary_zones)
reference_values = map(bz -> bz.reference_values, boundary_zones)
Expand Down Expand Up @@ -251,6 +254,8 @@ end
return system.shifting_technique
end

@inline density_calculator(system::OpenBoundarySystem) = nothing

system_sound_speed(system::OpenBoundarySystem) = system_sound_speed(system.fluid_system)

@inline hydrodynamic_mass(system::OpenBoundarySystem, particle) = system.mass[particle]
Expand Down Expand Up @@ -680,6 +685,66 @@ function interpolate_velocity!(system::OpenBoundarySystem, boundary_zone,
return system
end

function restart_u(system::OpenBoundarySystem, data)
coords_total = zeros(coordinates_eltype(system), u_nvariables(system),
n_integrated_particles(system))
coords_total .= coordinates_eltype(system)(1e16)

coords_active = data.coordinates
for particle in axes(coords_active, 2)
for dim in 1:ndims(system)
coords_total[dim, particle] = coords_active[dim, particle]
end
end

system.buffer.active_particle .= false
system.buffer.active_particle[1:size(coords_active, 2)] .= true

update_system_buffer!(system.buffer)

return coords_total
end

function restart_v(system::OpenBoundarySystem, data)
v_total = zeros(eltype(system), v_nvariables(system),
n_integrated_particles(system))

v_active = zeros(eltype(system), v_nvariables(system), size(data.velocity, 2))

v_active[1:ndims(system), :] = data.velocity
write_density_and_pressure!(v_active, system.fluid_system,
density_calculator(system), data.pressure, data.density)

for particle in axes(v_active, 2)
for i in axes(v_active, 1)
v_total[i, particle] = v_active[i, particle]
end
end

return v_total
end

function restore_previous_state!(system::OpenBoundarySystem, file)
# We cannot simply use `update_boundary_zone_indices!` because rounding errors during file I/O
# may result in particles being located outside their intended boundary zone, even though they
# were written as active particles.
set_zero!(system.boundary_zone_indices)

values = vtk2trixi(file; create_initial_condition=false)
system.boundary_zone_indices[each_integrated_particle(system)] .= values.zone_id

if any(pm -> isa(pm, AbstractPressureModel), system.cache.pressure_reference_values)
for (i, pressure_model) in enumerate(system.cache.pressure_reference_values)
if pressure_model isa AbstractPressureModel
pressure_model.pressure[] = values[Symbol(:boundary_zone_pressure_, i)]
pressure_model.flow_rate[] = values[Symbol(:Q_, i)]
end
end
end

return system
end

# Open-boundary interpolation should reconstruct the surrounding fluid-like velocity field.
# Therefore, only actual fluid systems and other open-boundary particles contribute;
# rigid bodies, walls, and other non-fluid systems are intentionally excluded.
Expand Down
4 changes: 4 additions & 0 deletions src/schemes/boundary/wall_boundary/dummy_particles.jl
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,10 @@ function Base.show(io::IO, model::BoundaryModelDummyParticles)
print(io, ")")
end

@inline function density_calculator(model::BoundaryModelDummyParticles)
return model.density_calculator
end

# Set the initial pressure to zero for visualization
function initial_boundary_pressure(initial_density, density_calculator, _)
return zero(initial_density)
Expand Down
Loading
Loading