Skip to content

Commit 361a175

Browse files
authored
Merge pull request #50 from maltezfaria/interpolations-ext
Extension for `Interpolants`
2 parents eefc78a + cb03772 commit 361a175

File tree

12 files changed

+134
-17
lines changed

12 files changed

+134
-17
lines changed

Project.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,19 @@ LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
88
StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"
99

1010
[weakdeps]
11+
Interpolations = "a98d9a8b-a2ab-59e6-89dd-64a1c18fca59"
1112
MMG_jll = "86086c02-e288-5929-a127-40944b0018b7"
1213
Makie = "ee78f7c6-11fb-53f2-987a-cfe4a2b5a57a"
1314
MarchingCubes = "299715c1-40a9-479a-aaf9-4a633d36f717"
1415

1516
[extensions]
17+
InterpolationsExt = "Interpolations"
1618
MMGSurfaceExt = ["MMG_jll", "MarchingCubes"]
1719
MMGVolumeExt = "MMG_jll"
1820
MakieExt = "Makie"
1921

2022
[compat]
23+
Interpolations = "0.15"
2124
LinearAlgebra = "1"
2225
MMG_jll = "5"
2326
Makie = "0.21, 0.22"

docs/Project.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
33
DocumenterCitations = "daee34ce-89f3-4625-b898-19384cb65244"
44
GLMakie = "e9467ef8-e4e7-5192-8a1a-b1aee30e663a"
55
Gmsh = "705231aa-382f-11e9-3f0c-b7cb4346fdeb"
6+
Interpolations = "a98d9a8b-a2ab-59e6-89dd-64a1c18fca59"
67
LevelSetMethods = "ca3df947-0575-4ae6-b9a3-78df393a7451"
78
LiveServer = "16fef848-5104-11e9-1b77-fb7a48bbb589"
89
MMG_jll = "86086c02-e288-5929-a127-40944b0018b7"

docs/make.jl

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ using Documenter
33
using GLMakie
44
using MMG_jll
55
using MarchingCubes
6+
using Interpolations
67
using StaticArrays
78
using DocumenterCitations
89

@@ -22,7 +23,7 @@ const numbered_pages = [
2223
]
2324

2425
modules = [LevelSetMethods]
25-
for extension in [:MakieExt, :MMGSurfaceExt, :MMGVolumeExt]
26+
for extension in [:MakieExt, :MMGSurfaceExt, :MMGVolumeExt, :InterpolationsExt]
2627
ext = Base.get_extension(LevelSetMethods, extension)
2728
isnothing(ext) && "error loading $ext"
2829
push!(modules, ext)
@@ -42,7 +43,8 @@ makedocs(;
4243
"terms.md",
4344
"time-integrators.md",
4445
"boundary-conditions.md",
45-
"Extensions" => ["extension-makie.md", "extension-mmg.md"],
46+
"Extensions" =>
47+
["extension-makie.md", "extension-mmg.md", "extension-interpolations.md"],
4648
"Examples" => ["example-zalesak.md", "example-shape-optim.md"],
4749
numbered_pages,
4850
),
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# [Interpolations extension](@id extension-interpolations)
2+
3+
This extension overloads the `interpolate` function from
4+
[`Interpolations.jl`](https://juliamath.github.io/Interpolations.jl/latest/) to provide a
5+
way to construct a global interpolant from the discrete data in a
6+
[`LevelSet`](@ref) or [`LevelSetEquation`](@ref). This can be useful in situations where you want
7+
to evaluate the approximate underlying functions at points that are not on the grid.
8+
9+
Here is an example of how to construct such an interpolant:
10+
11+
```@example interpolations
12+
using LevelSetMethods, Interpolations
13+
LevelSetMethods.set_makie_theme!()
14+
a, b = (-2, -2), (2, 2)
15+
ϕ = LevelSetMethods.star(CartesianGrid(a, b, (50, 50)))
16+
itp = interpolate(ϕ, BSpline(Cubic())) # create the interpolant
17+
```
18+
19+
Once constructed, the interpolant can be used to evaluate the level-set function anywhere
20+
inside the grid:
21+
22+
```@example interpolations
23+
itp(0.5, 0.5)
24+
```
25+
26+
This can be used e.g. to plot the level-set function using `Makie`:
27+
28+
```@example interpolations
29+
using CairoMakie
30+
xx = yy = -2:0.01:2
31+
contour(xx, yy, [itp(x,y) for x in xx, y in yy]; levels = [0], linewidth = 2)
32+
```
33+
34+
Trying to evaluate it outside the domain will throw an error:
35+
36+
```@example interpolations
37+
try
38+
itp(3, 0.1)
39+
catch e
40+
println("Error caught")
41+
end
42+
```
43+
44+
Using it on three-dimensional level sets is similar:
45+
46+
```@example interpolations
47+
using LinearAlgebra
48+
grid = CartesianGrid((-1.5, -1.5, -1.5), (1.5, 1.5, 1.5), (50, 50, 50))
49+
P1, P2 = (-1, 0, 0), (1, 0, 0)
50+
b = 1.05
51+
f = (x) -> norm(x .- P1)*norm(x .- P2) - b^2
52+
ϕ = LevelSet(f, grid)
53+
itp = interpolate(ϕ) # cubic spline by default
54+
println("ϕ(0.5, 0.5, 0.5) = ", f((0.5, 0.5, 0.5)))
55+
println("itp(0.5, 0.5, 0.5) = ", itp(0.5, 0.5, 0.5))
56+
```

docs/src/extension-makie.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
# [Makie extension](@id extension-makie)
22

3-
[Makie](https://docs.makie.org/v0.21/) can be used to visualize levelset functions in both 2
4-
and 3 dimensions. After loading one of the `Makie` backends (we recomment `GLMakie` for 3D),
5-
you can simply call `plot` on the levelset function to visualize it. For example:
3+
[Makie](https://docs.makie.org/v0.21/) can be used to visualize level set functions in both 2
4+
and 3 dimensions. After loading one of the `Makie` backends (we recommend `GLMakie` for 3D),
5+
you can simply call `plot` on the level set function to visualize it. For example:
66

77
```@example contour2D
88
using LevelSetMethods, GLMakie
@@ -11,15 +11,15 @@ grid = CartesianGrid((-2, -2), (2, 2), (100, 100))
1111
plot(ϕ)
1212
```
1313

14-
By default, only the zero level-set is plotted as a contour line. For more control, simply
14+
By default, only the zero level set is plotted as a contour line. For more control, simply
1515
call the `contour` (or `contourf`) function from `Makie` directly. For example:
1616

1717
```@example contour2D
1818
contour(ϕ; levels = [-0.5, 0, 0.5], labels = true)
1919
```
2020

2121
Although you can manually customize the `Axis` attributes for the plot, `LevelSetMethods`
22-
provides a `Theme` with some reasonable defaults for plotting levelset functions:
22+
provides a `Theme` with some reasonable defaults for plotting level set functions:
2323

2424
```@example contour2D
2525
theme = LevelSetMethods.makie_theme()
@@ -28,7 +28,7 @@ with_theme(theme) do
2828
end
2929
```
3030

31-
In `3D`, the `plot` function will plot the zero level-set as an isosurface. For example:
31+
In `3D`, the `plot` function will plot the zero level set as an isosurface. For example:
3232

3333
```@example volume3D
3434
using LevelSetMethods, GLMakie, LinearAlgebra

docs/src/extension-mmg.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# [MMG extension](@id extension-mmg)
22

3-
This extension provides functions to generate meshes of levelset functions using [MMG](https://www.mmgtools.org/).
4-
It define two methods: `export_volume_mesh` and `export_surface_mesh`.
3+
This extension provides functions to generate meshes of level-set functions using [MMG](https://www.mmgtools.org/).
4+
It defines two methods: `export_volume_mesh` and `export_surface_mesh`.
55
For both of them, it is possible to control the size of the generated mesh using the following optional parameters:
66

77
- `hgrad` control the growth ratio between two adjacent edges.
@@ -10,7 +10,7 @@ For both of them, it is possible to control the size of the generated mesh using
1010

1111
## Generation of 2D and 3D mesh from a level-set
1212

13-
For 2 and 3 dimensional Cartesian levelset, one can use the `export_volume_mesh` function to generate meshes.
13+
For 2 and 3-dimensional Cartesian level set, one can use the `export_volume_mesh` function to generate meshes.
1414
This method relies on the `mmg2d_O3` and `mmg3d_O3` utilities.
1515
Example in 2D:
1616

ext/InterpolationsExt.jl

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
module InterpolationsExt
2+
3+
import Interpolations as Itp
4+
import LevelSetMethods as LSM
5+
6+
function __init__()
7+
@info "Loading Interpolations extension for LevelSetMethods.jl"
8+
end
9+
10+
Itp.interpolate(ϕ::LSM.LevelSet) = Itp.interpolate(ϕ, Itp.BSpline(Itp.Cubic()))
11+
12+
function Itp.interpolate(ϕ::LSM.LevelSet, mode)
13+
itp = Itp.interpolate(ϕ.vals, mode)
14+
grids = LSM.grid1d(LSM.mesh(ϕ))
15+
return Itp.scale(itp, grids...)
16+
end
17+
18+
function Itp.interpolate(eq::LSM.LevelSetEquation, args...; kwargs...)
19+
return Itp.interpolate(LSM.current_state(eq), args...; kwargs...)
20+
end
21+
22+
end # module

ext/MMGVolumeExt.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ function LSM.export_volume_mesh(
7878
num_triangles = 2(nx - 1) * (ny - 1)
7979
write(file, "\nTriangles\n")
8080
write(file, "$num_triangles\n")
81-
for x_id in 1:nx-1, y_id in 1:ny-1
81+
for x_id in 1:(nx-1), y_id in 1:(ny-1)
8282
c00 = (y_id - 1) * nx + x_id
8383
c10 = c00 + 1
8484
c01 = c00 + nx
@@ -96,7 +96,7 @@ function LSM.export_volume_mesh(
9696
num_tetrahedrons = 6(nx - 1) * (ny - 1) * (nz - 1)
9797
write(file, "\nTetrahedra\n")
9898
write(file, "$num_tetrahedrons\n")
99-
for x_id in 1:nx-1, y_id in 1:ny-1, z_id in 1:nz-1
99+
for x_id in 1:(nx-1), y_id in 1:(ny-1), z_id in 1:(nz-1)
100100
c000 = (z_id - 1) * nx * ny + (y_id - 1) * nx + x_id
101101
c100 = c000 + 1
102102
c010 = c000 + nx

src/levelsetequation.jl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ function Base.show(io::IO, eq::LevelSetEquation)
102102
print(io, "Level-set equation given by\n")
103103
print(io, "\n \t ϕₜ + ")
104104
terms = eq.terms
105-
for term in terms[1:end-1]
105+
for term in terms[1:(end-1)]
106106
print(io, term)
107107
print(io, " + ")
108108
end
@@ -138,7 +138,7 @@ function integrate!(ls::LevelSetEquation, tf, Δt = Inf)
138138
the level-set equation cannot be solved back in time"
139139
@assert tf >= tc msg
140140
# append boundary conditions for integration
141-
ϕ = current_state(ls)
141+
ϕ = current_state(ls)
142142
buf = buffers(ls)
143143
integrator = time_integrator(ls)
144144
# dynamic dispatch. Should not be a problem provided enough computation is
@@ -153,7 +153,7 @@ end
153153
number_of_buffers(fe::ForwardEuler) = 1
154154

155155
@noinline function _integrate!(ϕ, buffers, integrator::ForwardEuler, terms, tc, tf, Δt)
156-
buffer = buffers[1]
156+
buffer = buffers[1]
157157
α = cfl(integrator)
158158
Δt_cfl = α * compute_cfl(terms, ϕ, tc)
159159
Δt = min(Δt, Δt_cfl)

src/meshes.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ function interior_indices(g::CartesianGrid, P)
7979
N = dimension(g)
8080
sz = size(g)
8181
I = ntuple(N) do dim
82-
return P+1:sz[dim]-P
82+
return (P+1):(sz[dim]-P)
8383
end
8484
return CartesianIndices(I)
8585
end

0 commit comments

Comments
 (0)