Skip to content

Commit 87c5969

Browse files
authored
Merge pull request #191 from gridap/gridap-0.19
Gridap 0.19
2 parents 9f65647 + 4bc721e commit 87c5969

9 files changed

Lines changed: 716 additions & 82 deletions

File tree

.github/workflows/ci.yml

Lines changed: 24 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ on:
55
- create
66
jobs:
77

8-
tutorials_set_1:
9-
name: Tutorials1 ${{ matrix.version }} - ${{ matrix.os }} - ${{ matrix.arch }} - ${{ github.event_name }}
8+
tutorials:
9+
name: Tutorials ${{ matrix.version }} - ${{ matrix.os }} - ${{ matrix.arch }} - ${{ github.event_name }} - ${{ matrix.test_set.name }}
1010
runs-on: ${{ matrix.os }}
1111
strategy:
1212
fail-fast: false
@@ -17,6 +17,21 @@ jobs:
1717
- ubuntu-latest
1818
arch:
1919
- x64
20+
test_set:
21+
- name: Basics
22+
files: "poisson.jl elasticity.jl lagrange_multipliers.jl dg_discretization.jl darcy.jl stokes.jl advection_diffusion.jl"
23+
- name: Nonlinear
24+
files: "p_laplacian.jl hyperelasticity.jl inc_navier_stokes.jl"
25+
- name: Applications
26+
files: "fsi_tutorial.jl emscatter.jl isotropic_damage.jl TopOptEMFocus.jl"
27+
- name: Transient
28+
files: "isotropic_damage.jl transient_linear.jl transient_nonlinear.jl "
29+
- name: Hybrid
30+
files: "poisson_hdg.jl poisson_hho.jl"
31+
- name: Plugins
32+
files: "stokes_blocks.jl poisson_amr.jl poisson_unfitted.jl"
33+
- name: Other
34+
files: "validation.jl validation_DrWatson.jl interpolation_fe.jl poisson_dev_fe.jl geometry_dev.jl"
2035
steps:
2136
- uses: actions/checkout@v4
2237
- uses: julia-actions/setup-julia@v2
@@ -25,72 +40,11 @@ jobs:
2540
arch: ${{ matrix.arch }}
2641
- uses: julia-actions/cache@v2
2742
- uses: julia-actions/julia-buildpkg@v1
28-
- run: cd test/; julia --project=.. --color=yes --check-bounds=yes runtests.jl poisson.jl validation.jl elasticity.jl lagrange_multipliers.jl
29-
tutorials_set_2:
30-
name: Tutorials2 ${{ matrix.version }} - ${{ matrix.os }} - ${{ matrix.arch }} - ${{ github.event_name }}
31-
runs-on: ${{ matrix.os }}
32-
strategy:
33-
fail-fast: false
34-
matrix:
35-
version:
36-
- '1.10'
37-
os:
38-
- ubuntu-latest
39-
arch:
40-
- x64
41-
steps:
42-
- uses: actions/checkout@v4
43-
- uses: julia-actions/setup-julia@v2
44-
with:
45-
version: ${{ matrix.version }}
46-
arch: ${{ matrix.arch }}
47-
- uses: julia-actions/cache@v2
48-
- uses: julia-actions/julia-buildpkg@v1
49-
- run: cd test/; julia --project=.. --color=yes --check-bounds=yes runtests.jl p_laplacian.jl hyperelasticity.jl dg_discretization.jl fsi_tutorial.jl poisson_amr.jl
50-
tutorials_set_3:
51-
name: Tutorials3 ${{ matrix.version }} - ${{ matrix.os }} - ${{ matrix.arch }} - ${{ github.event_name }}
52-
runs-on: ${{ matrix.os }}
53-
strategy:
54-
fail-fast: false
55-
matrix:
56-
version:
57-
- '1.10'
58-
os:
59-
- ubuntu-latest
60-
arch:
61-
- x64
62-
steps:
63-
- uses: actions/checkout@v4
64-
- uses: julia-actions/setup-julia@v2
65-
with:
66-
version: ${{ matrix.version }}
67-
arch: ${{ matrix.arch }}
68-
- uses: julia-actions/cache@v2
69-
- uses: julia-actions/julia-buildpkg@v1
70-
- run: cd test/; julia --project=.. --color=yes --check-bounds=yes runtests.jl darcy.jl inc_navier_stokes.jl stokes.jl poisson_dev_fe.jl emscatter.jl
71-
tutorials_set_4:
72-
name: Tutorials4 ${{ matrix.version }} - ${{ matrix.os }} - ${{ matrix.arch }} - ${{ github.event_name }}
73-
runs-on: ${{ matrix.os }}
74-
strategy:
75-
fail-fast: false
76-
matrix:
77-
version:
78-
- '1.10'
79-
os:
80-
- ubuntu-latest
81-
arch:
82-
- x64
83-
steps:
84-
- uses: actions/checkout@v4
85-
- uses: julia-actions/setup-julia@v2
86-
with:
87-
version: ${{ matrix.version }}
88-
arch: ${{ matrix.arch }}
89-
- uses: julia-actions/cache@v2
90-
- uses: julia-actions/julia-buildpkg@v1
91-
- run: cd test/; julia --project=.. --color=yes --check-bounds=yes runtests.jl isotropic_damage.jl validation_DrWatson.jl interpolation_fe.jl transient_linear.jl transient_nonlinear.jl TopOptEMFocus.jl
43+
- run: |
44+
cd test/
45+
julia --project=.. --color=yes --check-bounds=yes runtests.jl ${{ matrix.test_set.files }}
9246
tutorials_mpi:
93-
name: TutorialsMPI ${{ matrix.version }} - ${{ matrix.os }} - ${{ matrix.arch }} - ${{ github.event_name }}
47+
name: Tutorials MPI ${{ matrix.version }} - ${{ matrix.os }} - ${{ matrix.arch }} - ${{ github.event_name }}
9448
runs-on: ${{ matrix.os }}
9549
strategy:
9650
fail-fast: false
@@ -109,7 +63,9 @@ jobs:
10963
arch: ${{ matrix.arch }}
11064
- uses: julia-actions/cache@v2
11165
- uses: julia-actions/julia-buildpkg@v1
112-
- run: cd test/; julia --project=.. --color=yes --check-bounds=yes runtests_mpi.jl
66+
- run: |
67+
cd test/
68+
julia --project=.. --color=yes --check-bounds=yes runtests_mpi.jl
11369
docs:
11470
name: Documentation
11571
runs-on: ubuntu-latest

Project.toml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ authors = ["Santiago Badia <santiago.badia@monash.edu>", "Francesc Verdugo <fver
44
version = "0.17.0"
55

66
[deps]
7+
BlockArrays = "8e7c35d0-a365-5155-bbbb-fb81a777f24e"
78
CairoMakie = "13f3f980-e62b-5c42-98c6-ff1f3baf88f0"
89
ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4"
910
DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0"
@@ -17,6 +18,7 @@ GridapGmsh = "3025c34a-b394-11e9-2a55-3fee550c04c8"
1718
GridapMakie = "41f30b06-6382-4b60-a5f7-79d86b35bf5d"
1819
GridapP4est = "c2c8e14b-f5fd-423d-9666-1dd9ad120af9"
1920
GridapPETSc = "bcdc36c2-0c3e-11ea-095a-c9dadae499f1"
21+
GridapSolvers = "6d3209ee-5e3c-4db7-a716-942eb12ed534"
2022
IJulia = "7073ff75-c697-5162-941a-fcdaad2a7d2a"
2123
InteractiveUtils = "b77e0a4c-d291-57a0-90e8-8db25a27a240"
2224
LineSearches = "d3d80556-e9d4-5f37-9878-2ab0fcc64255"
@@ -34,12 +36,14 @@ SpecialFunctions = "276daf66-3868-5448-9aa4-cd146d93841b"
3436
Zygote = "e88e6eb3-aa80-5325-afca-941959d7151f"
3537

3638
[compat]
39+
BlockArrays = "1.6.3"
3740
DataStructures = "0.18.22"
38-
Gridap = "0.18"
41+
Gridap = "0.19"
3942
GridapDistributed = "0.4"
4043
GridapGmsh = "0.7"
4144
GridapP4est = "0.3"
4245
GridapPETSc = "0.5"
46+
GridapSolvers = "0.6"
4347
MPI = "0.20"
4448
SpecialFunctions = "1"
4549
julia = "1.6"

deps/build.jl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ files = [
2626
"Topology optimization"=>"TopOptEMFocus.jl",
2727
"Poisson on unfitted meshes"=>"poisson_unfitted.jl",
2828
"Poisson with AMR"=>"poisson_amr.jl",
29+
"Poisson with HDG"=>"poisson_hdg.jl",
30+
"Poisson with HHO on polytopal meshes"=>"poisson_hho.jl",
31+
"Block assembly and solvers: Incompressible Stokes example"=>"stokes_blocks.jl",
2932
"Lagrange multipliers" => "lagrange_multipliers.jl",
3033
"Low-level API - Poisson equation"=>"poisson_dev_fe.jl",
3134
"Low-level API - Geometry" => "geometry_dev.jl",

docs/make.jl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,15 +60,15 @@ for (i,(title,filename)) in enumerate(Tutorials.files)
6060
end
6161

6262
makedocs(
63-
sitename = "Gridap tutorials",
64-
format = Documenter.HTML(),
65-
pages = pages
63+
sitename = "Gridap tutorials",
64+
format = Documenter.HTML(),
65+
pages = pages
6666
)
6767

6868
# Documenter can also automatically deploy documentation to gh-pages.
6969
# See "Hosting Documentation" and deploydocs() in the Documenter manual
7070
# for more information.
7171

7272
deploydocs(
73-
repo = "github.com/gridap/Tutorials.git"
73+
repo = "github.com/gridap/Tutorials.git"
7474
)

src/advection_diffusion.jl

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -82,20 +82,25 @@
8282

8383
# The meshed model is like following:
8484

85-
# ![Pentagon_2D_Mesh](Pentagon_2D_Mesh.png)
85+
# ![Pentagon_2D_Mesh](../assets/advection_diffusion/Pentagon_2D_Mesh.png)
8686

8787
# ## Numerical Scheme
8888

89-
# The weak form of a PDE is a reformulation that allows the problem to be solved in a broader function space. Instead of requiring the solution to satisfy the PDE at every point (as in the strong form), the weak form requires the solution to satisfy an integral equation. This makes it particularly suitable for numerical methods such as the Finite Element Method.
89+
# The weak form of a PDE is a reformulation that allows the problem to be solved in a broader
90+
# function space. Instead of requiring the solution to satisfy the PDE at every point (as in the strong form),
91+
# the weak form requires the solution to satisfy an integral equation. This makes it particularly suitable for
92+
# numerical methods such as the Finite Element Method.
9093

91-
# Since we already hcave the original PDE (strong form), we can multiply each side by a test function $v \in H^1(\Omega)$(functions with square-integrable first derivatives). $v$ satisfies the Dirichlet boundary condition of $0$. Make integral on both sides.
94+
# Since we already hcave the original PDE (strong form), we can multiply each side by a test
95+
# function $v \in H^1(\Omega)$(functions with square-integrable first derivatives). $v$ satisfies
96+
# the Dirichlet boundary condition of $0$. Make integral on both sides.
9297

9398
# The weak form associated with this formulation is, find $T \in H^1(\Omega)$, such that:
94-
# $$
99+
# ```math
95100
# \int_\Omega v (\mathbf{u} \cdot \nabla T) \, \mathrm{d}\Omega
96101
# + \int_\Omega D \nabla T \cdot \nabla v \, \mathrm{d}\Omega
97102
# = 0
98-
# $$
103+
# ```
99104

100105
# ## FE spaces
101106

@@ -106,7 +111,7 @@ using GridapGmsh
106111

107112
# Import the model from file using GmshDiscreteModel:
108113

109-
model_pentagon = GmshDiscreteModel("pentagon_mesh.msh")
114+
model_pentagon = GmshDiscreteModel("../models/pentagon_mesh.msh")
110115

111116
# Set up the test FE space $V_0$, which conforms the zero value boundary conditions.
112117

@@ -165,8 +170,8 @@ writevtk(Ω,"results_non_zero",cellfields=["uh_non_zero"=>uh_non_zero])
165170

166171
# We can use the ParaView to preview the results clearly. Here is the temperature distribution without any flow velocity:
167172

168-
# ![Result_zero](Result_zero.png)
173+
# ![Result_zero](../assets/advection_diffusion/Result_zero.png)
169174

170175
# Here is the temperature distribution with a flow velocity of 2 going up:
171176

172-
# ![Result_zero](Result_non_zero.png)
177+
# ![Result_zero](../assets/advection_diffusion/Result_non_zero.png)

src/poisson_hdg.jl

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
# In this tutorial, we will implement a Hybridizable Discontinuous Galerkin (HDG) method
2+
# for solving the Poisson equation. The HDG method is an efficient variant of DG methods
3+
# that introduces an auxiliary variable m on mesh interfaces to reduce the global system size.
4+
#
5+
# ## HDG Discretization
6+
#
7+
# We consider the Poisson equation with Dirichlet boundary conditions:
8+
#
9+
# ```math
10+
# \begin{aligned}
11+
# -\Delta u &= f \quad \text{in} \quad \Omega\\
12+
# u &= g \quad \text{in} \quad \partial\Omega
13+
# \end{aligned}
14+
# ```
15+
#
16+
# The HDG method first rewrites the problem as a first-order system:
17+
#
18+
# ```math
19+
# \begin{aligned}
20+
# \boldsymbol{q} + \nabla u &= \boldsymbol{0} \quad \text{in} \quad \Omega\\
21+
# \nabla \cdot \boldsymbol{q} &= f \quad \text{in} \quad \Omega\\
22+
# u &= g \quad \text{on} \quad \partial\Omega
23+
# \end{aligned}
24+
# ```
25+
#
26+
# The HDG discretization introduces three variables:
27+
# - ``\boldsymbol{q}_h``: the approximation to the flux ``\boldsymbol{q}``
28+
# - ``u_h``: the approximation to the solution ``u``
29+
# - ``m_h``: the approximation to the trace of ``u`` on element faces
30+
#
31+
# Numerical fluxes are defindes as
32+
#
33+
# ```math
34+
# \widehat{\boldsymbol{q}}_h = \boldsymbol{q}_h + \tau(u_h - m_h)\boldsymbol{n}
35+
# ```
36+
#
37+
# where $\tau$ is a stabilization parameter.
38+
#
39+
# First, let's load the required Gridap packages:
40+
41+
using Gridap
42+
using Gridap.Geometry
43+
using Gridap.FESpaces
44+
using Gridap.MultiField
45+
using Gridap.CellData
46+
47+
# ## Manufactured Solution
48+
#
49+
# We use the method of manufactured solutions to verify our implementation.
50+
# We choose a solution u and derive the corresponding source term f:
51+
52+
u(x) = sin(2*π*x[1])*sin(2*π*x[2])
53+
q(x) = -(u)(x) # Define the flux q = -∇u
54+
f(x) = (∇ q)(x) # Source term f = -Δu = -∇⋅(∇u)$
55+
56+
# ## Geometry
57+
#
58+
# We generate a D-dimensional simplicial mesh from a Cartesian grid:
59+
60+
D = 2 # Problem dimension
61+
nc = Tuple(fill(8, D)) # 4 cells in each direction
62+
domain = Tuple(repeat([0, 1], D)) # Unit cube domain
63+
model = simplexify(CartesianDiscreteModel(domain,nc))
64+
65+
# From this mesh, we will require two triangulations where to define our HDG spaces:
66+
#
67+
# 1. A cell triangulation $\Omega$, for the volume variables
68+
# 2. A face triangulation $\Gamma$, for the skeleton variables
69+
#
70+
# These are given by
71+
72+
Ω = Triangulation(ReferenceFE{D}, model) # Volume triangulation
73+
Γ = Triangulation(ReferenceFE{D-1}, model) # Skeleton triangulation
74+
75+
# ## PatchTopology and PatchTriangulation
76+
#
77+
# A key aspect of hybrid methods is the use of static condensation, which is the
78+
# elimination of cell unknowns to reduce the size of the global system.
79+
# To achieve this, we need to be able to assemble and solve local problems on each cell, that
80+
# involve
81+
# - contributions from the cell itself
82+
# - contributions from the cell faces
83+
# To this end, Gridap provides a general framework for patch-assembly and solves. The idea
84+
# is to define a patch decomposition of the mesh (in this case, a patch is a cell and its sourrounding
85+
# faces). We can then gather contributions for each patch, solve the local problems, and
86+
# assemble the results into the global system.
87+
#
88+
# The following code creates the required `PatchTopology` for the problem at hand. We then
89+
# take d-dimensional slices of it by the means of `PatchTriangulation` and `PatchBoundaryTriangulation`.
90+
# These are the `Triangulation`s we will integrate our weakform over.
91+
92+
ptopo = Geometry.PatchTopology(model)
93+
Ωp = Geometry.PatchTriangulation(model,ptopo) # Patch volume triangulation
94+
Γp = Geometry.PatchBoundaryTriangulation(model,ptopo) # Patch skeleton triangulation
95+
96+
# ## FESpaces
97+
#
98+
# HDG uses three different finite element spaces:
99+
# 1. A vector-valued space for the flux q (Q)
100+
# 2. A scalar space for the solution u (V)
101+
# 3. A scalar space for the interface variable m (M)
102+
#
103+
# We then define discontinuous finite element spaces of the approppriate order, locally $\mathbb{P}^k$.
104+
# Note that only the skeletal space has Dirichlet boundary conditions.
105+
106+
order = 1 # Polynomial order
107+
reffe_Q = ReferenceFE(lagrangian, VectorValue{D, Float64}, order; space=:P)
108+
reffe_V = ReferenceFE(lagrangian, Float64, order; space=:P)
109+
reffe_M = ReferenceFE(lagrangian, Float64, order; space=:P)
110+
111+
V = TestFESpace(Ω, reffe_V; conformity=:L2) # Discontinuous vector space
112+
Q = TestFESpace(Ω, reffe_Q; conformity=:L2) # Discontinuous scalar space
113+
M = TestFESpace(Γ, reffe_M; conformity=:L2, dirichlet_tags="boundary") # Interface space
114+
N = TrialFESpace(M, u)
115+
116+
# ## MultiField Structure
117+
#
118+
# Since we are doing static condensation, we need assemble by blocks. In particular, the
119+
# `StaticCondensationOperator` expects the variables to be groupped in two blocks:
120+
# - The eliminated variables (in this case, the volume variables q and u)
121+
# - The retained variables (in this case, the interface variable m)
122+
# We will assemble by blocks using the `BlockMultiFieldStyle` API.
123+
124+
mfs = BlockMultiFieldStyle(2,(2,1)) # Special blocking for efficient static condensation
125+
X = MultiFieldFESpace([V, Q, N]; style=mfs)
126+
127+
# ## Weak Form and integration
128+
#
129+
130+
degree = 2*(order+1) # Integration degree
131+
dΩp = Measure(Ωp,degree) # Volume measure, on the patch triangulation
132+
dΓp = Measure(Γp,degree) # Surface measure, on the patch boundary triangulation
133+
134+
τ = 1.0 # HDG stabilization parameter
135+
136+
n = get_normal_vector(Γp) # Face normal vector
137+
Πn(u) = un # Normal component
138+
Π(u) = change_domain(u,Γp,DomainStyle(u)) # Project to skeleton
139+
140+
a((uh,qh,sh),(vh,wh,lh)) = ( qhwh - uh*(∇wh) - qh(vh) )dΩp + (sh*Πn(wh))dΓp +
141+
((Πn(qh) + τ*(Π(uh) - sh))*(Π(vh) + lh))dΓp
142+
l((vh,wh,lh)) = ( f*vh )dΩp
143+
144+
# ## Static Condensation and Solution
145+
#
146+
# With all these ingredients, we can now build our statically-condensed operator ans
147+
# solve the problem. Note that we are solving a scatically-condensed system. We can
148+
# retrieve the internal `AffineFEOperator` from `op.sc_op`.
149+
150+
op = MultiField.StaticCondensationOperator(ptopo,X,a,l)
151+
uh, qh, sh = solve(op)
152+
153+
= Measure(Ω,degree)
154+
eh = uh - u
155+
l2_uh = sqrt(sum((eheh)*dΩ))
156+
157+
writevtk(Ω,"results",cellfields=["uh"=>uh,"qh"=>qh,"eh"=>eh])
158+
159+
# ## Going Further
160+
#
161+
# By modifying the stabilisation term, HDG can also work on polytopal meshes. An driver
162+
# solving the same problem on a polytopal mesh is available [in the Gridap repository](https://github.com/gridap/Gridap.jl/blob/75efc9a7a7e286c27e7ca3ddef5468e591845484/test/GridapTests/HDGPolytopalTests.jl).
163+
# A tutorial for HHO on polytopal meshes is also available.
164+
#

0 commit comments

Comments
 (0)