Troubleshooting#

Log level#

Sometimes, a FESTIM model produces strange results, either because it doesn’t converge or it converges “too quickly”.

The first step to resolve these issues is to change the log level, which is the amount of information displayed by the solver.

Let’s make a simple problem as an example:

import festim as F
import numpy as np
from dolfinx.mesh import create_unit_square
from mpi4py import MPI

my_model = F.HydrogenTransportProblem()

fenics_mesh = create_unit_square(MPI.COMM_WORLD, 10, 10)
my_model.mesh = F.Mesh(fenics_mesh)

material_top = F.Material(D_0=1, E_D=0)
material_bot = F.Material(D_0=2, E_D=0)


top_volume = F.VolumeSubdomain(id=1, material=material_top, locator=lambda x: x[1] >= 0.5)
bottom_volume = F.VolumeSubdomain(id=2, material=material_bot, locator=lambda x: x[1] <= 0.5)

top_surface = F.SurfaceSubdomain(id=1, locator=lambda x: np.isclose(x[1], 1.0))
bottom_surface = F.SurfaceSubdomain(id=2, locator=lambda x: np.isclose(x[1], 0.0))

my_model.subdomains = [top_surface, bottom_surface, top_volume, bottom_volume]

H = F.Species("H")
my_model.species = [H]

my_model.temperature = 400

my_model.boundary_conditions = [
    F.FixedConcentrationBC(subdomain=top_surface, value=1.0, species=H),
    F.FixedConcentrationBC(subdomain=bottom_surface, value=0.0, species=H),
]

my_model.exports = [
    F.TotalVolume(field=H, volume=top_volume),
    F.TotalVolume(field=H, volume=bottom_volume),
]

my_model.settings = F.Settings(atol=1e-1, rtol=1e-10, transient=True, final_time=3, stepsize=0.05)

my_model.initialise()
my_model.run()
/home/docs/checkouts/readthedocs.org/user_builds/festim-workshop/conda/latest/lib/python3.12/site-packages/festim/coupled_heat_hydrogen_problem.py:1: TqdmExperimentalWarning: Using `tqdm.autonotebook.tqdm` in notebook mode. Use `tqdm.tqdm` instead to force console mode (e.g. in jupyter console)
  import tqdm.autonotebook

By default, the solver doesn’t show anything but the progres bar.

Let’s plot the inventory values:

import matplotlib.pyplot as plt

for i, export in enumerate(my_model.exports):
    plt.plot(export.t, export.data, label=f"Export {i}")
plt.xlabel("Time")
plt.ylabel("Inventory")
plt.legend()
plt.show()
../../_images/36b25219bc488bdb29a9066592f8dc8408269b40a77f974fc9c13feb7f29e142.png

Does this look right to you? The values abruptly stop varying after a few iterations!

We can also inspect the data attribute of the export object:

my_model.exports[0].data
[0.1978318948484268,
 0.26323565775171764,
 0.2948396919548619,
 0.31158398221726025,
 0.31158398221726025,
 0.31158398221726025,
 0.31158398221726025,
 0.31158398221726025,
 0.31158398221726025,
 0.31158398221726025,
 0.31158398221726025,
 0.31158398221726025,
 0.31158398221726025,
 0.31158398221726025,
 0.31158398221726025,
 0.31158398221726025,
 0.31158398221726025,
 0.31158398221726025,
 0.31158398221726025,
 0.31158398221726025,
 0.31158398221726025,
 0.31158398221726025,
 0.31158398221726025,
 0.31158398221726025,
 0.31158398221726025,
 0.31158398221726025,
 0.31158398221726025,
 0.31158398221726025,
 0.31158398221726025,
 0.31158398221726025,
 0.31158398221726025,
 0.31158398221726025,
 0.31158398221726025,
 0.31158398221726025,
 0.31158398221726025,
 0.31158398221726025,
 0.31158398221726025,
 0.31158398221726025,
 0.31158398221726025,
 0.31158398221726025,
 0.31158398221726025,
 0.31158398221726025,
 0.31158398221726025,
 0.31158398221726025,
 0.31158398221726025,
 0.31158398221726025,
 0.31158398221726025,
 0.31158398221726025,
 0.31158398221726025,
 0.31158398221726025,
 0.31158398221726025,
 0.31158398221726025,
 0.31158398221726025,
 0.31158398221726025,
 0.31158398221726025,
 0.31158398221726025,
 0.31158398221726025,
 0.31158398221726025,
 0.31158398221726025,
 0.31158398221726025,
 0.31158398221726025]

To better understand what is going on, let’s turn the log level to INFO to display more information. We use the dolfinx.log module:

from dolfinx.log import set_log_level, LogLevel
set_log_level(LogLevel.INFO)

And run the model again:

my_model.initialise()
my_model.run()
[2026-05-22 15:23:13.738] [info] Checking required entities per dimension
[2026-05-22 15:23:13.738] [info] Cell type: 0 dofmap: 200x3
[2026-05-22 15:23:13.738] [info] Global index computation
[2026-05-22 15:23:13.738] [info] Got 1 index_maps
[2026-05-22 15:23:13.738] [info] Get global indices
[2026-05-22 15:23:13.738] [info] Checking required entities per dimension
[2026-05-22 15:23:13.738] [info] Cell type: 0 dofmap: 200x1
[2026-05-22 15:23:13.738] [info] Global index computation
[2026-05-22 15:23:13.738] [info] Got 1 index_maps
[2026-05-22 15:23:13.738] [info] Get global indices
[2026-05-22 15:23:13.738] [info] Checking required entities per dimension
[2026-05-22 15:23:13.738] [info] Cell type: 0 dofmap: 200x3
[2026-05-22 15:23:13.738] [info] Global index computation
[2026-05-22 15:23:13.738] [info] Got 1 index_maps
[2026-05-22 15:23:13.738] [info] Get global indices
[2026-05-22 15:23:13.744] [info] Column ghost size increased from 0 to 0
[2026-05-22 15:23:13.750] [info] SNES iter=0 ; rnorm=4.45840e+00 (atol=0.1) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:13.752] [info] SNES iter=1 ; rnorm=1.91059e-15 (atol=0.1) ; relative_residual=4.28537e-16 (rtol=1e-10) ; stepsize_rel=1.00000e+00 (stol=1.49012e-10)
[2026-05-22 15:23:13.755] [info] SNES iter=0 ; rnorm=5.18958e-01 (atol=0.1) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:13.761] [info] SNES iter=1 ; rnorm=1.46501e-15 (atol=0.1) ; relative_residual=2.82299e-15 (rtol=1e-10) ; stepsize_rel=1.39286e-01 (stol=1.49012e-10)
[2026-05-22 15:23:13.763] [info] SNES iter=0 ; rnorm=1.97512e-01 (atol=0.1) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:13.765] [info] SNES iter=1 ; rnorm=9.77483e-16 (atol=0.1) ; relative_residual=4.94898e-15 (rtol=1e-10) ; stepsize_rel=6.96799e-02 (stol=1.49012e-10)
[2026-05-22 15:23:13.767] [info] SNES iter=0 ; rnorm=1.05477e-01 (atol=0.1) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:13.769] [info] SNES iter=1 ; rnorm=9.57793e-16 (atol=0.1) ; relative_residual=9.08059e-15 (rtol=1e-10) ; stepsize_rel=3.83873e-02 (stol=1.49012e-10)
[2026-05-22 15:23:13.771] [info] SNES iter=0 ; rnorm=6.01163e-02 (atol=0.1) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:13.773] [info] SNES iter=0 ; rnorm=6.01163e-02 (atol=0.1) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:13.775] [info] SNES iter=0 ; rnorm=6.01163e-02 (atol=0.1) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:13.777] [info] SNES iter=0 ; rnorm=6.01163e-02 (atol=0.1) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:13.779] [info] SNES iter=0 ; rnorm=6.01163e-02 (atol=0.1) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:13.781] [info] SNES iter=0 ; rnorm=6.01163e-02 (atol=0.1) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:13.783] [info] SNES iter=0 ; rnorm=6.01163e-02 (atol=0.1) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:13.785] [info] SNES iter=0 ; rnorm=6.01163e-02 (atol=0.1) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:13.788] [info] SNES iter=0 ; rnorm=6.01163e-02 (atol=0.1) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:13.790] [info] SNES iter=0 ; rnorm=6.01163e-02 (atol=0.1) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:13.792] [info] SNES iter=0 ; rnorm=6.01163e-02 (atol=0.1) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:13.794] [info] SNES iter=0 ; rnorm=6.01163e-02 (atol=0.1) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:13.796] [info] SNES iter=0 ; rnorm=6.01163e-02 (atol=0.1) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:13.798] [info] SNES iter=0 ; rnorm=6.01163e-02 (atol=0.1) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:13.800] [info] SNES iter=0 ; rnorm=6.01163e-02 (atol=0.1) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:13.802] [info] SNES iter=0 ; rnorm=6.01163e-02 (atol=0.1) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:13.804] [info] SNES iter=0 ; rnorm=6.01163e-02 (atol=0.1) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:13.806] [info] SNES iter=0 ; rnorm=6.01163e-02 (atol=0.1) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:13.808] [info] SNES iter=0 ; rnorm=6.01163e-02 (atol=0.1) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:13.810] [info] SNES iter=0 ; rnorm=6.01163e-02 (atol=0.1) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:13.812] [info] SNES iter=0 ; rnorm=6.01163e-02 (atol=0.1) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:13.814] [info] SNES iter=0 ; rnorm=6.01163e-02 (atol=0.1) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:13.816] [info] SNES iter=0 ; rnorm=6.01163e-02 (atol=0.1) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:13.818] [info] SNES iter=0 ; rnorm=6.01163e-02 (atol=0.1) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:13.821] [info] SNES iter=0 ; rnorm=6.01163e-02 (atol=0.1) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:13.823] [info] SNES iter=0 ; rnorm=6.01163e-02 (atol=0.1) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:13.825] [info] SNES iter=0 ; rnorm=6.01163e-02 (atol=0.1) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:13.827] [info] SNES iter=0 ; rnorm=6.01163e-02 (atol=0.1) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:13.829] [info] SNES iter=0 ; rnorm=6.01163e-02 (atol=0.1) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:13.831] [info] SNES iter=0 ; rnorm=6.01163e-02 (atol=0.1) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:13.833] [info] SNES iter=0 ; rnorm=6.01163e-02 (atol=0.1) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:13.835] [info] SNES iter=0 ; rnorm=6.01163e-02 (atol=0.1) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:13.837] [info] SNES iter=0 ; rnorm=6.01163e-02 (atol=0.1) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:13.839] [info] SNES iter=0 ; rnorm=6.01163e-02 (atol=0.1) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:13.841] [info] SNES iter=0 ; rnorm=6.01163e-02 (atol=0.1) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:13.843] [info] SNES iter=0 ; rnorm=6.01163e-02 (atol=0.1) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:13.846] [info] SNES iter=0 ; rnorm=6.01163e-02 (atol=0.1) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:13.849] [info] SNES iter=0 ; rnorm=6.01163e-02 (atol=0.1) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:13.852] [info] SNES iter=0 ; rnorm=6.01163e-02 (atol=0.1) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:13.854] [info] SNES iter=0 ; rnorm=6.01163e-02 (atol=0.1) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:13.856] [info] SNES iter=0 ; rnorm=6.01163e-02 (atol=0.1) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:13.858] [info] SNES iter=0 ; rnorm=6.01163e-02 (atol=0.1) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:13.860] [info] SNES iter=0 ; rnorm=6.01163e-02 (atol=0.1) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:13.862] [info] SNES iter=0 ; rnorm=6.01163e-02 (atol=0.1) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:13.864] [info] SNES iter=0 ; rnorm=6.01163e-02 (atol=0.1) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:13.866] [info] SNES iter=0 ; rnorm=6.01163e-02 (atol=0.1) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:13.868] [info] SNES iter=0 ; rnorm=6.01163e-02 (atol=0.1) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:13.870] [info] SNES iter=0 ; rnorm=6.01163e-02 (atol=0.1) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:13.872] [info] SNES iter=0 ; rnorm=6.01163e-02 (atol=0.1) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:13.874] [info] SNES iter=0 ; rnorm=6.01163e-02 (atol=0.1) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:13.876] [info] SNES iter=0 ; rnorm=6.01163e-02 (atol=0.1) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:13.878] [info] SNES iter=0 ; rnorm=6.01163e-02 (atol=0.1) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:13.881] [info] SNES iter=0 ; rnorm=6.01163e-02 (atol=0.1) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:13.883] [info] SNES iter=0 ; rnorm=6.01163e-02 (atol=0.1) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:13.885] [info] SNES iter=0 ; rnorm=6.01163e-02 (atol=0.1) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:13.887] [info] SNES iter=0 ; rnorm=6.01163e-02 (atol=0.1) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:13.889] [info] SNES iter=0 ; rnorm=6.01163e-02 (atol=0.1) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)

Now we see a many more things, including some dolfinx operations during the pre-processing, but more importantly the SNES solver monitoring.

At each timestep, we have the evolution of the different norms and residuals and their associated tolerances for each Newton iteration.

Now going back to the original problem.

At the beginning of the simulation, the solver converges in two Newton iterations.

[info] SNES iter=0 ; rnorm=4.45840e+00 (atol=0.1) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[info] SNES iter=1 ; rnorm=2.06591e-15 (atol=0.1) ; relative_residual=4.63373e-16 (rtol=1e-10) ; stepsize_rel=1.00000e+00 (stol=1.49012e-10)

Note

At the 0th iteration, the relative residual and relative stepsize increase are infinity.

And then, after a couple of timesteps, the solver starts converging in zero iteration.

[info] SNES iter=0 ; rnorm=6.01163e-02 (atol=0.1) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)

This happens because the residual’s absolute norm rnorm is about 1e-2 which is already below the absolute tolerance atol of 0.1 (which we voluntarily set to a high value for illustration purposes). This typically happens when the system has reached steady state. But here, the system clearly hasn’t reached steady state yet.

Let’s lower the absolute tolerance and run the simulation again!

my_model.settings.atol = 1e-10

my_model.initialise()
my_model.run()
[2026-05-22 15:23:13.897] [info] Checking required entities per dimension
[2026-05-22 15:23:13.897] [info] Cell type: 0 dofmap: 200x3
[2026-05-22 15:23:13.897] [info] Global index computation
[2026-05-22 15:23:13.897] [info] Got 1 index_maps
[2026-05-22 15:23:13.897] [info] Get global indices
[2026-05-22 15:23:13.897] [info] Checking required entities per dimension
[2026-05-22 15:23:13.897] [info] Cell type: 0 dofmap: 200x1
[2026-05-22 15:23:13.897] [info] Global index computation
[2026-05-22 15:23:13.897] [info] Got 1 index_maps
[2026-05-22 15:23:13.897] [info] Get global indices
[2026-05-22 15:23:13.898] [info] Checking required entities per dimension
[2026-05-22 15:23:13.898] [info] Cell type: 0 dofmap: 200x3
[2026-05-22 15:23:13.898] [info] Global index computation
[2026-05-22 15:23:13.898] [info] Got 1 index_maps
[2026-05-22 15:23:13.898] [info] Get global indices
[2026-05-22 15:23:13.903] [info] Column ghost size increased from 0 to 0
[2026-05-22 15:23:13.912] [info] SNES iter=0 ; rnorm=4.45840e+00 (atol=1e-10) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:13.914] [info] SNES iter=1 ; rnorm=1.91059e-15 (atol=1e-10) ; relative_residual=4.28537e-16 (rtol=1e-10) ; stepsize_rel=1.00000e+00 (stol=1.49012e-10)
[2026-05-22 15:23:13.916] [info] SNES iter=0 ; rnorm=5.18958e-01 (atol=1e-10) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:13.918] [info] SNES iter=1 ; rnorm=1.46501e-15 (atol=1e-10) ; relative_residual=2.82299e-15 (rtol=1e-10) ; stepsize_rel=1.39286e-01 (stol=1.49012e-10)
[2026-05-22 15:23:13.920] [info] SNES iter=0 ; rnorm=1.97512e-01 (atol=1e-10) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:13.922] [info] SNES iter=1 ; rnorm=9.77483e-16 (atol=1e-10) ; relative_residual=4.94898e-15 (rtol=1e-10) ; stepsize_rel=6.96799e-02 (stol=1.49012e-10)
[2026-05-22 15:23:13.924] [info] SNES iter=0 ; rnorm=1.05477e-01 (atol=1e-10) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:13.926] [info] SNES iter=1 ; rnorm=9.57793e-16 (atol=1e-10) ; relative_residual=9.08059e-15 (rtol=1e-10) ; stepsize_rel=3.83873e-02 (stol=1.49012e-10)
[2026-05-22 15:23:13.928] [info] SNES iter=0 ; rnorm=6.01163e-02 (atol=1e-10) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:13.929] [info] SNES iter=1 ; rnorm=9.46403e-16 (atol=1e-10) ; relative_residual=1.57429e-14 (rtol=1e-10) ; stepsize_rel=2.18697e-02 (stol=1.49012e-10)
[2026-05-22 15:23:13.931] [info] SNES iter=0 ; rnorm=3.47446e-02 (atol=1e-10) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:13.933] [info] SNES iter=1 ; rnorm=1.02640e-15 (atol=1e-10) ; relative_residual=2.95412e-14 (rtol=1e-10) ; stepsize_rel=1.26087e-02 (stol=1.49012e-10)
[2026-05-22 15:23:13.935] [info] SNES iter=0 ; rnorm=2.01412e-02 (atol=1e-10) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:13.938] [info] SNES iter=1 ; rnorm=1.06550e-15 (atol=1e-10) ; relative_residual=5.29018e-14 (rtol=1e-10) ; stepsize_rel=7.30098e-03 (stol=1.49012e-10)
[2026-05-22 15:23:13.940] [info] SNES iter=0 ; rnorm=1.16829e-02 (atol=1e-10) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:13.941] [info] SNES iter=1 ; rnorm=1.13121e-15 (atol=1e-10) ; relative_residual=9.68257e-14 (rtol=1e-10) ; stepsize_rel=4.23412e-03 (stol=1.49012e-10)
[2026-05-22 15:23:13.944] [info] SNES iter=0 ; rnorm=6.77754e-03 (atol=1e-10) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:13.946] [info] SNES iter=1 ; rnorm=1.04954e-15 (atol=1e-10) ; relative_residual=1.54855e-13 (rtol=1e-10) ; stepsize_rel=2.45672e-03 (stol=1.49012e-10)
[2026-05-22 15:23:13.948] [info] SNES iter=0 ; rnorm=3.93187e-03 (atol=1e-10) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:13.950] [info] SNES iter=1 ; rnorm=9.70515e-16 (atol=1e-10) ; relative_residual=2.46833e-13 (rtol=1e-10) ; stepsize_rel=1.42558e-03 (stol=1.49012e-10)
[2026-05-22 15:23:13.952] [info] SNES iter=0 ; rnorm=2.28101e-03 (atol=1e-10) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:13.954] [info] SNES iter=1 ; rnorm=1.12403e-15 (atol=1e-10) ; relative_residual=4.92776e-13 (rtol=1e-10) ; stepsize_rel=8.27205e-04 (stol=1.49012e-10)
[2026-05-22 15:23:13.957] [info] SNES iter=0 ; rnorm=1.32328e-03 (atol=1e-10) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:13.958] [info] SNES iter=1 ; rnorm=1.06281e-15 (atol=1e-10) ; relative_residual=8.03158e-13 (rtol=1e-10) ; stepsize_rel=4.79966e-04 (stol=1.49012e-10)
[2026-05-22 15:23:13.960] [info] SNES iter=0 ; rnorm=7.67677e-04 (atol=1e-10) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:13.962] [info] SNES iter=1 ; rnorm=1.13745e-15 (atol=1e-10) ; relative_residual=1.48167e-12 (rtol=1e-10) ; stepsize_rel=2.78474e-04 (stol=1.49012e-10)
[2026-05-22 15:23:13.965] [info] SNES iter=0 ; rnorm=4.45353e-04 (atol=1e-10) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:13.966] [info] SNES iter=1 ; rnorm=1.09156e-15 (atol=1e-10) ; relative_residual=2.45101e-12 (rtol=1e-10) ; stepsize_rel=1.61563e-04 (stol=1.49012e-10)
[2026-05-22 15:23:13.968] [info] SNES iter=0 ; rnorm=2.58363e-04 (atol=1e-10) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:13.970] [info] SNES iter=1 ; rnorm=1.01765e-15 (atol=1e-10) ; relative_residual=3.93885e-12 (rtol=1e-10) ; stepsize_rel=9.37321e-05 (stol=1.49012e-10)
[2026-05-22 15:23:13.972] [info] SNES iter=0 ; rnorm=1.49884e-04 (atol=1e-10) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:13.973] [info] SNES iter=1 ; rnorm=1.07269e-15 (atol=1e-10) ; relative_residual=7.15679e-12 (rtol=1e-10) ; stepsize_rel=5.43784e-05 (stol=1.49012e-10)
[2026-05-22 15:23:13.976] [info] SNES iter=0 ; rnorm=8.69521e-05 (atol=1e-10) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:13.977] [info] SNES iter=1 ; rnorm=1.09400e-15 (atol=1e-10) ; relative_residual=1.25816e-11 (rtol=1e-10) ; stepsize_rel=3.15471e-05 (stol=1.49012e-10)
[2026-05-22 15:23:13.979] [info] SNES iter=0 ; rnorm=5.04435e-05 (atol=1e-10) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:13.981] [info] SNES iter=1 ; rnorm=1.09643e-15 (atol=1e-10) ; relative_residual=2.17358e-11 (rtol=1e-10) ; stepsize_rel=1.83016e-05 (stol=1.49012e-10)
[2026-05-22 15:23:13.983] [info] SNES iter=0 ; rnorm=2.92638e-05 (atol=1e-10) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:13.985] [info] SNES iter=1 ; rnorm=1.07338e-15 (atol=1e-10) ; relative_residual=3.66796e-11 (rtol=1e-10) ; stepsize_rel=1.06174e-05 (stol=1.49012e-10)
[2026-05-22 15:23:13.987] [info] SNES iter=0 ; rnorm=1.69768e-05 (atol=1e-10) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:13.988] [info] SNES iter=1 ; rnorm=9.69383e-16 (atol=1e-10) ; relative_residual=5.71004e-11 (rtol=1e-10) ; stepsize_rel=6.15948e-06 (stol=1.49012e-10)
[2026-05-22 15:23:13.990] [info] SNES iter=0 ; rnorm=9.84875e-06 (atol=1e-10) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:13.992] [info] SNES iter=1 ; rnorm=9.90182e-16 (atol=1e-10) ; relative_residual=1.00539e-10 (rtol=1e-10) ; stepsize_rel=3.57331e-06 (stol=1.49012e-10)
[2026-05-22 15:23:13.994] [info] SNES iter=0 ; rnorm=5.71356e-06 (atol=1e-10) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:13.996] [info] SNES iter=1 ; rnorm=1.01044e-15 (atol=1e-10) ; relative_residual=1.76850e-10 (rtol=1e-10) ; stepsize_rel=2.07298e-06 (stol=1.49012e-10)
[2026-05-22 15:23:13.998] [info] SNES iter=0 ; rnorm=3.31461e-06 (atol=1e-10) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:13.999] [info] SNES iter=1 ; rnorm=1.04092e-15 (atol=1e-10) ; relative_residual=3.14042e-10 (rtol=1e-10) ; stepsize_rel=1.20260e-06 (stol=1.49012e-10)
[2026-05-22 15:23:14.002] [info] SNES iter=0 ; rnorm=1.92290e-06 (atol=1e-10) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:14.003] [info] SNES iter=1 ; rnorm=1.12827e-15 (atol=1e-10) ; relative_residual=5.86754e-10 (rtol=1e-10) ; stepsize_rel=6.97665e-07 (stol=1.49012e-10)
[2026-05-22 15:23:14.007] [info] SNES iter=0 ; rnorm=1.11553e-06 (atol=1e-10) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:14.008] [info] SNES iter=1 ; rnorm=1.03037e-15 (atol=1e-10) ; relative_residual=9.23656e-10 (rtol=1e-10) ; stepsize_rel=4.04737e-07 (stol=1.49012e-10)
[2026-05-22 15:23:14.011] [info] SNES iter=0 ; rnorm=6.47154e-07 (atol=1e-10) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:14.012] [info] SNES iter=1 ; rnorm=1.20372e-15 (atol=1e-10) ; relative_residual=1.86002e-09 (rtol=1e-10) ; stepsize_rel=2.34800e-07 (stol=1.49012e-10)
[2026-05-22 15:23:14.014] [info] SNES iter=0 ; rnorm=3.75433e-07 (atol=1e-10) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:14.016] [info] SNES iter=1 ; rnorm=1.04887e-15 (atol=1e-10) ; relative_residual=2.79376e-09 (rtol=1e-10) ; stepsize_rel=1.36214e-07 (stol=1.49012e-10)
[2026-05-22 15:23:14.018] [info] SNES iter=0 ; rnorm=2.17800e-07 (atol=1e-10) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:14.020] [info] SNES iter=1 ; rnorm=9.64225e-16 (atol=1e-10) ; relative_residual=4.42711e-09 (rtol=1e-10) ; stepsize_rel=7.90221e-08 (stol=1.49012e-10)
[2026-05-22 15:23:14.022] [info] SNES iter=0 ; rnorm=1.26352e-07 (atol=1e-10) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:14.023] [info] SNES iter=1 ; rnorm=1.14728e-15 (atol=1e-10) ; relative_residual=9.07998e-09 (rtol=1e-10) ; stepsize_rel=4.58431e-08 (stol=1.49012e-10)
[2026-05-22 15:23:14.025] [info] SNES iter=0 ; rnorm=7.33008e-08 (atol=1e-10) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:14.027] [info] SNES iter=1 ; rnorm=9.35073e-16 (atol=1e-10) ; relative_residual=1.27567e-08 (rtol=1e-10) ; stepsize_rel=2.65949e-08 (stol=1.49012e-10)
[2026-05-22 15:23:14.029] [info] SNES iter=0 ; rnorm=4.25240e-08 (atol=1e-10) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:14.031] [info] SNES iter=1 ; rnorm=1.12801e-15 (atol=1e-10) ; relative_residual=2.65265e-08 (rtol=1e-10) ; stepsize_rel=1.54285e-08 (stol=1.49012e-10)
[2026-05-22 15:23:14.033] [info] SNES iter=0 ; rnorm=2.46694e-08 (atol=1e-10) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:14.034] [info] SNES iter=1 ; rnorm=1.11225e-15 (atol=1e-10) ; relative_residual=4.50860e-08 (rtol=1e-10) ; stepsize_rel=8.95054e-09 (stol=1.49012e-10)
[2026-05-22 15:23:14.036] [info] SNES iter=0 ; rnorm=1.43115e-08 (atol=1e-10) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:14.038] [info] SNES iter=1 ; rnorm=1.03820e-15 (atol=1e-10) ; relative_residual=7.25434e-08 (rtol=1e-10) ; stepsize_rel=5.19248e-09 (stol=1.49012e-10)
[2026-05-22 15:23:14.040] [info] SNES iter=0 ; rnorm=8.30251e-09 (atol=1e-10) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:14.042] [info] SNES iter=1 ; rnorm=1.36949e-15 (atol=1e-10) ; relative_residual=1.64948e-07 (rtol=1e-10) ; stepsize_rel=3.01231e-09 (stol=1.49012e-10)
[2026-05-22 15:23:14.044] [info] SNES iter=0 ; rnorm=4.81654e-09 (atol=1e-10) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:14.045] [info] SNES iter=1 ; rnorm=1.15172e-15 (atol=1e-10) ; relative_residual=2.39118e-07 (rtol=1e-10) ; stepsize_rel=1.74753e-09 (stol=1.49012e-10)
[2026-05-22 15:23:14.047] [info] SNES iter=0 ; rnorm=2.79422e-09 (atol=1e-10) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:14.049] [info] SNES iter=1 ; rnorm=9.58583e-16 (atol=1e-10) ; relative_residual=3.43060e-07 (rtol=1e-10) ; stepsize_rel=1.01380e-09 (stol=1.49012e-10)
[2026-05-22 15:23:14.051] [info] SNES iter=0 ; rnorm=1.62101e-09 (atol=1e-10) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:14.052] [info] SNES iter=1 ; rnorm=1.21318e-15 (atol=1e-10) ; relative_residual=7.48408e-07 (rtol=1e-10) ; stepsize_rel=5.88133e-10 (stol=1.49012e-10)
[2026-05-22 15:23:14.055] [info] SNES iter=0 ; rnorm=9.40395e-10 (atol=1e-10) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:14.056] [info] SNES iter=1 ; rnorm=9.80564e-16 (atol=1e-10) ; relative_residual=1.04271e-06 (rtol=1e-10) ; stepsize_rel=3.41194e-10 (stol=1.49012e-10)
[2026-05-22 15:23:14.058] [info] SNES iter=0 ; rnorm=5.45552e-10 (atol=1e-10) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:14.060] [info] SNES iter=1 ; rnorm=1.03550e-15 (atol=1e-10) ; relative_residual=1.89808e-06 (rtol=1e-10) ; stepsize_rel=1.97937e-10 (stol=1.49012e-10)
[2026-05-22 15:23:14.062] [info] SNES iter=0 ; rnorm=3.16491e-10 (atol=1e-10) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:14.063] [info] SNES iter=1 ; rnorm=1.11904e-15 (atol=1e-10) ; relative_residual=3.53579e-06 (rtol=1e-10) ; stepsize_rel=1.14829e-10 (stol=1.49012e-10)
[2026-05-22 15:23:14.065] [info] SNES iter=0 ; rnorm=1.83606e-10 (atol=1e-10) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:14.067] [info] SNES iter=1 ; rnorm=9.37888e-16 (atol=1e-10) ; relative_residual=5.10816e-06 (rtol=1e-10) ; stepsize_rel=6.66156e-11 (stol=1.49012e-10)
[2026-05-22 15:23:14.069] [info] SNES iter=0 ; rnorm=1.06515e-10 (atol=1e-10) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:14.071] [info] SNES iter=1 ; rnorm=1.03699e-15 (atol=1e-10) ; relative_residual=9.73559e-06 (rtol=1e-10) ; stepsize_rel=3.86458e-11 (stol=1.49012e-10)
[2026-05-22 15:23:14.073] [info] SNES iter=0 ; rnorm=6.17927e-11 (atol=1e-10) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:14.075] [info] SNES iter=0 ; rnorm=6.17927e-11 (atol=1e-10) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:14.077] [info] SNES iter=0 ; rnorm=6.17927e-11 (atol=1e-10) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:14.079] [info] SNES iter=0 ; rnorm=6.17927e-11 (atol=1e-10) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:14.081] [info] SNES iter=0 ; rnorm=6.17927e-11 (atol=1e-10) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:14.083] [info] SNES iter=0 ; rnorm=6.17927e-11 (atol=1e-10) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:14.085] [info] SNES iter=0 ; rnorm=6.17927e-11 (atol=1e-10) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:14.087] [info] SNES iter=0 ; rnorm=6.17927e-11 (atol=1e-10) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:14.089] [info] SNES iter=0 ; rnorm=6.17927e-11 (atol=1e-10) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:14.091] [info] SNES iter=0 ; rnorm=6.17927e-11 (atol=1e-10) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:14.093] [info] SNES iter=0 ; rnorm=6.17927e-11 (atol=1e-10) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:14.095] [info] SNES iter=0 ; rnorm=6.17927e-11 (atol=1e-10) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:14.097] [info] SNES iter=0 ; rnorm=6.17927e-11 (atol=1e-10) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:14.099] [info] SNES iter=0 ; rnorm=6.17927e-11 (atol=1e-10) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:14.101] [info] SNES iter=0 ; rnorm=6.17927e-11 (atol=1e-10) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:14.105] [info] SNES iter=0 ; rnorm=6.17927e-11 (atol=1e-10) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:14.107] [info] SNES iter=0 ; rnorm=6.17927e-11 (atol=1e-10) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:14.110] [info] SNES iter=0 ; rnorm=6.17927e-11 (atol=1e-10) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)
[2026-05-22 15:23:14.112] [info] SNES iter=0 ; rnorm=6.17927e-11 (atol=1e-10) ; relative_residual=inf (rtol=1e-10) ; stepsize_rel=inf (stol=1.49012e-10)

Now we see that the solver converges in one iteration (as opposed to zero) for longer! Let’s have a look at the derived quantities:

import matplotlib.pyplot as plt

for i, export in enumerate(my_model.exports):
    plt.plot(export.t, export.data, label=f"Export {i}")
plt.xlabel("Time")
plt.ylabel("Inventory")
plt.legend()
plt.show()
../../_images/bd7330108f4bba5c234b0a01b597e8e4b085a151b0e20f752d040b0dcacfaf42.png
set_log_level(LogLevel.WARNING)

The plot is now much smoother and the (real) steady state values are different from what they were previously!

Inspect the solution fields#

Often, inspecting the solution (concentration) field is a good way to quickly identify issues.

Let’s setup a 1D diffusion problem:

(26)#\[\begin{align} &\frac{\partial c}{\partial t} = \nabla \cdot (D \nabla c) = D \frac{\partial^2 c}{\partial x^2} \quad \text{on } x\in [0, 1]\\ &c = 1 \quad \text{on } x=\{0, 1\} \end{align}\]
my_model = F.HydrogenTransportProblem()

my_model.mesh = F.Mesh1D(vertices=np.linspace(0, 1, 11))

mat = F.Material(D_0=1, E_D=0)


vol = F.VolumeSubdomain1D(id=1, material=mat, borders=[0, 1])

left = F.SurfaceSubdomain1D(id=1, x=0)
right = F.SurfaceSubdomain1D(id=2, x=1)

my_model.subdomains = [left, right, vol]

H = F.Species("H")
my_model.species = [H]

my_model.temperature = 400

my_model.boundary_conditions = [
    F.FixedConcentrationBC(subdomain=left, value=1.0, species=H),
    F.FixedConcentrationBC(subdomain=right, value=1.0, species=H),
]

profile = F.Profile1DExport(field=H)

my_model.exports = [
    F.SurfaceFlux(field=H, surface=right),
    profile
]

my_model.settings = F.Settings(atol=1e-10, rtol=1e-10, transient=True, final_time=0.1)
my_model.settings.stepsize = F.Stepsize(initial_value=0.00001, growth_factor=1.1, cutback_factor=0.9, target_nb_iterations=4, max_stepsize=50)

my_model.initialise()
my_model.run()

This is a known mathematical problem with an analytical solution for \(c\) and for the outwards flux \(D \frac{\partial c}{\partial x}|_{x=1}\)

def analytical_solution(x, t):
    D = mat.D_0
    n = np.arange(1, 1000)[:, np.newaxis]
    A_n = 4 / ((2 * n - 1) * np.pi)
    return 1 - np.sum(
        A_n * np.sin((2*n - 1) * np.pi * x) * np.exp(-D * ((2*n - 1) * np.pi) ** 2 * t),
        axis=0
    )

def analytical_solution_flux_right(t):
    D = mat.D_0
    n = np.arange(1, 1000)[:, np.newaxis]
    A_n = 4 / ((2 * n - 1) * np.pi)
    return np.sum(
        A_n * (2*n - 1) * np.pi * D * np.exp(-D * ((2*n - 1) * np.pi) ** 2 * t),
            axis=0
    )

plt.plot(my_model.exports[0].t, -np.array(my_model.exports[0].data), label="FESTIM")
plt.plot(my_model.exports[0].t, analytical_solution_flux_right(my_model.exports[0].t), label="Analytical", color="tab:green")
plt.xlabel("Time")
plt.ylabel("Flux at x=1")
plt.yscale("log")
plt.legend()
plt.show()
../../_images/6e6c9ba574bf3d4336f3c5fd15928bddafbf1baad1a2d57a2f22efe564cceae5.png

The agreement with the analytical solution at small \(t\) is really off. What’s the issue?

Let’s plot the concentration profile!

spacing = 10
data = profile.data[::spacing]
times = profile.t[::spacing]

x_analytical = np.linspace(0, 1, 1000)

for t, c in zip(times, data):
    l_festim, = plt.plot(profile.x, c, marker="+", color="tab:blue")
    l_analytical, =plt.plot(x_analytical, analytical_solution(x_analytical, t), color="tab:green", linestyle="dashed", alpha=0.5)
plt.xlabel("Position")
plt.ylabel("Concentration")
plt.legend([l_festim, l_analytical], ["FESTIM", "Analytical"])
plt.show()
../../_images/b2b235d99faa5339045e2fa7e756b272511e029ff229f9a7340fe4f2db41bf8f.png
# delete some objects to reset the model and profile, see issue https://github.com/festim-dev/FESTIM/issues/1079
my_model.volume_meshtags = None
my_model.facet_meshtags = None
my_model.bc_forms = []
profile.data = []
profile.t = []
profile.x = None
profile._dofs = None
profile._sort_coords = None

There we go: at small times, the concentration gradient is very to big to be approximated properly by the numerical solution on this mesh.

In other words, the mesh is not refined enough. Let’s crank it up!

my_model.mesh = F.Mesh1D(vertices=np.linspace(0, 1, 1000))

my_model.initialise()
my_model.run()

Now the FESTIM solution is much closer to the analytical solution at small timesteps!

Hide code cell source

spacing = 10
data = profile.data[::spacing]
times = profile.t[::spacing]

x_analytical = np.linspace(0, 1, 1000)

for t, c in zip(times, data):
    l_festim, = plt.plot(profile.x, c, color="tab:blue")
    l_analytical, =plt.plot(x_analytical, analytical_solution(x_analytical, t), color="tab:green", linestyle="dashed", alpha=0.5, linewidth=3)
plt.xlabel("Position")
plt.ylabel("Concentration")
plt.legend([l_festim, l_analytical], ["FESTIM", "Analytical"])
plt.show()
../../_images/46ad7850e60bce88d64b606df68245fe5bb757a351619f7d6458eaf80dc0b786.png

Wich, in turn, fixes the flux mismatch!

plt.plot(my_model.exports[0].t, -np.array(my_model.exports[0].data), label="FESTIM")
plt.plot(my_model.exports[0].t, analytical_solution_flux_right(my_model.exports[0].t), label="Analytical", color="tab:green")
plt.xlabel("Time")
plt.ylabel("Flux at x=1")
plt.yscale("log")
plt.legend()
plt.show()
../../_images/bfa8bbe13cbe78f05bf9a034e8f6aae8864d0f4da3c4e6feec3cb233e86f31ff.png

Global vs Local refinement

Here the refinement was overkill. We refined the mesh globally.

We could have been more efficient and perform a local refinement in the high gradient regions.

x1 = 0.05
x2 = 0.95
vertices = np.concatenate(
    [
        np.linspace(0, x1, 100),  # refine the mesh near x=0
        np.linspace(x1, x2, 100),  # keep the same mesh in the middle
        np.linspace(x2, 1, 100)  # refine the mesh near x=1
    ]
)

my_model.mesh = F.Mesh1D(vertices)

Penalty term for interfaces#

Soon