Skip to content

Commit 6a2c74e

Browse files
authored
Merge pull request #116 from Balaje/interpolation_tutorial
Interpolation tutorial
2 parents ef6eb63 + 3698222 commit 6a2c74e

6 files changed

Lines changed: 273 additions & 4 deletions

File tree

.github/workflows/ci.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ jobs:
3333
${{ runner.os }}-test-
3434
${{ runner.os }}-
3535
- uses: julia-actions/julia-buildpkg@v1
36-
- run: cd test/; julia --project=.. --color=yes --check-bounds=yes runtests.jl poisson.jl validation.jl elasticity.jl
36+
- run: cd test/; julia --project=.. --color=yes --check-bounds=yes runtests.jl poisson.jl validation.jl elasticity.jl
3737
tutorials_set_2:
3838
name: Tutorials2 ${{ matrix.version }} - ${{ matrix.os }} - ${{ matrix.arch }} - ${{ github.event_name }}
3939
runs-on: ${{ matrix.os }}
@@ -123,7 +123,7 @@ jobs:
123123
${{ runner.os }}-test-
124124
${{ runner.os }}-
125125
- uses: julia-actions/julia-buildpkg@v1
126-
- run: cd test/; julia --project=.. --color=yes --check-bounds=yes runtests.jl isotropic_damage.jl validation_DrWatson.jl
126+
- run: cd test/; julia --project=.. --color=yes --check-bounds=yes runtests.jl isotropic_damage.jl validation_DrWatson.jl interpolation_fe.jl
127127
docs:
128128
name: Documentation
129129
runs-on: ubuntu-latest

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@ Manifest.toml
77
tmp/
88
.vscode/
99
*.code-workspace
10+
*.DS_Store

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
2020
SpecialFunctions = "276daf66-3868-5448-9aa4-cd146d93841b"
2121

2222
[compat]
23-
Gridap = "0.16.3"
23+
Gridap = "0.16.4"
2424
GridapGmsh = "0.4"
2525
SpecialFunctions = "1"
2626
julia = "1.3"
322 KB
Loading

deps/build.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ files = [
1818
"Fluid-Structure Interaction"=>"fsi_tutorial.jl",
1919
"Electromagnetic scattering in 2D"=>"emscatter.jl",
2020
"Low-level API Poisson equation"=>"poisson_dev_fe.jl",
21-
"On using DrWatson.jl"=>"validation_DrWatson.jl"]
21+
"On using DrWatson.jl"=>"validation_DrWatson.jl",
22+
"Interpolation of CellFields"=>"interpolation_fe.jl"]
2223

2324
Sys.rm(notebooks_dir;recursive=true,force=true)
2425
for (i,(title,filename)) in enumerate(files)

src/interpolation_fe.jl

Lines changed: 267 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,267 @@
1+
# In this tutorial, we will look at how to
2+
# - Evaluate `CellFields` at arbitrary points
3+
# - Interpolate finite element functions defined on different
4+
# triangulations. We will consider examples for
5+
# - Lagrangian finite element spaces
6+
# - Raviart Thomas finite element spaces
7+
# - Vector-Valued Spaces
8+
# - Multifield finite element spaces
9+
10+
# ## Problem Statement
11+
# Let $\mathcal{T}_1$ and $\mathcal{T}_2$ be two triangulations of a
12+
# domain $\Omega$. Let $V_i$ be the finite element space defined on
13+
# the triangulation $\mathcal{T}_i$ for $i=1,2$. Let $f_h \in V_1$. The
14+
# interpolation problem is to find $g_h \in V_2$ such that
15+
#
16+
# ```math
17+
# dof_k^{V_2}(g_h) = dof_k^{V_2}(f_h),\quad \forall k \in
18+
# \{1,\dots,N_{dof}^{V_2}\}
19+
# ```
20+
21+
22+
# ## Setup
23+
# For the purpose of this tutorial we require `Test`, `Gridap` along with the
24+
# following submodules of `Gridap`
25+
26+
using Test
27+
using Gridap
28+
using Gridap.CellData
29+
using Gridap.Visualization
30+
31+
# We now create a computational domain on the unit square $[0,1]^2$ consisting
32+
# of 5 cells per direction
33+
34+
domain = (0,1,0,1)
35+
partition = (5,5)
36+
𝒯₁ = CartesianDiscreteModel(domain, partition)
37+
38+
39+
# ## Background
40+
# `Gridap` offers the feature to evaluate functions at arbitrary
41+
# points in the domain. This will be shown in the next
42+
# section. Interpolation then takes advantage of this feature to
43+
# obtain the `FEFunction` in the new space from the old one by
44+
# evaluating the appropriate degrees of freedom. Interpolation works
45+
# using the composite type `Interpolable` to tell `Gridap` that the
46+
# argument can be interpolated between triangulations.
47+
48+
# ## Interpolating between Lagrangian FE Spaces
49+
50+
# Let us define the infinite dimensional function
51+
52+
f(x) = x[1] + x[2]
53+
54+
# This function will be interpolated to the source `FESpace`
55+
# $V_1$. The space can be built using
56+
57+
reffe₁ = ReferenceFE(lagrangian, Float64, 1)
58+
V₁ = FESpace(𝒯₁, reffe₁)
59+
60+
# Finally to build the function $f_h$, we do
61+
62+
fₕ = interpolate_everywhere(f,V₁)
63+
64+
# To construct arbitrary points in the domain, we use `Random` package:
65+
66+
using Random
67+
pt = Point(rand(2))
68+
pts = [Point(rand(2)) for i in 1:3]
69+
70+
# The finite element function $f_h$ can be evaluated at arbitrary points (or
71+
# array of points) by
72+
73+
fₕ(pt), fₕ.(pts)
74+
75+
# We can also check our results using
76+
77+
@test fₕ(pt) f(pt)
78+
@test fₕ.(pts) f.(pts)
79+
80+
# Now let us define the new triangulation $\mathcal{T}_2$ of
81+
# $\Omega$. We build the new triangulation using a partition of 20 cells per
82+
# direction. The map can be passed as an argument to
83+
# `CartesianDiscreteModel` to define the position of the vertices in
84+
# the new mesh.
85+
86+
partition = (20,20)
87+
𝒯₂ = CartesianDiscreteModel(domain,partition)
88+
89+
# As before, we define the new `FESpace` consisting of second order
90+
# elements
91+
92+
reffe₂ = ReferenceFE(lagrangian, Float64, 2)
93+
V₂ = FESpace(𝒯₂, reffe₂)
94+
95+
# Now we interpolate $f_h$ onto $V_2$ to obtain the new function
96+
# $g_h$. The first step is to create the `Interpolable` version of
97+
# $f_h$.
98+
99+
if= Interpolable(fₕ)
100+
101+
# Then to obtain $g_h$, we dispatch `ifₕ` and the new `FESpace` $V_2$
102+
# to the `interpolate_everywhere` method of `Gridap`.
103+
104+
gₕ = interpolate_everywhere(ifₕ, V₂)
105+
106+
# We can also use
107+
# `interpolate` if interpolating only on the free dofs or
108+
# `interpolate_dirichlet` if interpolating the Dirichlet dofs of the
109+
# `FESpace`.
110+
111+
ḡₕ = interpolate(ifₕ, V₂)
112+
113+
# The finite element function $\bar{g}_h$ is the same as $g_h$ in this
114+
# example since all the dofs are free.
115+
116+
@test gₕ.cell_dof_values == ḡₕ.cell_dof_values
117+
118+
# Now we obtain a finite element function using `interpolate_dirichlet`
119+
120+
g̃ₕ = interpolate_dirichlet(ifₕ, V₂)
121+
122+
# Now $\tilde{g}_h$ will be equal to 0 since there are
123+
# no Dirichlet nodes defined in the `FESpace`. We can check by running
124+
125+
g̃ₕ.cell_dof_values
126+
127+
# Like earlier we can check our results for `gₕ`:
128+
129+
@test fₕ(pt) gₕ(pt) f(pt)
130+
@test fₕ.(pts) gₕ.(pts) f.(pts)
131+
132+
# We can visualize the results using Paraview
133+
134+
writevtk(get_triangulation(fₕ), "source", cellfields=["fₕ"=>fₕ])
135+
writevtk(get_triangulation(gₕ), "target", cellfields=["gₕ"=>gₕ])
136+
137+
# which produces the following output
138+
139+
# ![Target](../assets/interpolation_fe/source_and_target.png)
140+
141+
# ## Interpolating between Raviart-Thomas FESpaces
142+
143+
# The procedure is identical to Lagrangian finite element spaces, as
144+
# discussed in the previous section. The extra thing here is that
145+
# functions in Raviart-Thomas spaces are vector-valued. The degrees of
146+
# freedom of the RT spaces are fluxes of the function across the edge
147+
# of the element. Refer to the
148+
# [tutorial](https://gridap.github.io/Tutorials/dev/pages/t007_darcy/)
149+
# on Darcy equation with RT for more information on the RT
150+
# elements.
151+
152+
# Assuming a function
153+
154+
f(x) = VectorValue([x[1], x[2]])
155+
156+
# on the domain, we build the associated finite dimensional version
157+
# $f_h \in V_1$.
158+
159+
reffe₁ = ReferenceFE(raviart_thomas, Float64, 1) # RT space of order 1
160+
V₁ = FESpace(𝒯₁, reffe₁)
161+
fₕ = interpolate_everywhere(f, V₁)
162+
163+
# As before, we can evaluate the RT function on any arbitrary point in
164+
# the domain.
165+
166+
fₕ(pt), fₕ.(pts)
167+
168+
# Constructing the target RT space and building the `Interpolable`
169+
# object,
170+
171+
reffe₂ = ReferenceFE(raviart_thomas, Float64, 1) # RT space of order 1
172+
V₂ = FESpace(𝒯₂, reffe₂)
173+
if= Interpolable(fₕ)
174+
175+
# we can construct the new `FEFunction` $g_h \in V_2$ from $f_h$
176+
177+
gₕ = interpolate_everywhere(ifₕ, V₂)
178+
179+
# Like earlier we can check our results
180+
181+
@test gₕ(pt) f(pt) fₕ(pt)
182+
183+
# ## Interpolating vector-valued functions
184+
185+
# We can also interpolate vector-valued functions across
186+
# triangulations. First, we define a vector-valued function on a
187+
# two-dimensional mesh.
188+
189+
f(x) = VectorValue([x[1], x[1]+x[2]])
190+
191+
# We then create a vector-valued reference element containing linear
192+
# elements along with the source finite element space $V_1$.
193+
194+
reffe₁ = ReferenceFE(lagrangian, VectorValue{2,Float64}, 1)
195+
V₁ = FESpace(𝒯₁, reffe₁)
196+
fₕ = interpolate_everywhere(f, V₁)
197+
198+
# The target finite element space $V_2$ can be defined in a similar manner.
199+
200+
reffe₂ = ReferenceFE(lagrangian, VectorValue{2,Float64}, 2)
201+
V₂ = FESpace(𝒯₂, reffe₂)
202+
203+
# The rest of the process is similar to the previous sections, i.e.,
204+
# define the `Interpolable` version of $f_h$ and use
205+
# `interpolate_everywhere` to find $g_h \in V₂$.
206+
207+
if= Interpolable(fₕ)
208+
gₕ = interpolate_everywhere(ifₕ, V₂)
209+
210+
# We can then check the results
211+
212+
@test gₕ(pt) f(pt) fₕ(pt)
213+
214+
215+
# ## Interpolating Multi-field Functions
216+
217+
# Similarly, it is possible to interpolate between multi-field finite element
218+
# functions. First, we define the components $h_1(x), h_2(x)$ of a
219+
# multi-field function $h(x)$ as follows.
220+
221+
h₁(x) = x[1]+x[2]
222+
h₂(x) = x[1]
223+
224+
# Next we create a Lagrangian finite element space containing linear
225+
# elements.
226+
227+
reffe₁ = ReferenceFE(lagrangian, Float64, 1)
228+
V₁ = FESpace(𝒯₁, reffe₁)
229+
230+
# Next we create a `MultiFieldFESpace` $V_1 \times V_1$ and
231+
# interpolate the function $h(x)$ to the source space $V_1$.
232+
233+
V₁xV₁ = MultiFieldFESpace([V₁,V₁])
234+
fₕ = interpolate_everywhere([h₁, h₂], V₁xV₁)
235+
236+
# Similarly, the target multi-field finite element space is created
237+
# using $\Omega_2$.
238+
239+
reffe₂ = ReferenceFE(lagrangian, Float64, 2)
240+
V₂ = FESpace(𝒯₂, reffe₂)
241+
V₂xV₂ = MultiFieldFESpace([V₂,V₂])
242+
243+
# Now, to find $g_h \in V_2 \times V_2$, we first extract the components of
244+
# $f_h$ and obtain the `Interpolable` version of the components.
245+
246+
fₕ¹, fₕ² = fₕ
247+
ifₕ¹ = Interpolable(fₕ¹)
248+
ifₕ² = Interpolable(fₕ²)
249+
250+
# We can then use `interpolate_everywhere` on the `Interpolable`
251+
# version of the components and obtain $g_h \in V_2 \times V_2$ as
252+
# follows.
253+
254+
gₕ = interpolate_everywhere([ifₕ¹,ifₕ²], V₂xV₂)
255+
256+
# We can then check the results of the interpolation, component-wise.
257+
258+
gₕ¹, gₕ² = gₕ
259+
@test fₕ¹(pt) gₕ¹(pt)
260+
@test fₕ²(pt) gₕ²(pt)
261+
262+
# ## Acknowledgements
263+
264+
# Gridap contributors acknowledge support received from Google,
265+
# Inc. through the Google Summer of Code 2021 project [A fast finite
266+
# element interpolator in
267+
# Gridap.jl](https://summerofcode.withgoogle.com/projects/#6175012823760896).

0 commit comments

Comments
 (0)