Skip to content

Typos #186

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Apr 30, 2024
Merged

Typos #186

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 20 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# The DOLFINx tutorial

[![Test, build and publish](https://github.com/jorgensd/dolfinx-tutorial/actions/workflows/build-publish.yml/badge.svg)](https://github.com/jorgensd/dolfinx-tutorial/actions/workflows/build-publish.yml)
[![Test release branch against DOLFINx nightly build](https://github.com/jorgensd/dolfinx-tutorial/actions/workflows/nightly.yml/badge.svg)](https://github.com/jorgensd/dolfinx-tutorial/actions/workflows/nightly.yml)

Expand All @@ -8,33 +9,50 @@ This is the source code for the dolfinx-tutorial [webpage](https://jorgensd.gith
If you have any comments, corrections or questions, please submit an issue in the issue tracker.

## Contributing

If you want to contribute to this tutorial, please make a fork of the repository, make your changes, and test that the CI passes. You can do this locally by downloading [act](https://github.com/nektos/act) and call

```bash
act -j test-nightly
```

Any code added to the tutorial should work in parallel.

Alternatively, if you want to add a separate chapter, a Jupyter notebook can be added to a pull request, without integrating it into the tutorial. If so, the notebook will be reviewed and modified to be included in the tutorial.

Also ensure that both Python file and notebook files are updated by using jupytext, i.e.

```bash
python3 -m jupytext --sync */*.ipynb
```

## Dependencies

It is adviced to use a pre-installed version of DOLFINx, for instance through conda or docker. Remaining dependencies can be installed with

```bash
python3 -m pip install --no-binary=h5py -e .
```

# Docker images
Docker images for this tutorial can be found in the [packages tab](https://github.com/jorgensd/dolfinx-tutorial/pkgs/container/dolfinx-tutorial)

Docker images for this tutorial can be found in the [packages tab](https://github.com/jorgensd/dolfinx-tutorial/pkgs/container/dolfinx-tutorial)

Additional requirements on top of the `dolfinx/lab:nightly` images can be found at [Dockerfile](docker/Dockerfile) and [pyproject.toml](./pyproject.toml)

##

An image building DOLFINx, Basix, UFL and FFCx from source can be built using:

```bash
cd docker
docker build -f ./docker/Dockerfile -t local_lab_env .
```

from the root of this repository, and run

```bash
docker run --rm -ti -v $(pwd):/root/shared -w /root/shared --init -p 8888:8888 local_lab_env
```
```

from the main directory.
331 changes: 18 additions & 313 deletions chapter1/complex_mode.ipynb

Large diffs are not rendered by default.

39 changes: 26 additions & 13 deletions chapter1/complex_mode.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
# extension: .py
# format_name: light
# format_version: '1.5'
# jupytext_version: 1.14.7
# jupytext_version: 1.15.2
# kernelspec:
# display_name: Python 3 (DOLFINx complex)
# language: python
Expand All @@ -19,19 +19,19 @@
#
# Many PDEs, such as the [Helmholtz equation](https://docs.fenicsproject.org/dolfinx/v0.4.1/python/demos/demo_helmholtz.html) require complex-valued fields.
#
# For simplicity, let us consider a Poisson equation of the form:
# For simplicity, let us consider a Poisson equation of the form:
#
# $$-\Delta u = f \text{ in } \Omega,$$
# $$ f = -1 - 2j \text{ in } \Omega,$$
# $$ f = -1 - 2j \text{ in } \Omega,$$
# $$ u = u_{exact} \text{ on } \partial\Omega,$$
# $$u_{exact}(x, y) = \frac{1}{2}x^2 + 1j\cdot y^2,$$
#
# As in [Solving the Poisson equation](./fundamentals) we want to express our partial differential equation as a weak formulation.
#
# We start by defining our discrete function space $V_h$, such that $u_h\in V_h$ and $u_h = \sum_{i=1}^N c_i \phi_i(x, y)$ where $\phi_i$ are **real valued** global basis functions of our space $V_h$, $c_i \in \mathcal{C}$ are the **complex valued** degrees of freedom.
# We start by defining our discrete function space $V_h$, such that $u_h\in V_h$ and $u_h = \sum_{i=1}^N c_i \phi_i(x, y)$ where $\phi_i$ are **real valued** global basis functions of our space $V_h$, and $c_i \in \mathcal{C}$ are the **complex valued** degrees of freedom.
#
# Next, we choose a test function $v\in \hat V_h$ where $\hat V_h\subset V_h$ such that $v\vert_{\partial\Omega}=0$, as done in the first tutorial.
# We now need to define our inner product space. We choose the $L^2$ inner product spaces, which is a *[sesquilinear](https://en.wikipedia.org/wiki/Sesquilinear_form) 2-form*, Meaning that $\langle u, v\rangle$ is a map from $V_h\times V_h\mapsto K$, and $\langle u, v \rangle = \int_\Omega u \cdot \bar v ~\mathrm{d} x$. As it is sesquilinear, we have the following properties:
# Next, we choose a test function $v\in \hat V_h$ where $\hat V_h\subset V_h$ such that $v\vert_{\partial\Omega}=0$, as done in the first tutorial.
# We now need to define our inner product space. We choose the $L^2$ inner product spaces, which is a _[sesquilinear](https://en.wikipedia.org/wiki/Sesquilinear_form) 2-form_, meaning that $\langle u, v\rangle$ is a map from $V_h\times V_h\mapsto K$, and $\langle u, v \rangle = \int_\Omega u \cdot \bar v ~\mathrm{d} x$. As it is sesquilinear, we have the following properties:
#
# $$\langle u , v \rangle = \overline{\langle v, u \rangle},$$
# $$\langle u , u \rangle \geq 0.$$
Expand All @@ -41,10 +41,12 @@
# $$\int_\Omega \nabla u_h \cdot \nabla \overline{v}~ \mathrm{dx} = \int_{\Omega} f \cdot \overline{v} ~\mathrm{d} s \qquad \forall v \in \hat{V}_h.$$
#
# ## Installation of FEniCSx with complex number support
# FEniCSx supports both real and complex numbers, meaning that we can create a function spaces with real valued or complex valued coefficients.
#
# FEniCSx supports both real and complex numbers, so we can create a function space with real valued or complex valued coefficients.
#

import dolfinx
from mpi4py import MPI
import dolfinx
import numpy as np
mesh = dolfinx.mesh.create_unit_square(MPI.COMM_WORLD, 10, 10)
V = dolfinx.fem.FunctionSpace(mesh, ("Lagrange", 1))
Expand All @@ -55,19 +57,22 @@
print(u_r.x.array.dtype)
print(u_c.x.array.dtype)

# However, as we would like to solve linear algebra problems on the form $Ax=b$, we need to be able to use matrices and vectors that support real and complex numbers. As [PETSc](https://petsc.org/release/) is one of the most popular interfaces to linear algebra packages, we need to be able to work with their matrix and vector structures.
# However, as we would like to solve linear algebra problems of the form $Ax=b$, we need to be able to use matrices and vectors that support real and complex numbers. As [PETSc](https://petsc.org/release/) is one of the most popular interfaces to linear algebra packages, we need to be able to work with their matrix and vector structures.
#
# Unfortunately, PETSc only supports one floating type in their matrices, thus we need to install two versions of PETSc, one that supports `float64` and one that supports `complex128`. In the [docker images](https://hub.docker.com/r/dolfinx/dolfinx) for DOLFINx, both versions are installed, and one can switch between them by calling `source dolfinx-real-mode` or `source dolfinx-complex-mode`. For the `dolfinx/lab` images, one can change the Python kernel to be either the real or complex mode, by going to `Kernel->Change Kernel...` and choose `Python3 (ipykernel)` (for real mode) or `Python3 (DOLFINx complex)` (for complex mode).
#
# We check that we are using the correct installation of PETSc by inspecting the scalar type.
#

from petsc4py import PETSc
from dolfinx.fem.petsc import assemble_vector
print(PETSc.ScalarType)
assert np.dtype(PETSc.ScalarType).kind == 'c'

# ## Variational problem
#
# We are now ready to define our variational problem
#

import ufl
u = ufl.TrialFunction(V)
Expand All @@ -78,23 +83,27 @@

# Note that we have used the `PETSc.ScalarType` to wrap the constant source on the right hand side. This is because we want the integration kernels to assemble into the correct floating type.
#
# Secondly, note that we are using `ufl.inner` to describe multiplication of $f$ and $v$, even if they are scalar values. This is because `ufl.inner` takes the conjugate of the second argument, as decribed by the $L^2$ inner product. One could alternatively write this out manually
# Secondly, note that we are using `ufl.inner` to describe multiplication of $f$ and $v$, even if they are scalar values. This is because `ufl.inner` takes the conjugate of the second argument, as decribed by the $L^2$ inner product. One could alternatively write this out explicitly
#
# ### Inner-products and derivatives
#

L2 = f * ufl.conj(v) * ufl.dx
print(L)
print(L2)

# Similarly, if we want to use the function $ufl.derivative$ to take derivatives of functionals, we need to take some special care. As `derivative` inserts a `ufl.TestFunction` to represent the variation, we need to take the conjugate of this to be able to use it to assemble vectors.
# Similarly, if we want to use the function `ufl.derivative` to take derivatives of functionals, we need to take some special care. As `derivative` inserts a `ufl.TestFunction` to represent the variation, we need to take the conjugate of this to in order to assemble vectors.
#

J = u_c**2 * ufl.dx
F = ufl.derivative(J, u_c, ufl.conj(v))
residual = assemble_vector(dolfinx.fem.form(F))
print(residual.array)

# We define our Dirichlet condition and setup and solve the variational problem.
#
# ## Solve variational problem
#

mesh.topology.create_connectivity(mesh.topology.dim-1, mesh.topology.dim)
boundary_facets = dolfinx.mesh.exterior_facet_indices(mesh.topology)
Expand All @@ -103,8 +112,10 @@
problem = dolfinx.fem.petsc.LinearProblem(a, L, bcs=[bc])
uh = problem.solve()

# We compute the $L^2$ error and the max error
# We compute the $L^2$ error and the max error.
#
# ## Error computation
#

x = ufl.SpatialCoordinate(mesh)
u_ex = 0.5 * x[0]**2 + 1j*x[1]**2
Expand All @@ -115,7 +126,9 @@
print(global_error, max_error)

# ## Plotting
# Finally, we plot the real and imaginary solution
#
# Finally, we plot the real and imaginary solutions.
#

import pyvista
pyvista.start_xvfb()
Expand Down
2 changes: 1 addition & 1 deletion chapter1/fundamentals_code.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
# extension: .py
# format_name: light
# format_version: '1.5'
# jupytext_version: 1.14.7
# jupytext_version: 1.16.1
# kernelspec:
# display_name: Python 3 (ipykernel)
# language: python
Expand Down
584 changes: 549 additions & 35 deletions chapter1/membrane_code.ipynb

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion chapter1/membrane_code.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
# extension: .py
# format_name: light
# format_version: '1.5'
# jupytext_version: 1.14.7
# jupytext_version: 1.16.1
# kernelspec:
# display_name: Python 3 (ipykernel)
# language: python
Expand Down
2 changes: 1 addition & 1 deletion chapter1/nitsche.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
# extension: .py
# format_name: light
# format_version: '1.5'
# jupytext_version: 1.14.7
# jupytext_version: 1.16.1
# kernelspec:
# display_name: Python 3 (ipykernel)
# language: python
Expand Down
2 changes: 1 addition & 1 deletion chapter2/diffusion_code.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
# extension: .py
# format_name: light
# format_version: '1.5'
# jupytext_version: 1.14.7
# jupytext_version: 1.16.1
# kernelspec:
# display_name: Python 3 (ipykernel)
# language: python
Expand Down
2 changes: 1 addition & 1 deletion chapter2/heat_code.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
# extension: .py
# format_name: light
# format_version: '1.5'
# jupytext_version: 1.14.7
# jupytext_version: 1.16.1
# kernelspec:
# display_name: Python 3 (ipykernel)
# language: python
Expand Down
2 changes: 1 addition & 1 deletion chapter2/hyperelasticity.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
# extension: .py
# format_name: light
# format_version: '1.5'
# jupytext_version: 1.14.7
# jupytext_version: 1.16.1
# kernelspec:
# display_name: Python 3 (ipykernel)
# language: python
Expand Down
2 changes: 1 addition & 1 deletion chapter2/linearelasticity_code.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
# extension: .py
# format_name: light
# format_version: '1.5'
# jupytext_version: 1.14.7
# jupytext_version: 1.16.1
# kernelspec:
# display_name: Python 3 (ipykernel)
# language: python
Expand Down
14 changes: 7 additions & 7 deletions chapter2/nonlinpoisson_code.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"Author: Jørgen S. Dokken\n",
"\n",
"## Test problem\n",
"To solve a test problem, we need to choose the right hand side $f$ and the coefficient $q(u)$ and the boundary $u_D$. Previously, we have worked with manufactured solutions that can be reproduced without approximation errors. This is more difficult in non-linear porblems, and the algebra is more tedious. Howeve, we will utilize UFLs differentiation capabilities to obtain a manufactured solution.\n",
"To solve a test problem, we need to choose the right hand side $f$, the coefficient $q(u)$, and the boundary $u_D$. Previously, we have worked with manufactured solutions that can be reproduced without approximation errors. This is more difficult in nonlinear problems, and the algebra is more tedious. However, we will utilize the UFL differentiation capabilities to obtain a manufactured solution.\n",
"\n",
"For this problem, we will choose $q(u) = 1 + u^2$ and define a two dimensional manufactured solution that is linear in $x$ and $y$:"
]
Expand Down Expand Up @@ -44,10 +44,10 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"Note that since `x` is a 2D vector, the first component (index 0) resemble $x$, while the second component (index 1) resemble $y$. The resulting function `f` can be directly used in variational formulations in DOLFINx.\n",
"Note that since `x` is a 2D vector, the first component (index 0) represents $x$, while the second component (index 1) represents $y$. The resulting function `f` can be directly used in variational formulations in DOLFINx.\n",
"\n",
"As we now have defined our source term and exact solution, we can create the appropriate function space and boundary conditions.\n",
"Note that as we have already defined the exact solution, we only have to convert it to a python function that can be evaluated in the interpolation function. We do this by employing the Python `eval` and `lambda`-functions."
"As we now have defined our source term and an exact solution, we can create the appropriate function space and boundary conditions.\n",
"Note that as we have already defined the exact solution, we only have to convert it to a Python function that can be evaluated in the interpolation function. We do this by employing the Python `eval` and `lambda`-functions."
]
},
{
Expand Down Expand Up @@ -77,7 +77,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"We are now ready to define the variational formulation. Note that as the problem is non-linear, we have replace the `TrialFunction` with a `Function`, which serves as the unknown of our problem."
"We are now ready to define the variational formulation. Note that as the problem is nonlinear, we have to replace the `TrialFunction` with a `Function`, which serves as the unknown of our problem."
]
},
{
Expand Down Expand Up @@ -114,7 +114,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"Next, we use the dolfinx Newton solver. We can set the convergence criterions for the solver by changing the absolute tolerance (`atol`), relative tolerance (`rtol`) or the convergence criterion (`residual` or `incremental`)."
"Next, we use the DOLFINx Newton solver. We can set the convergence criteria for the solver by changing the absolute tolerance (`atol`), relative tolerance (`rtol`) or the convergence criterion (`residual` or `incremental`)."
]
},
{
Expand Down Expand Up @@ -213,7 +213,7 @@
"metadata": {},
"source": [
"We observe that the solver converges after $8$ iterations.\n",
"If we think of the problem in terms of finite differences on a uniform mesh, $\\mathcal{P}_1$ elements mimic standard second-order finite differences, which compute the derivative of a linear or quadratic funtion exactly. Here $\\nabla u$ is a constant vector, which is multiplied by $1+u^2$, which is a second order polynomial in $x$ and $y$, which the finite difference operator would compute exactly. We can therefore, even with $\\mathcal{P}_1$ elements, expect the manufactured solution to be reproduced by the numerical method. However, if we had chosen a nonlinearity, such as $1+u^4$, this would not be the case, and we would need to verify convergence rates."
"If we think of the problem in terms of finite differences on a uniform mesh, $\\mathcal{P}_1$ elements mimic standard second-order finite differences, which compute the derivative of a linear or quadratic funtion exactly. Here $\\nabla u$ is a constant vector, which is multiplied by $1+u^2$, giving a second order polynomial in $x$ and $y$, which the finite difference operator would compute exactly. We can therefore, even with $\\mathcal{P}_1$ elements, expect the manufactured solution to be reproduced by the numerical method. However, if we had chosen a nonlinearity, such as $1+u^4$, this would not be the case, and we would need to verify convergence rates."
]
},
{
Expand Down
Loading