Skip to content

Commit 0874150

Browse files
authored
Merge pull request #213 from WaterLily-jl/jld2_ext
JLD2 extension to restart a `Simulation` using JLD2 file data format (HDF5 compatible)
2 parents d3fa813 + a312481 commit 0874150

File tree

6 files changed

+98
-25
lines changed

6 files changed

+98
-25
lines changed

Project.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ AMDGPU = "21141c5a-9bdb-4563-92ae-f87d6854732e"
2121
CUDA = "052768ef-5323-5732-b1bb-66c8b64840ba"
2222
GeometryBasics = "5c1252a2-5f33-56bf-86c9-59e7332b4326"
2323
GLMakie = "e9467ef8-e4e7-5192-8a1a-b1aee30e663a"
24+
JLD2 = "033835bb-8acc-5ee8-8aae-3f567f8a3819"
2425
Meshing = "e6723b4c-ebff-59f1-b4b7-d97aa5274f73"
2526
Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
2627
ReadVTK = "dc215faf-f008-4882-a9f7-a79a826fadc3"
@@ -30,6 +31,7 @@ WriteVTK = "64499a7a-5c06-52f2-abe2-ccb03c286192"
3031
WaterLilyAMDGPUExt = "AMDGPU"
3132
WaterLilyCUDAExt = "CUDA"
3233
WaterLilyGLMakieExt = "GLMakie"
34+
WaterLilyJLD2Ext = "JLD2"
3335
WaterLilyMeshingExt = ["GLMakie", "GeometryBasics", "Meshing"]
3436
WaterLilyPlotsExt = "Plots"
3537
WaterLilyReadVTKExt = "ReadVTK"
@@ -53,6 +55,7 @@ CUDA = "052768ef-5323-5732-b1bb-66c8b64840ba"
5355
GLMakie = "e9467ef8-e4e7-5192-8a1a-b1aee30e663a"
5456
GPUArrays = "0c68f7d7-f131-5f86-a1c3-88cf8149b2d7"
5557
GeometryBasics = "5c1252a2-5f33-56bf-86c9-59e7332b4326"
58+
JLD2 = "033835bb-8acc-5ee8-8aae-3f567f8a3819"
5659
LaTeXStrings = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f"
5760
Makie = "537997a7-5e4e-5d89-9595-2241ea00577e"
5861
Meshing = "e6723b4c-ebff-59f1-b4b7-d97aa5274f73"
@@ -64,4 +67,4 @@ UnicodePlots = "b8865327-cd53-5732-bb35-84acbb429228"
6467
WriteVTK = "64499a7a-5c06-52f2-abe2-ccb03c286192"
6568

6669
[targets]
67-
test = ["Test", "BenchmarkTools", "CUDA", "AMDGPU", "GPUArrays", "WriteVTK", "ReadVTK"]
70+
test = ["Test", "BenchmarkTools", "CUDA", "AMDGPU", "GPUArrays", "WriteVTK", "ReadVTK", "JLD2"]

ext/WaterLilyJLD2Ext.jl

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
module WaterLilyJLD2Ext
2+
3+
if isdefined(Base, :get_extension)
4+
using JLD2
5+
else
6+
using ..JLD2
7+
end
8+
9+
using WaterLily
10+
import WaterLily: save!, load!
11+
12+
"""
13+
save!(fname, flow::Flow; dir="./")
14+
15+
Save the `flow::Flow` pressure, velocity, and time steps arrays into a JLD2-formatted binary file (HDF5 compatible).
16+
"""
17+
save!(fname, flow::Flow; dir="./") = jldsave(
18+
joinpath(dir, fname);
19+
p=Array(flow.p),
20+
u=Array(flow.u),
21+
Δt=flow.Δt
22+
)
23+
save!(fname::String, sim::AbstractSimulation; dir="./") = save!(fname, sim.flow; dir)
24+
25+
"""
26+
load!(flow::Flow, fname::String; dir="./")
27+
28+
Load pressure, velocity, and time steps arrays from a JLD2-formatted binary file.
29+
Keyword arguments considered are `fname="WaterLily.jld2"` and `dir="./"`.
30+
"""
31+
function load!(flow::Flow; kwargs...)
32+
fname = get(Dict(kwargs), :fname, "WaterLily.jld2")
33+
dir = get(Dict(kwargs), :dir, "./")
34+
obj = jldopen(joinpath(dir, fname))
35+
@assert size(flow.p) == size(obj["p"]) "Simulation size does not match the size of the JLD2-stored simulation."
36+
f = typeof(flow.p).name.wrapper
37+
flow.p .= obj["p"] |> f
38+
flow.u .= obj["u"] |> f
39+
empty!(flow.Δt)
40+
push!(flow.Δt, obj["Δt"]...)
41+
close(obj)
42+
end
43+
load!(sim::AbstractSimulation, ::Val{:jld2}; kwargs...) = load!(sim.flow; kwargs...)
44+
45+
end # module

ext/WaterLilyReadVTKExt.jl

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ else
77
end
88

99
using WaterLily
10-
import WaterLily: restart_sim!
10+
import WaterLily: load!
1111

1212
"""
1313
components_last(a::Array)
@@ -16,19 +16,23 @@ Permute the dimensions such that the u₁,u₂,(u₃) components of a vector fie
1616
this is reqired for the vtk file.
1717
"""
1818
components_last(a::AbstractArray{T,N}) where {T,N} = permutedims(a,[2:N...,1])
19+
1920
"""
20-
restart_sim!(a::Simulation;fname::String="WaterLily.pvd")
21+
load!(a::AbstractSimulation, ::Val{:pvd}; kwargs...)
2122
22-
Restart a simulation from a pvd collection file, using the last saved vtk file
23-
The velocity and pressure field of sim are overwriten by the one in the vtk file.
24-
The time step is also updated to match the time step of the vtk file, such that
25-
the simulation can be restarted and continued.
23+
Restart a simulation from a pvd collection file, using the last saved vtk file.
24+
The velocity and pressure field of `a::AbstractSimulation`` are overwriten by the one in the vtk file.
25+
The time step is also updated to match the time step of the vtk file, such that the simulation can be restarted and continued.
26+
Keyword arguments considered are `fname="WaterLily.pvd"` and `attrib=default_attrib()`.
2627
"""
27-
function restart_sim!(a::AbstractSimulation;fname::String="WaterLily.pvd",attrib=default_attrib())
28+
function load!(a::AbstractSimulation, ::Val{:pvd}; kwargs...)
29+
kwargs_dict = Dict(kwargs)
30+
fname = get(kwargs_dict, :fname, "WaterLily.pvd")
31+
attrib = get(kwargs_dict, :attrib, default_attrib())
2832
vtk = VTKFile(PVDFile(fname).vtk_filenames[end])
2933
extent = filter(!iszero,ReadVTK.get_whole_extent(vtk)[2:2:end]);
3034
# check dimensions match
31-
text = "The dimensions of the simulation do not match the dimensions of the vtk file"
35+
text = "The dimensions of the simulation do not match the dimensions of the vtk file."
3236
@assert extent.+1 == collect(size(a.flow.p)) text
3337
# fill the arrays for pressure and velocity
3438
point_data = ReadVTK.get_point_data(vtk)

ext/WaterLilyWriteVTKExt.jl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ else
77
end
88

99
using WaterLily
10-
import WaterLily: vtkWriter, write!, default_attrib, pvd_collection
10+
import WaterLily: vtkWriter, save!, default_attrib, pvd_collection
1111
using Printf: @sprintf
1212
import Base: close
1313

@@ -41,20 +41,20 @@ end
4141
"""
4242
default_attrib()
4343
44-
Returns a `Dict` containing the `name` and `bound_function` for the default attributes.
44+
Returns a `Dict` containing the `name` and `bound_function` for the default attributes.
4545
The `name` is used as the key in the `vtk` file and the `bound_function` generates the data
4646
to put in the file. With this approach, any variable can be save to the vtk file.
4747
"""
4848
_velocity(a::AbstractSimulation) = a.flow.u |> Array;
4949
_pressure(a::AbstractSimulation) = a.flow.p |> Array;
5050
default_attrib() = Dict("Velocity"=>_velocity, "Pressure"=>_pressure)
5151
"""
52-
write!(w::VTKWriter, sim<:AbstractSimulation)
52+
save!(w::VTKWriter, sim<:AbstractSimulation)
5353
5454
Write the simulation data at time `sim_time(sim)` to a `vti` file and add the file path
5555
to the collection file.
5656
"""
57-
function write!(w::VTKWriter,a::AbstractSimulation)
57+
function save!(w::VTKWriter, a::AbstractSimulation)
5858
k = w.count[1]; N=size(a.flow.p)
5959
vtk = vtk_grid(w.dir_name*@sprintf("/%s_%06i", w.fname, k), [1:n for n in N]...)
6060
for (name,func) in w.output_attrib

src/WaterLily.jl

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -132,18 +132,21 @@ perturb!(sim::AbstractSimulation; noise=0.1) = sim.flow.u .+= randn(size(sim.flo
132132

133133
export AbstractSimulation,Simulation,sim_step!,sim_time,measure!,sim_info,perturb!
134134

135-
# default WriteVTK functions
135+
# defaults JLD2 and VTK I/O functions
136+
function load!(sim::AbstractSimulation; kwargs...)
137+
fname = get(Dict(kwargs), :fname, "WaterLily.jld2")
138+
ext = split(fname, ".")[end] |> Symbol
139+
vtk_loaded = !isnothing(Base.get_extension(WaterLily, :WaterLilyReadVTKExt))
140+
jld2_loaded = !isnothing(Base.get_extension(WaterLily, :WaterLilyJLD2Ext))
141+
ext == :pvd && (@assert vtk_loaded "WriteVTK must be loaded to save .pvd data.")
142+
ext == :jdl2 && (@assert jld2_loaded "JLD2 must be loaded to save .jld2 data.")
143+
load!(sim, Val{ext}(); kwargs...)
144+
end
145+
function save! end
136146
function vtkWriter end
137-
function write! end
138147
function default_attrib end
139148
function pvd_collection end
140-
# export
141-
export vtkWriter, write!, default_attrib
142-
143-
# default ReadVTK functions
144-
function restart_sim! end
145-
# export
146-
export restart_sim!
149+
export load!, save!, vtkWriter, default_attrib
147150

148151
# default Plots functions
149152
function flood end
@@ -186,6 +189,7 @@ function __init__()
186189
@require Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" include("../ext/WaterLilyPlotsExt.jl")
187190
@require GLMakie = "e9467ef8-e4e7-5192-8a1a-b1aee30e663a" include("../ext/WaterLilyGLMakieExt.jl")
188191
@require Meshing = "e6723b4c-ebff-59f1-b4b7-d97aa5274f73" include("../ext/WaterLilyMeshingExt.jl")
192+
@require JLD2 = "033835bb-8acc-5ee8-8aae-3f567f8a3819" include("../ext/WaterLilyJLD2Ext.jl")
189193
end
190194
check_nthreads(Val{Threads.nthreads()}())
191195
end

test/maintests.jl

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
using GPUArrays
2-
using ReadVTK, WriteVTK
2+
using ReadVTK, WriteVTK, JLD2
33

44
@info "Test backends: $(join(arrays,", "))"
55
@testset "util.jl" begin
@@ -500,11 +500,11 @@ end
500500
sim = sphere_sim(;D,mem);
501501
# make a vtk writer
502502
wr = vtkWriter("test_vtk_reader_$D";dir="TEST_DIR")
503-
sim_step!(sim,1); write!(wr, sim); close(wr)
503+
sim_step!(sim,1); save!(wr, sim); close(wr)
504504

505505
# re start the sim from a paraview file
506506
restart = sphere_sim(;D,mem);
507-
restart_sim!(restart;fname="test_vtk_reader_$D.pvd")
507+
load!(restart; fname="test_vtk_reader_$D.pvd")
508508

509509
# check that the restart is the same as the original
510510
@test all(sim.flow.p .== restart.flow.p)
@@ -517,4 +517,21 @@ end
517517
@test_nowarn rm("TEST_DIR",recursive=true)
518518
@test_nowarn rm("test_vtk_reader_$D.pvd")
519519
end
520+
end
521+
522+
@testset "WaterLilyJLD2Ext.jl" begin
523+
test_dir = "TEST_DIR"; mkpath(test_dir)
524+
for D [2,3], mem arrays
525+
sim1 = sphere_sim(;D,mem)
526+
sim_step!(sim1, 1)
527+
save!("sim1_sphere.jld2", sim1; dir=test_dir)
528+
529+
sim2 = sphere_sim(;D,mem)
530+
load!(sim2; fname="sim1_sphere.jld2", dir=test_dir)
531+
532+
@test all(sim1.flow.p .== sim2.flow.p)
533+
@test all(sim1.flow.u .== sim2.flow.u)
534+
@test all(sim1.flow.Δt .== sim2.flow.Δt)
535+
end
536+
@test_nowarn rm(test_dir, recursive=true)
520537
end

0 commit comments

Comments
 (0)