Skip to content
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

Non cartesian cases for simple diffusion and the soret effect #74

Draft
wants to merge 10 commits into
base: main
Choose a base branch
from
2 changes: 1 addition & 1 deletion environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,4 @@ dependencies:
- scipy
- pip
- pip:
- festim==1.3
- festim~=1.3
6 changes: 5 additions & 1 deletion report/_toc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ parts:
- file: verification/mms/simple
- file: verification/mms/simple_transient
- file: verification/mms/simple_temperature
- file: verification/mms/simple_cylindrical
- file: verification/mms/fluxes
- file: verification/mms/heat_transfer
- file: verification/mms/discontinuity
Expand All @@ -25,7 +26,10 @@ parts:
sections:
- file: verification/mes/radioactive_decay
- file: verification/mms/radioactive_decay
- file: verification/mms/soret
- file: verification/soret
sections:
- file: verification/mms/soret
- file: verification/mms/soret_cylindrical
- file: verification/tmap
sections:
- file: verification/mes/depleting_source
Expand Down
232 changes: 232 additions & 0 deletions report/verification/mms/simple_cylindrical.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,232 @@
---
jupytext:
formats: ipynb,md:myst
text_representation:
extension: .md
format_name: myst
format_version: 0.13
jupytext_version: 1.16.4
kernelspec:
display_name: vv-festim-report-env
language: python
name: python3
---

# Simple cylindrical case

```{tags} 2D, MMS, steady state, cylindrical
```

This is a simple MMS example on a cylindrical mesh.
We will only consider diffusion of hydrogen in a unit square domain $\Omega$ s.t. $r \in [1, 2]$ and $z \in [0, 1]$ at steady state with a homogeneous diffusion coefficient $D$.
Moreover, a Dirichlet boundary condition will be assumed on the boundaries $\partial \Omega $.

The problem is therefore:

$$
\begin{align}
& \nabla \cdot (D \ \nabla{c}) = -S \quad \text{on } \Omega \\
& c = c_0 \quad \text{on } \partial \Omega
\end{align}
$$(problem_simple_cylindrical)

The exact solution for mobile concentration is:

$$
\begin{equation}
c_\mathrm{exact} = 1 + r^2
\end{equation}
$$(c_exact_simple_cylindrical)

Injecting {eq}`c_exact_simple_cylindrical` in {eq}`problem_simple_cylindrical`, we obtain the expressions of $S$ and $c_0$:

$$
\begin{align}
& S = -4D \\
& c_0 = c_\mathrm{exact}
\end{align}
$$

We can then run a FESTIM model with these values and compare the numerical solution with $c_\mathrm{exact}$.

+++

## FESTIM code

```{code-cell} ipython3
import festim as F
import sympy as sp
import fenics as f
import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np

# Create and mark the mesh
nx = ny = 100
fenics_mesh = f.RectangleMesh(f.Point(1, 0), f.Point(2, 1), nx, ny)

volume_markers = f.MeshFunction("size_t", fenics_mesh, fenics_mesh.topology().dim())
volume_markers.set_all(1)

surface_markers = f.MeshFunction(
"size_t", fenics_mesh, fenics_mesh.topology().dim() - 1
)
surface_markers.set_all(0)

class Boundary(f.SubDomain):
def inside(self, x, on_boundary):
return on_boundary


boundary = Boundary()
boundary.mark(surface_markers, 1)

r = F.x
exact_solution = 1 + r**2
D = 2


def run_model(type: str):

# Create the FESTIM model
my_model = F.Simulation()

my_model.mesh = F.Mesh(
fenics_mesh,
volume_markers=volume_markers,
surface_markers=surface_markers,
type=type,
)

my_model.sources = [
F.Source(-4 * D, volume=1, field="solute"),
]

my_model.boundary_conditions = [
F.DirichletBC(surfaces=[1], value=exact_solution, field="solute"),
]

my_model.materials = F.Material(id=1, D_0=D, E_D=0)

my_model.T = F.Temperature(500) # ignored in this problem

my_model.settings = F.Settings(
absolute_tolerance=1e-10,
relative_tolerance=1e-10,
transient=False,
)

my_model.initialise()
my_model.run()

return my_model.h_transport_problem.mobile.post_processing_solution
```

## Comparison with exact solution

```{code-cell} ipython3
:tags: [hide-input]

c_exact = f.Expression(sp.printing.ccode(exact_solution), degree=4)
c_exact = f.project(c_exact, f.FunctionSpace(fenics_mesh, "CG", 1))

cylindrical_solution = run_model("cylindrical")

E_cyl = f.errornorm(cylindrical_solution, c_exact, "L2")
print(f"L2 error, cylindrical: {E_cyl:.2e}")

# plot exact solution and computed solution
fig, axs = plt.subplots(
1,
3,
figsize=(15, 5),
)

plt.sca(axs[0])
plt.title("Exact solution")
plt.xlabel("r")
plt.ylabel("z")
CS1 = f.plot(c_exact, cmap="inferno")
plt.sca(axs[1])
plt.xlabel("r")
plt.title("Cylindrical solution")
CS2 = f.plot(cylindrical_solution, cmap="inferno")

plt.colorbar(CS1, ax=[axs[0]], shrink=0.8)
plt.colorbar(CS2, ax=[axs[1]], shrink=0.8)

# axs[0].sharey(axs[1])
plt.setp(axs[1].get_yticklabels(), visible=False)
plt.setp(axs[2].get_yticklabels(), visible=False)

for CS in [CS1, CS2]:
CS.set_edgecolor("face")


def compute_arc_length(xs, ys):
"""Computes the arc length of x,y points based
on x and y arrays
"""
points = np.vstack((xs, ys)).T
distance = np.linalg.norm(points[1:] - points[:-1], axis=1)
arc_length = np.insert(np.cumsum(distance), 0, [0.0])
return arc_length


# define the profiles
profiles = [
{"start": (1.0, 0.0), "end": (2.0, 1.0)},
{"start": (1.2, 0.8), "end": (1.7, 0.2)},
{"start": (1.2, 0.6), "end": (1.8, 0.8)},
]

# plot the profiles on the right subplot
for i, profile in enumerate(profiles):
start_x, start_y = profile["start"]
end_x, end_y = profile["end"]
plt.sca(axs[1])
(l,) = plt.plot([start_x, end_x], [start_y, end_y])

plt.sca(axs[-1])

points_x_exact = np.linspace(start_x, end_x, num=30)
points_y_exact = np.linspace(start_y, end_y, num=30)
arc_length_exact = compute_arc_length(points_x_exact, points_y_exact)
u_values = [c_exact(x, y) for x, y in zip(points_x_exact, points_y_exact)]

points_x = np.linspace(start_x, end_x, num=100)
points_y = np.linspace(start_y, end_y, num=100)
arc_lengths = compute_arc_length(points_x, points_y)
computed_values = [cylindrical_solution(x, y) for x, y in zip(points_x, points_y)]

(exact_line,) = plt.plot(
arc_length_exact,
u_values,
color=l.get_color(),
marker="o",
linestyle="None",
alpha=0.3,
)
(computed_line,) = plt.plot(arc_lengths, computed_values, color=l.get_color())

plt.sca(axs[-1])
plt.xlabel("Arc length")
plt.ylabel("Solution")

legend_marker = mpl.lines.Line2D(
[],
[],
color="black",
marker=exact_line.get_marker(),
linestyle="None",
label="Exact",
)
legend_line = mpl.lines.Line2D([], [], color="black", label="Computed")
plt.legend(
[legend_marker, legend_line], [legend_marker.get_label(), legend_line.get_label()]
)

plt.grid(alpha=0.3)
plt.gca().spines[["right", "top"]].set_visible(False)
plt.show()
```
3 changes: 1 addition & 2 deletions report/verification/mms/soret.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ kernelspec:

# Soret Effect

```{tags} 2D, MMS, soret, steady state
```{tags} 2D, MMS, steady state, soret
```

This MMS case verifies the implementation of the Soret effect in FESTIM.
Expand Down Expand Up @@ -47,7 +47,6 @@ For this problem, we choose:
& D = 2
\end{align}


Injecting {eq}`c_exact_soret` in {eq}`problem_soret`, we obtain the expressions of $S$ and $c_0$:

$$
Expand Down
Loading