Skip to content

Dokken/bump release #249

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 5 commits into from
Feb 4, 2025
Merged
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
96 changes: 73 additions & 23 deletions .github/workflows/publish_docker.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
name: Publish tutorial docker image
# Recipe based on: https://docs.docker.com/build/ci/github-actions/multi-platform/#distribute-build-across-multiple-runners
name: Build and publish platform dependent docker image
on:
push:
branches:
Expand All @@ -15,8 +16,12 @@ env:
IMAGE_NAME: ${{ github.repository }}

jobs:
build-and-push-image:
runs-on: ubuntu-latest
build:
strategy:
matrix:
os: ["ubuntu-24.04", "ubuntu-24.04-arm"]
runs-on: ${{ matrix.os }}

permissions:
contents: read
packages: write
Expand All @@ -25,43 +30,88 @@ jobs:
- name: Checkout repository
uses: actions/checkout@v4

- name: Set up QEMU
uses: docker/setup-qemu-action@v3

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Log in to the Container registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}

- name: Build Docker image
- name: Set architecture tag (amd64)
if: ${{ matrix.os == 'ubuntu-24.04' }}
run: echo "ARCH_TAG=amd64" >> $GITHUB_ENV

- name: Set architecture tag (arm)
if: ${{ contains(matrix.os, 'arm') }}
run: echo "ARCH_TAG=arm64" >> $GITHUB_ENV

- name: Build and push by digest
id: build
uses: docker/build-push-action@v6
with:
context: .
load: true
push: false
file: docker/Dockerfile
platforms: linux/amd64
tags: ${{ steps.meta.outputs.tags }}
platforms: ${{ env.ARCH_TAG }}
labels: ${{ steps.meta.outputs.labels }}
outputs: type=image,"name=${{ env.REGISTRY }}/${{ env.IMAGE_NAME}}",push-by-digest=true,name-canonical=true,push=true

- name: Build (arm) and push (amd/arm) Docker image
uses: docker/build-push-action@v6
- name: Export digest
run: |
mkdir -p ${{ runner.temp }}/digests
digest="${{ steps.build.outputs.digest }}"
touch "${{ runner.temp }}/digests/${digest#sha256:}"

- name: Upload digest
if: github.event_name == 'push'
uses: actions/upload-artifact@v4
with:
context: .
push: true
file: docker/Dockerfile
platforms: linux/amd64,linux/arm64
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
name: digests-${{ env.ARCH_TAG }}
path: ${{ runner.temp }}/digests/*
if-no-files-found: error
retention-days: 1

merge-and-publish:
if: github.event_name == 'push'
runs-on: ubuntu-latest
needs:
- build
steps:
- name: Download digests
uses: actions/download-artifact@v4
with:
path: ${{ runner.temp }}/digests
pattern: digests-*
merge-multiple: true

- name: Log in to the Container registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}


- name: Create manifest list and push
working-directory: ${{ runner.temp }}/digests
run: |
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
$(printf '${{ env.REGISTRY }}/${{ env.IMAGE_NAME}}@sha256:%s ' *)

- name: Inspect image
run: |
docker buildx imagetools inspect ${{ env.REGISTRY }}/${{ env.IMAGE_NAME}}:${{ steps.meta.outputs.version }}

6 changes: 5 additions & 1 deletion _toc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ parts:
- file: chapter2/ns_code1
- file: chapter2/ns_code2
- file: chapter2/hyperelasticity
- file: chapter2/helmholtz
sections:
- file: chapter2/helmholtz_code

- caption: Subdomains and boundary conditions
chapters:
- file: chapter3/neumann_dirichlet_code
Expand All @@ -48,4 +52,4 @@ parts:
- file: chapter4/solvers
- file: chapter4/compiler_parameters
- file: chapter4/convergence
- file: chapter4/newton-solver
- file: chapter4/newton-solver
4 changes: 2 additions & 2 deletions chapter2/elasticity_scaling.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,6 @@ where $\beta = 1+\frac{\lambda}{\mu}$ is a dimensionless elasticity parameter an
```
is a dimensionless variable reflecting the ratio of the load $\rho g$ and the shear stress term $\mu \nabla^2u \sim \mu \frac{U}{L^2}$ in the PDE.

One option for the scaling is to chose $U$ such that $\gamma$ is of unit size ($U=\frac{\rho g L^2}{\mu}$). However, in elasticity, this leads to displacements of the size of the geometry. This can be achieved by choosing $U$ equal to the maximum deflection of a clamped beam, for which there actually exists a formula: $U=\frac{3}{2} \rho g L^2\frac{\delta^2}{E}$ where $\delta=\frac{L}{W}$ is a parameter reflecting how slender the beam is, and $E$ is the modulus of elasticity. Thus the dimensionless parameter $\delta$ is very important in the problem (as expected $\delta\gg 1$ is what gives beam theory!). Taking $E$ to be of the same order as $\mu$, which in this case and for many materials, we realize that $\gamma \sim \delta^{-2}$ is an appropriate choice. Experimenting with the code to find a displacement that "looks right" in the plots of the deformed geometry, points to $\gamma=0.4\delta^{-2}$ as our final choice of $\gamma$.
One option for the scaling is to choose $U$ such that $\gamma$ is of unit size ($U=\frac{\rho g L^2}{\mu}$). However, in elasticity, this leads to displacements of the size of the geometry. This can be achieved by choosing $U$ equal to the maximum deflection of a clamped beam, for which there actually exists a formula: $U=\frac{3}{2} \rho g L^2\frac{\delta^2}{E}$ where $\delta=\frac{L}{W}$ is a parameter reflecting how slender the beam is, and $E$ is the modulus of elasticity. Thus the dimensionless parameter $\delta$ is very important in the problem (as expected $\delta\gg 1$ is what gives beam theory!). Taking $E$ to be of the same order as $\mu$, which in this case and for many materials, we realize that $\gamma \sim \delta^{-2}$ is an appropriate choice. Experimenting with the code to find a displacement that "looks right" in the plots of the deformed geometry, points to $\gamma=0.4\delta^{-2}$ as our final choice of $\gamma$.

The simulation code implements the problem with dimensions and physical parameters $\lambda, \mu, \rho, g, L$ and $W$. However, we can easily reuse this code for a scaled problem: Just set $\mu=\rho=L=1$, $W$ as $W/L(\delta^{-1})$, $g=\gamma$ and $\lambda=\beta$.
The simulation code implements the problem with dimensions and physical parameters $\lambda, \mu, \rho, g, L$ and $W$. However, we can easily reuse this code for a scaled problem: Just set $\mu=\rho=L=1$, $W$ as $W/L(\delta^{-1})$, $g=\gamma$ and $\lambda=\beta$.
125 changes: 125 additions & 0 deletions chapter2/helmholtz.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
# The Helmholtz equation
Author: Antonio Baiano Svizzero

The study of computational acoustics is fundamental in fields such as noise, vibration, and harshness (NVH), noise control, and acoustic design. In this chapter, we focus on the theoretical foundations of the Helmholtz equation - valid for noise problems with harmonic time dependency - and its implementation in FEniCSx to compute the sound pressure for any acoustic system.

## The PDE problem
The acoustic Helmholtz equation in its general form reads

$$
\begin{align}
\nabla^2 p + k^2 p = -j \omega \rho_0 q \qquad\text{in } \Omega,
\end{align}
$$

where $k$ is the acoustic wavenumber, $\omega$ is the angular frequency, $j$ the imaginary unit and $q$ is the volume velocity ($m^3/s$) of a generic source field.
In case of a monopole source, we can write $q=Q \delta(x_s,y_s,z_s)$, where $\delta(x_s,y_s,z_s)$ is the 3D Dirac Delta centered at the monopole location.

This equation is coupled with the following boundary conditions:

- Dirichlet BC:

$$
\begin{align}
p = \bar{p} \qquad \text{on } \partial\Omega_p,
\end{align}
$$

- Neumann BC:

$$
\begin{align}
\frac{\partial p}{\partial n} = - j \omega \rho_0 \bar{v}_n\qquad \text{on } \partial\Omega_v,
\end{align}
$$

- Robin BC:

$$
\begin{align}
\frac{\partial p}{\partial n} = - \frac{j \omega \rho_0 }{\bar{Z}} p \qquad \text{on } \partial\Omega_Z,
\end{align}
$$

where we prescribe, respectively, an acoustic pressure $\bar{p}$ on the boundary $\partial\Omega_p$,
a sound particle velocity $\bar{v}_n$ on the boundary $\partial\Omega_v$ and
an acoustic impedance $\bar{Z}$ on the boundary $\partial\Omega_Z$ where $n$ is the outward normal.
In general, any BC can also be frequency dependant, as it happens in real-world applications.

## The variational formulation
Now we have to turn the equation in its weak formulation.
The first step is to multiplicate the equation by a *test function* $v\in \hat V$,
where $\hat V$ is the *test function space*, after which we integrate over the whole domain, $\Omega$:

$$
\begin{align}
\int_{\Omega}\left(\nabla^2 p + k^2 p \right) \bar v ~\mathrm{d}x = -\int_{\Omega} j \omega \rho_0 q \bar v ~\mathrm{d}x.
\end{align}
$$

Here, the unknown function $p$ is referred to as *trial function* and the $\bar{\cdot}$ is the complex conjugate operator.

In order to keep the order of derivatives as low as possible, we use integration by parts on the Laplacian term:

$$
\begin{align}
\int_{\Omega}(\nabla^2 p) \bar v ~\mathrm{d}x =
-\int_{\Omega} \nabla p \cdot \nabla \bar v ~\mathrm{d}x
+ \int_{\partial \Omega} \frac{\partial p}{\partial n} \bar v ~\mathrm{d}s.
\end{align}
$$

Substituting in the original version and rearranging we get:

$$
\begin{align}
\int_{\Omega} \nabla p \cdot \nabla \bar v ~\mathrm{d}x
- k^2 \int_{\Omega} p \bar v ~\mathrm{d} x = \int_{\Omega} j \omega \rho_0 q \bar v ~\mathrm{d}x
+ \int_{\partial \Omega} \frac{\partial p}{\partial n} \bar v ~\mathrm{d}s.
\end{align}
$$

Since we are dealing with complex values, the inner product in the first equation is *sesquilinear*,
meaning it is linear in one argument and conjugate-linear in the other,
as explained in [The Poisson problem with complex numbers](../chapter1/complex_mode).

The last term can be written using the Neumann and Robin BCs, that is:

$$
\begin{align}
\int_{\partial \Omega} \frac{\partial p}{\partial n} \bar v ~\mathrm{d}s =
-\int_{\partial \Omega_v} j \omega \rho_0 \bar v ~\mathrm{d}s
- \int_{\partial \Omega_Z} \frac{j \omega \rho_0 \bar{v}_n}{\bar{Z}} p \bar v ~\mathrm{d}s.
\end{align}
$$

Substituting, rearranging and taking out of integrals the terms with $j$ and $\omega$ we get the variational formulation of the Helmholtz.
Find $u \in V$ such that:

$$
\begin{align}
\int_{\Omega} \nabla p \cdot \nabla \bar v ~\mathrm{d}x
+ \frac{j \omega }{\bar{Z}} \int_{\partial \Omega_Z} \rho_0 p \bar v ~\mathrm{d}s
- k^2 \int_{\Omega} p \bar v ~\mathrm{d}x
= j \omega \int_{\Omega} \rho_0 q \bar v ~\mathrm{d}x
-j \omega\int_{\partial \Omega_v} \rho_0 \bar{v}_n \bar v ~\mathrm{d}s \qquad \forall v \in \hat{V}.
\end{align}
$$

We define the sesquilinear form $a(p,v)$ is

$$
\begin{align}
a(p,v) = \int_{\Omega} \nabla p \cdot \nabla \bar v ~\mathrm{d}x
+ \frac{j \omega }{\bar{Z}} \int_{\partial \Omega_Z} \rho_0 p \bar v ~\mathrm{d}s,
- k^2 \int_{\Omega} p \bar v ~\mathrm{d}x
\end{align}
$$

and the linear form $L(v)$ reads

$$
\begin{align}
L(v) = j \omega \int_{\Omega}\rho_0 q \bar v ~\mathrm{d}x - j \omega \int_{\partial \Omega_v} \rho_0 \bar{v}_n \bar v ~\mathrm{d}s.
\end{align}
$$
Loading