From 7f4cf679e6ee3dfbbe854e4363216cf43caa74c9 Mon Sep 17 00:00:00 2001 From: Bernat Font Date: Wed, 24 Jul 2024 11:55:51 +0200 Subject: [PATCH] Fixed images not being displayed in docs after latest README update. --- README.md | 40 +++++++++++++++------------------------- docs/make.jl | 2 +- 2 files changed, 16 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index b4bab0f..fdabc69 100644 --- a/README.md +++ b/README.md @@ -4,18 +4,13 @@ [![CI](https://github.com/WaterLily-jl/WaterLily.jl/workflows/CI/badge.svg?branch=master&event=push)](https://github.com/WaterLily-jl/WaterLily.jl/actions) [![codecov](https://codecov.io/gh/WaterLily-jl/WaterLily.jl/branch/master/graph/badge.svg?token=8XYFWKOUFN)](https://codecov.io/gh/WaterLily-jl/WaterLily.jl) - -

- -

+![Julia flow](examples/julia.gif) ## Overview **WaterLily.jl** is a simple and fast fluid simulator written in pure Julia. This project is supported by awesome libraries developed within the Julia scientific community, and it aims to accelerate and enhance fluid simulations. Watch the JuliaCon2024 talk here: -

- -

+[![JuliaCon2024 still and link](examples/JuliaCon2024.png)](https://www.youtube.com/live/qru5G5Yp77E?t=29074s) If you have used WaterLily for research, please __cite us__! The following manuscript describes the main features of the solver and provides benchmarking, validation, and profiling results. ``` @@ -36,7 +31,7 @@ WaterLily solves the unsteady incompressible 2D or 3D [Navier-Stokes equations]( ## Examples -The user can set the boundary conditions, the initial velocity field, the fluid viscosity (which determines the [Reynolds number](https://en.wikipedia.org/wiki/Reynolds_number)), and immerse solid obstacles using a signed distance function. These examples and others are found in the [examples](examples) directory. +The user can set the boundary conditions, the initial velocity field, the fluid viscosity (which determines the [Reynolds number](https://en.wikipedia.org/wiki/Reynolds_number)), and immerse solid obstacles using a signed distance function. These examples and others are found in the [examples](https://github.com/WaterLily-jl/WaterLily.jl/blob/master/examples) directory. ### Flow over a circle We define the size of the simulation domain as `n`$\times$`m` cells. The circle has radius `m/8` and is centered at `(m/2,m/2)`. The flow boundary conditions are `(U,0)`, where we set `U=1`, and the Reynolds number is `Re=U*radius/ν` where `ν` (Greek "nu" U+03BD, not Latin lowercase "v") is the kinematic viscosity of the fluid. @@ -48,7 +43,7 @@ function circle(n,m;Re=250,U=1) Simulation((n,m), (U,0), radius; ν=U*radius/Re, body) end ``` -The second to last line defines the circle geometry using a [signed distance function](https://en.wikipedia.org/wiki/Signed_distance_function#Applications). The `AutoBody` function uses [automatic differentiation](https://github.com/JuliaDiff/) to infer the other geometric parameter automatically. Replace the circle's distance function with any other, and now you have the flow around something else... such as a [donut](examples/ThreeD_donut.jl) or the [Julia logo](examples/TwoD_Julia.jl). Finally, the last line defines the `Simulation` by passing in parameters we've defined. +The second to last line defines the circle geometry using a [signed distance function](https://en.wikipedia.org/wiki/Signed_distance_function#Applications). The `AutoBody` function uses [automatic differentiation](https://github.com/JuliaDiff/) to infer the other geometric parameter automatically. Replace the circle's distance function with any other, and now you have the flow around something else... such as a [donut](https://github.com/WaterLily-jl/WaterLily.jl/blob/master/examples/ThreeD_donut.jl) or the [Julia logo](https://github.com/WaterLily-jl/WaterLily.jl/blob/master/examples/TwoD_Julia.jl). Finally, the last line defines the `Simulation` by passing in parameters we've defined. Now we can create a simulation (first line) and run it forward in time (third line) ```julia @@ -61,10 +56,10 @@ Note we've set `n,m` to be multiples of powers of 2, which is important when usi using Plots contour(circ.flow.p') ``` -A set of [flow metric functions](src/Metrics.jl) have been implemented and the examples use these to make gifs such as the one above. +A set of [flow metric functions](https://github.com/WaterLily-jl/WaterLily.jl/blob/master/src/Metrics.jl) have been implemented and the examples use these to make gifs such as the one above. ### 3D Taylor Green Vortex -The three-dimensional [Taylor Green Vortex](examples/ThreeD_TaylorGreenVortex.jl) demonstrates many of the other available simulation options. First, you can simulate a nontrivial initial velocity field by passing in a vector function `uλ(i,xyz)` where `i ∈ (1,2,3)` indicates the velocity component `uᵢ` and `xyz=[x,y,z]` is the position vector. +The three-dimensional [Taylor Green Vortex](https://github.com/WaterLily-jl/WaterLily.jl/blob/master/examples/ThreeD_TaylorGreenVortex.jl) demonstrates many of the other available simulation options. First, you can simulate a non-trivial initial velocity field by passing in a vector function `uλ(i,xyz)` where `i ∈ (1,2,3)` indicates the velocity component `uᵢ` and `xyz=[x,y,z]` is the position vector. ```julia function TGV(; pow=6, Re=1e5, T=Float64, mem=Array) # Define vortex size, velocity, viscosity @@ -91,10 +86,7 @@ For an AMD GPU, use `import AMDGPU` and `mem=AMDGPU.ROCArray`. Note that Julia 1 ### Moving bodies -

- -

- +![Flapping line segment flow](examples/hover.gif) You can simulate moving bodies in WaterLily by passing a coordinate `map` to `AutoBody` in addition to the `sdf`. ```julia @@ -113,17 +105,15 @@ function hover(L=2^5;Re=250,U=1,amp=π/4,ϵ=0.5,thk=2ϵ+√2) Simulation((6L,6L),(0,0),L;U,ν=U*L/Re,body=AutoBody(sdf,map),ϵ) end ``` -[In this example](examples/TwoD_hover.jl), the `sdf` function defines a line segment from `-L/2 ≤ x[2] ≤ L/2` with a thickness `thk`. To make the line segment move, we define a coordinate transformation function `map(x,t)`. In this example, the coordinate `x` is shifted by `(3L,4L)` at time `t=0`, which moves the center of the segment to this point. However, the horizontal shift varies harmonically in time, sweeping the segment left and right during the simulation. The example also rotates the segment using the rotation matrix `R = [cos(α) sin(α); -sin(α) cos(α)]` where the angle `α` is also varied harmonically. The combined result is a thin flapping line, similar to a cross-section of a hovering insect wing. +[In this example](https://github.com/WaterLily-jl/WaterLily.jl/blob/master/examples/TwoD_hover.jl), the `sdf` function defines a line segment from `-L/2 ≤ x[2] ≤ L/2` with a thickness `thk`. To make the line segment move, we define a coordinate transformation function `map(x,t)`. In this example, the coordinate `x` is shifted by `(3L,4L)` at time `t=0`, which moves the center of the segment to this point. However, the horizontal shift varies harmonically in time, sweeping the segment left and right during the simulation. The example also rotates the segment using the rotation matrix `R = [cos(α) sin(α); -sin(α) cos(α)]` where the angle `α` is also varied harmonically. The combined result is a thin flapping line, similar to a cross-section of a hovering insect wing. One important thing to note here is the use of `StaticArrays` to define the `sdf` and `map`. This speeds up the simulation since it eliminates allocations at every grid cell and time step. ### Circle inside an oscillating flow -

- -

+![Oscillating flow](examples/oscillating.gif) -This [example](examples/TwoD_oscillatingFlowOverCircle.jl) demonstrates a 2D oscillating periodic flow over a circle. +This [example](https://github.com/WaterLily-jl/WaterLily.jl/blob/master/examples/TwoD_oscillatingFlowOverCircle.jl) demonstrates a 2D oscillating periodic flow over a circle. ```julia function circle(n,m;Re=250,U=1) # define a circle at the domain center @@ -142,7 +132,7 @@ The `perdir` argument is a tuple that specifies the directions to which periodic ### Accelerating reference frame -WaterLily gives the possibility to set up a `Simulation` using time-varying boundary conditions for the velocity field, as demonstrated in [this example](examples/TwoD_SlowStartCircle.jl). This can be used to simulate a flow in an accelerating reference frame. The following example demonstrates how to set up a `Simulation` with a time-varying velocity field. +WaterLily gives the possibility to set up a `Simulation` using time-varying boundary conditions for the velocity field, as demonstrated in [this example](https://github.com/WaterLily-jl/WaterLily.jl/blob/master/examples/TwoD_SlowStartCircle.jl). This can be used to simulate a flow in an accelerating reference frame. The following example demonstrates how to set up a `Simulation` with a time-varying velocity field. ```julia using WaterLily # define time-varying velocity boundary conditions @@ -155,7 +145,7 @@ The `Ut` function is used to define the time-varying velocity field. In this exa ### Periodic and convective boundary conditions -In addition to the standard free-slip (or reflective) boundary conditions, WaterLily also supports periodic boundary conditions, as demonstrated in [this example](examples/TwoD_circle_periodicBC_convectiveBC.jl). For instance, to set up a `Simulation` with periodic boundary conditions in the "y" direction the `perdir=(2,)` keyword argument should be passed +In addition to the standard free-slip (or reflective) boundary conditions, WaterLily also supports periodic boundary conditions, as demonstrated in [this example](https://github.com/WaterLily-jl/WaterLily.jl/blob/master/examples/TwoD_circle_periodicBC_convectiveBC.jl). For instance, to set up a `Simulation` with periodic boundary conditions in the "y" direction the `perdir=(2,)` keyword argument should be passed ```julia using WaterLily,StaticArrays @@ -188,7 +178,7 @@ Simulation((512,384), u_BC=(1,0), L=32; body, exitBC=true) ### Writing to a VTK file -The following [example](examples/ThreeD_cylinder_vtk_restart.jl) demonstrates how to write simulation data to a `.pvd` file using the `WriteVTK` package and the WaterLily `vtkwriter` function. The simplest writer can be instantiated with +The following [example](https://github.com/WaterLily-jl/WaterLily.jl/blob/master/examples/ThreeD_cylinder_vtk_restart.jl) demonstrates how to write simulation data to a `.pvd` file using the `WriteVTK` package and the WaterLily `vtkwriter` function. The simplest writer can be instantiated with ```julia using WaterLily,WriteVTK @@ -239,7 +229,7 @@ where `...` should be replaced with the code that generates the field you want t ### Restarting from a VTK file -The restart of a simulation from a VTK file is demonstrated in [this example](examples/ThreeD_cylinder_vtk_restart.jl). The `ReadVTK` package is used to read simulation data from a `.pvd` file. This `.pvd` __must__ have been written with the `vtkwriter` function and __must__ contain at least the `velocity` and `pressure` fields. The following example demonstrates how to restart a simulation from a `.pvd` file using the `ReadVTK` package and the WaterLily `vtkreader` function +The restart of a simulation from a VTK file is demonstrated in [this example](https://github.com/WaterLily-jl/WaterLily.jl/blob/master/examples/ThreeD_cylinder_vtk_restart.jl). The `ReadVTK` package is used to read simulation data from a `.pvd` file. This `.pvd` __must__ have been written with the `vtkwriter` function and __must__ contain at least the `velocity` and `pressure` fields. The following example demonstrates how to restart a simulation from a `.pvd` file using the `ReadVTK` package and the WaterLily `vtkreader` function ```julia using WaterLily,ReadVTK sim = make_sim(...) @@ -258,7 +248,7 @@ Internally, this function reads the last file in the `.pvd` file and use that to WaterLily uses [KernelAbstractions.jl](https://github.com/JuliaGPU/KernelAbstractions.jl) to multi-thread on CPU and run on GPU backends. The implementation method and speed-up are documented in our [preprint](#to do). In summary, a single macro `WaterLily.@loop` is used for nearly every loop in the code base, and this uses KernelAbstractactions to generate optimized code for each back-end. The speed-up with respect to a serial (single thread) execution is more pronounce for large simulations, and we have measure up to x8 speedups when multi-threading on an Intel Xeon Platinum 8460Y @ 2.3GHz backend, and up to 200x speedup on an NVIDIA Hopper H100 64GB HBM2 GPU. When maximizing the GPU load, a cost of 1.44 nano-seconds has been measured per degree of freedom and time step. -Note that multi-threading requires _starting_ Julia with the `--threads` argument, see [the multi-threading section](https://docs.julialang.org/en/v1/manual/multi-threading/) of the manual. If you are running Julia with multiple threads, KernelAbstractions will detect this and multi-thread the loops automatically. As in the Taylor-Green-Vortex examples above, running on a GPU requires initializing the `Simulation` memory on the GPU, and care needs to be taken to move the data back to the CPU for visualization. See [jelly fish](examples/ThreeD_jelly.jl) for another non-trivial example. +Note that multi-threading requires _starting_ Julia with the `--threads` argument, see [the multi-threading section](https://docs.julialang.org/en/v1/manual/multi-threading/) of the manual. If you are running Julia with multiple threads, KernelAbstractions will detect this and multi-thread the loops automatically. As in the Taylor-Green-Vortex examples above, running on a GPU requires initializing the `Simulation` memory on the GPU, and care needs to be taken to move the data back to the CPU for visualization. See [jelly fish](https://github.com/WaterLily-jl/WaterLily.jl/blob/master/examples/ThreeD_jelly.jl) for another non-trivial example. Finally, KernelAbstractions does incur some CPU allocations for every loop, but other than this `sim_step!` is completely non-allocating. This is one reason why the speed-up improves as the size of the simulation increases. diff --git a/docs/make.jl b/docs/make.jl index cd89ce7..ebf7ca2 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -9,7 +9,7 @@ recursive_find(directory, pattern) = image_files = [] -for pattern in [r"\.gif", r"\.jpg"] +for pattern in [r"\.gif", r"\.jpg", r"\.png"] global image_files = vcat(image_files, recursive_find(joinpath(@__DIR__, "../examples"), pattern)) end