From cd335addc412781bdd5c574786187fedf5046cf8 Mon Sep 17 00:00:00 2001 From: RemDelaporteMathurin Date: Fri, 13 Feb 2026 14:59:44 -0500 Subject: [PATCH 01/10] added monitor functions --- src/festim/__init__.py | 3 +++ src/festim/helpers.py | 57 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+) diff --git a/src/festim/__init__.py b/src/festim/__init__.py index 8b3a074de..fd676ff8b 100644 --- a/src/festim/__init__.py +++ b/src/festim/__init__.py @@ -44,6 +44,9 @@ as_fenics_interp_expr_and_function, as_mapped_function, get_interpolation_points, + KSPMonitor, + convergenceTest, + SnesMonitor, ) from .hydrogen_transport_problem import ( HydrogenTransportProblem, diff --git a/src/festim/helpers.py b/src/festim/helpers.py index 68f437c3f..0d07f7d13 100644 --- a/src/festim/helpers.py +++ b/src/festim/helpers.py @@ -1,5 +1,7 @@ from collections.abc import Callable +from mpi4py import MPI + import dolfinx import numpy as np import ufl @@ -341,3 +343,58 @@ def is_it_time_to_export( return True return False + + +_residual0 = 0 +_prev_xnorm = 0 + + +def convergenceTest(snes, it, norms): + global _residual0 + xnorm, gnorm, f = norms # ||x_k||, ||x_k-x_k-1||, ||F(x_k)|| + + rtol, atol, stol, max_its = snes.getTolerances() + + if it == 0: + _residual0 = f + if it > max_its: + return snes.ConvergedReason.DIVERGED_MAX_IT + elif f < atol and it > 0: + print("Here atol", flush=True) + return snes.ConvergedReason.CONVERGED_FNORM_ABS + elif f / _residual0 < rtol: + print(f"Here rtol {f / _residual0} with rtol = {rtol}", flush=True) + return snes.ConvergedReason.CONVERGED_FNORM_RELATIVE + elif gnorm < stol and it > 0: + print("Here stol", flush=True) + return snes.ConvergedReason.CONVERGED_SNORM_RELATIVE + else: + return snes.ConvergedReason.ITERATING + + +def SnesMonitor(snes, iter, rnorm): + global _prev_xnorm + if MPI.COMM_WORLD.rank == 0: + rtol, atol, stol, max_its = snes.getTolerances() + x = snes.getSolution() + xnorm = x.norm() + + stepsize_rel = abs(xnorm - _prev_xnorm) / xnorm if iter > 0 else float("inf") + if iter == 0: + relative_residual = float("inf") + else: + relative_residual = rnorm / _residual0 + + dolfinx.log.log( + dolfinx.log.LogLevel.DEBUG, + f"SNES {iter=} ; {rnorm=:.5e} ({atol=:.5e}) ; {relative_residual=:.5e} ({rtol=:.5e}) ; {stepsize_rel=:.5e} ({stol=:.5e})", + ) + + # Update previous xnorm + _prev_xnorm = xnorm + + +def KSPMonitor(ksp, iter, rnorm): + dolfinx.log.log(dolfinx.log.LogLevel.INFO, f"{iter}, {_residual0=}") + if MPI.COMM_WORLD.rank == 0: + dolfinx.log.log(dolfinx.log.LogLevel.DEBUG, f"KSP {iter=} {rnorm=:.5e}") From 4b8b54d4deb66d351dea4f38aa393631f9dbafec Mon Sep 17 00:00:00 2001 From: RemDelaporteMathurin Date: Fri, 13 Feb 2026 15:10:18 -0500 Subject: [PATCH 02/10] updated log levels + removed prints --- src/festim/helpers.py | 7 ++----- src/festim/problem.py | 6 ++++++ 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/festim/helpers.py b/src/festim/helpers.py index 0d07f7d13..ab6e3c982 100644 --- a/src/festim/helpers.py +++ b/src/festim/helpers.py @@ -360,13 +360,10 @@ def convergenceTest(snes, it, norms): if it > max_its: return snes.ConvergedReason.DIVERGED_MAX_IT elif f < atol and it > 0: - print("Here atol", flush=True) return snes.ConvergedReason.CONVERGED_FNORM_ABS elif f / _residual0 < rtol: - print(f"Here rtol {f / _residual0} with rtol = {rtol}", flush=True) return snes.ConvergedReason.CONVERGED_FNORM_RELATIVE elif gnorm < stol and it > 0: - print("Here stol", flush=True) return snes.ConvergedReason.CONVERGED_SNORM_RELATIVE else: return snes.ConvergedReason.ITERATING @@ -386,7 +383,7 @@ def SnesMonitor(snes, iter, rnorm): relative_residual = rnorm / _residual0 dolfinx.log.log( - dolfinx.log.LogLevel.DEBUG, + dolfinx.log.LogLevel.INFO, f"SNES {iter=} ; {rnorm=:.5e} ({atol=:.5e}) ; {relative_residual=:.5e} ({rtol=:.5e}) ; {stepsize_rel=:.5e} ({stol=:.5e})", ) @@ -395,6 +392,6 @@ def SnesMonitor(snes, iter, rnorm): def KSPMonitor(ksp, iter, rnorm): - dolfinx.log.log(dolfinx.log.LogLevel.INFO, f"{iter}, {_residual0=}") + dolfinx.log.log(dolfinx.log.LogLevel.DEBUG, f"{iter}, {_residual0=}") if MPI.COMM_WORLD.rank == 0: dolfinx.log.log(dolfinx.log.LogLevel.DEBUG, f"KSP {iter=} {rnorm=:.5e}") diff --git a/src/festim/problem.py b/src/festim/problem.py index 8cd086172..610d4a081 100644 --- a/src/festim/problem.py +++ b/src/festim/problem.py @@ -185,6 +185,8 @@ def create_solver(self): "ksp_type": "preonly", "pc_type": "lu", "pc_factor_mat_solver_type": linear_solver, + "snes_error_if_not_converged": True, + "ksp_error_if_not_converged": True, } else: petsc_options = self.petsc_options @@ -196,6 +198,10 @@ def create_solver(self): petsc_options=petsc_options, petsc_options_prefix="festim_solver", ) + + self.solver.solver.setMonitor(F.helpers.SnesMonitor) + self.solver.solver.getKSP().setMonitor(F.helpers.KSPMonitor) + self.solver.solver.setConvergenceTest(F.helpers.convergenceTest) # Delete PETSc options post setting them, ref: # https://gitlab.com/petsc/petsc/-/issues/1201 snes = self.solver.solver From ca1e6205bc993595dac7068582a4e7d6c903de8a Mon Sep 17 00:00:00 2001 From: RemDelaporteMathurin Date: Fri, 13 Feb 2026 15:22:02 -0500 Subject: [PATCH 03/10] slight formatting modifs --- src/festim/helpers.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/festim/helpers.py b/src/festim/helpers.py index ab6e3c982..5b217d5e4 100644 --- a/src/festim/helpers.py +++ b/src/festim/helpers.py @@ -384,7 +384,7 @@ def SnesMonitor(snes, iter, rnorm): dolfinx.log.log( dolfinx.log.LogLevel.INFO, - f"SNES {iter=} ; {rnorm=:.5e} ({atol=:.5e}) ; {relative_residual=:.5e} ({rtol=:.5e}) ; {stepsize_rel=:.5e} ({stol=:.5e})", + f"SNES {iter=} ; {rnorm=:.5e} ({atol=}) ; {relative_residual=:.5e} ({rtol=}) ; {stepsize_rel=:.5e} ({stol=:.5e})", ) # Update previous xnorm @@ -392,6 +392,6 @@ def SnesMonitor(snes, iter, rnorm): def KSPMonitor(ksp, iter, rnorm): - dolfinx.log.log(dolfinx.log.LogLevel.DEBUG, f"{iter}, {_residual0=}") + dolfinx.log.log(dolfinx.log.LogLevel.DEBUG, f"KSP {iter=}, {_residual0=:.5e}") if MPI.COMM_WORLD.rank == 0: dolfinx.log.log(dolfinx.log.LogLevel.DEBUG, f"KSP {iter=} {rnorm=:.5e}") From ce4c864cbed010b45034dc210392bfefa7f53171 Mon Sep 17 00:00:00 2001 From: RemDelaporteMathurin Date: Fri, 13 Feb 2026 16:00:39 -0500 Subject: [PATCH 04/10] allow to converge in zero iterations (abs) --- src/festim/helpers.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/festim/helpers.py b/src/festim/helpers.py index 5b217d5e4..53e2cf700 100644 --- a/src/festim/helpers.py +++ b/src/festim/helpers.py @@ -359,7 +359,8 @@ def convergenceTest(snes, it, norms): _residual0 = f if it > max_its: return snes.ConvergedReason.DIVERGED_MAX_IT - elif f < atol and it > 0: + elif f < atol: + # elif f < atol and it > 0: return snes.ConvergedReason.CONVERGED_FNORM_ABS elif f / _residual0 < rtol: return snes.ConvergedReason.CONVERGED_FNORM_RELATIVE From e340c6f505643620938339921f2d0d61abb4e8f2 Mon Sep 17 00:00:00 2001 From: RemDelaporteMathurin Date: Fri, 13 Feb 2026 16:00:47 -0500 Subject: [PATCH 05/10] fix test --- test/test_permeation_problem.py | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/test/test_permeation_problem.py b/test/test_permeation_problem.py index 08c6d5e8c..a6ab10d18 100644 --- a/test/test_permeation_problem.py +++ b/test/test_permeation_problem.py @@ -196,13 +196,13 @@ def test_permeation_problem_multi_volume(tmp_path): ] my_model.settings = F.Settings( - atol=1e10, + atol=1e2, rtol=1e-10, max_iterations=30, final_time=50, ) - my_model.settings.stepsize = F.Stepsize(initial_value=1 / 20) + my_model.settings.stepsize = F.Stepsize(initial_value=0.4) my_model.initialise() @@ -215,17 +215,6 @@ def test_permeation_problem_multi_volume(tmp_path): opts[f"{option_prefix}pc_type"] = "gamg" opts[f"{option_prefix}pc_factor_mat_solver_type"] = "mumps" ksp.setFromOptions() - elif Version(dolfinx.__version__) > Version("0.9.0"): - snes = my_model.solver.solver - opts = PETSc.Options() - option_prefix = snes.getOptionsPrefix() - opts[f"{option_prefix}snes_atol"] = 0 - opts[f"{option_prefix}snes_rtol"] = 0 - opts[f"{option_prefix}snes_stol"] = 1e-8 - opts[f"{option_prefix}ksp_type"] = "cg" - opts[f"{option_prefix}pc_type"] = "gamg" - opts[f"{option_prefix}pc_factor_mat_solver_type"] = "mumps" - snes.setFromOptions() my_model.run() From 982c1f9e84117b57550380b2b5c6e97159f382be Mon Sep 17 00:00:00 2001 From: RemDelaporteMathurin Date: Fri, 13 Feb 2026 16:12:16 -0500 Subject: [PATCH 06/10] fixed tests --- test/test_multispecies_problem.py | 16 +++------------- test/test_permeation_problem.py | 15 ++------------- 2 files changed, 5 insertions(+), 26 deletions(-) diff --git a/test/test_multispecies_problem.py b/test/test_multispecies_problem.py index 654ec952b..4defae394 100644 --- a/test/test_multispecies_problem.py +++ b/test/test_multispecies_problem.py @@ -84,12 +84,12 @@ def test_multispecies_permeation_problem(): ), ] my_model.settings = F.Settings( - atol=1e10, + atol=1e2, rtol=1e-10, max_iterations=30, final_time=10, ) - my_model.settings.stepsize = F.Stepsize(initial_value=1 / 20) + my_model.settings.stepsize = F.Stepsize(initial_value=0.08) outgassing_flux_spe_1 = F.SurfaceFlux( field=spe_1, @@ -124,17 +124,7 @@ def test_multispecies_permeation_problem(): opts[f"{option_prefix}pc_type"] = "gamg" opts[f"{option_prefix}pc_factor_mat_solver_type"] = "mumps" ksp.setFromOptions() - elif Version(dolfinx.__version__) > Version("0.9.0"): - snes = my_model.solver.solver - opts = PETSc.Options() - option_prefix = snes.getOptionsPrefix() - opts[f"{option_prefix}snes_atol"] = 0 - opts[f"{option_prefix}snes_rtol"] = 0 - opts[f"{option_prefix}snes_stol"] = 1e-8 - opts[f"{option_prefix}ksp_type"] = "cg" - opts[f"{option_prefix}pc_type"] = "gamg" - opts[f"{option_prefix}pc_factor_mat_solver_type"] = "mumps" - snes.setFromOptions() + my_model.run() times = outgassing_flux_spe_1.t diff --git a/test/test_permeation_problem.py b/test/test_permeation_problem.py index a6ab10d18..d5da1e391 100644 --- a/test/test_permeation_problem.py +++ b/test/test_permeation_problem.py @@ -83,13 +83,13 @@ def test_permeation_problem(mesh_size=1001): ] my_model.settings = F.Settings( - atol=1e10, + atol=1e2, rtol=1e-10, max_iterations=30, final_time=50, ) - my_model.settings.stepsize = F.Stepsize(initial_value=1 / 20) + my_model.settings.stepsize = F.Stepsize(initial_value=0.3) my_model.initialise() @@ -101,17 +101,6 @@ def test_permeation_problem(mesh_size=1001): opts[f"{option_prefix}ksp_type"] = "cg" opts[f"{option_prefix}pc_type"] = "gamg" ksp.setFromOptions() - elif Version(dolfinx.__version__) > Version("0.9.0"): - snes = my_model.solver.solver - opts = PETSc.Options() - option_prefix = snes.getOptionsPrefix() - opts[f"{option_prefix}snes_atol"] = 0 - opts[f"{option_prefix}snes_rtol"] = 0 - opts[f"{option_prefix}snes_stol"] = 1e-8 - opts[f"{option_prefix}snes_max_it"] = 30 - opts[f"{option_prefix}ksp_type"] = "cg" - opts[f"{option_prefix}pc_type"] = "gamg" - snes.setFromOptions() my_model.run() From 7cf9e93c119033735d110e3d6e2c0e6083aa4037 Mon Sep 17 00:00:00 2001 From: RemDelaporteMathurin Date: Fri, 13 Feb 2026 16:21:52 -0500 Subject: [PATCH 07/10] ruff --- test/system_tests/test_multi_mat_penalty.py | 10 ++++------ test/system_tests/test_multi_material.py | 20 ++++++++----------- .../test_multi_material_change_of_var.py | 20 ++++++++----------- 3 files changed, 20 insertions(+), 30 deletions(-) diff --git a/test/system_tests/test_multi_mat_penalty.py b/test/system_tests/test_multi_mat_penalty.py index efd505081..116da435e 100644 --- a/test/system_tests/test_multi_mat_penalty.py +++ b/test/system_tests/test_multi_mat_penalty.py @@ -71,13 +71,11 @@ def test_2_materials_2d_mms(tmpdir): K_S_bot = 6.0 D_top = 2.0 D_bot = 5.0 - c_exact_top_ufl = ( - lambda x: 3 - + ufl.sin(ufl.pi * (2 * x[1] + 0.5)) - + 0.1 * ufl.cos(2 * ufl.pi * x[0]) + c_exact_top_ufl = lambda x: ( + 3 + ufl.sin(ufl.pi * (2 * x[1] + 0.5)) + 0.1 * ufl.cos(2 * ufl.pi * x[0]) ) - c_exact_top_np = ( - lambda x: 3 + np.sin(np.pi * (2 * x[1] + 0.5)) + 0.1 * np.cos(2 * np.pi * x[0]) + c_exact_top_np = lambda x: ( + 3 + np.sin(np.pi * (2 * x[1] + 0.5)) + 0.1 * np.cos(2 * np.pi * x[0]) ) def c_exact_bot_ufl(x): diff --git a/test/system_tests/test_multi_material.py b/test/system_tests/test_multi_material.py index 167efbf11..86526d7b4 100644 --- a/test/system_tests/test_multi_material.py +++ b/test/system_tests/test_multi_material.py @@ -71,15 +71,15 @@ def test_2_materials_2d_mms(tmpdir): K_S_bot = 6.0 D_top = 2.0 D_bot = 5.0 - c_exact_top_ufl = ( - lambda x: 1 + ufl.sin(ufl.pi * (2 * x[0] + 0.5)) + ufl.cos(2 * ufl.pi * x[1]) + c_exact_top_ufl = lambda x: ( + 1 + ufl.sin(ufl.pi * (2 * x[0] + 0.5)) + ufl.cos(2 * ufl.pi * x[1]) ) def c_exact_bot_ufl(x): return K_S_bot / K_S_top * c_exact_top_ufl(x) - c_exact_top_np = ( - lambda x: 1 + np.sin(np.pi * (2 * x[0] + 0.5)) + np.cos(2 * np.pi * x[1]) + c_exact_top_np = lambda x: ( + 1 + np.sin(np.pi * (2 * x[0] + 0.5)) + np.cos(2 * np.pi * x[1]) ) def c_exact_bot_np(x): @@ -126,15 +126,11 @@ def c_exact_bot_np(x): F.FixedConcentrationBC(bottom_surface, value=c_exact_bot_ufl, species=H), ] - source_top_val = ( - lambda x: 8 - * ufl.pi**2 - * (ufl.cos(2 * ufl.pi * x[0]) + ufl.cos(2 * ufl.pi * x[1])) + source_top_val = lambda x: ( + 8 * ufl.pi**2 * (ufl.cos(2 * ufl.pi * x[0]) + ufl.cos(2 * ufl.pi * x[1])) ) - source_bottom_val = ( - lambda x: 40 - * ufl.pi**2 - * (ufl.cos(2 * ufl.pi * x[0]) + ufl.cos(2 * ufl.pi * x[1])) + source_bottom_val = lambda x: ( + 40 * ufl.pi**2 * (ufl.cos(2 * ufl.pi * x[0]) + ufl.cos(2 * ufl.pi * x[1])) ) my_model.sources = [ F.ParticleSource(volume=top_domain, species=H, value=source_top_val), diff --git a/test/system_tests/test_multi_material_change_of_var.py b/test/system_tests/test_multi_material_change_of_var.py index fa0674461..8091a2663 100644 --- a/test/system_tests/test_multi_material_change_of_var.py +++ b/test/system_tests/test_multi_material_change_of_var.py @@ -156,15 +156,15 @@ def test_2_materials_2d_mms(tmpdir): K_S_bot = 6.0 D_top = 2.0 D_bot = 5.0 - c_exact_top_ufl = ( - lambda x: 1 + ufl.sin(ufl.pi * (2 * x[0] + 0.5)) + ufl.cos(2 * ufl.pi * x[1]) + c_exact_top_ufl = lambda x: ( + 1 + ufl.sin(ufl.pi * (2 * x[0] + 0.5)) + ufl.cos(2 * ufl.pi * x[1]) ) def c_exact_bot_ufl(x): return K_S_bot / K_S_top * c_exact_top_ufl(x) - c_exact_top_np = ( - lambda x: 1 + np.sin(np.pi * (2 * x[0] + 0.5)) + np.cos(2 * np.pi * x[1]) + c_exact_top_np = lambda x: ( + 1 + np.sin(np.pi * (2 * x[0] + 0.5)) + np.cos(2 * np.pi * x[1]) ) def c_exact_bot_np(x): @@ -201,15 +201,11 @@ def c_exact_bot_np(x): F.FixedConcentrationBC(bottom_surface, value=c_exact_bot_ufl, species=H), ] - source_top_val = ( - lambda x: 8 - * ufl.pi**2 - * (ufl.cos(2 * ufl.pi * x[0]) + ufl.cos(2 * ufl.pi * x[1])) + source_top_val = lambda x: ( + 8 * ufl.pi**2 * (ufl.cos(2 * ufl.pi * x[0]) + ufl.cos(2 * ufl.pi * x[1])) ) - source_bottom_val = ( - lambda x: 40 - * ufl.pi**2 - * (ufl.cos(2 * ufl.pi * x[0]) + ufl.cos(2 * ufl.pi * x[1])) + source_bottom_val = lambda x: ( + 40 * ufl.pi**2 * (ufl.cos(2 * ufl.pi * x[0]) + ufl.cos(2 * ufl.pi * x[1])) ) my_model.sources = [ F.ParticleSource(volume=top_domain, species=H, value=source_top_val), From 55444c785fb566ecef59e290d0daab9c4d72ed78 Mon Sep 17 00:00:00 2001 From: RemDelaporteMathurin Date: Fri, 13 Feb 2026 16:22:30 -0500 Subject: [PATCH 08/10] ruff again --- src/festim/__init__.py | 6 +++--- test/benchmark.py | 1 - test/test_species.py | 2 -- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/festim/__init__.py b/src/festim/__init__.py index fd676ff8b..d6df5c269 100644 --- a/src/festim/__init__.py +++ b/src/festim/__init__.py @@ -39,14 +39,14 @@ from .exports.xdmf import XDMFExport from .heat_transfer_problem import HeatTransferProblem from .helpers import ( + KSPMonitor, + SnesMonitor, Value, as_fenics_constant, as_fenics_interp_expr_and_function, as_mapped_function, - get_interpolation_points, - KSPMonitor, convergenceTest, - SnesMonitor, + get_interpolation_points, ) from .hydrogen_transport_problem import ( HydrogenTransportProblem, diff --git a/test/benchmark.py b/test/benchmark.py index 7c388ad5e..99cbfc27a 100644 --- a/test/benchmark.py +++ b/test/benchmark.py @@ -5,7 +5,6 @@ from petsc4py import PETSc import basix -import dolfinx import numpy as np import tqdm.autonotebook from dolfinx.fem import ( diff --git a/test/test_species.py b/test/test_species.py index 289d4c7e0..e5d2af306 100644 --- a/test/test_species.py +++ b/test/test_species.py @@ -1,12 +1,10 @@ from mpi4py import MPI -import dolfinx import numpy as np import pytest import ufl from dolfinx.fem import Function, functionspace from dolfinx.mesh import create_unit_cube -from ufl.indexed import Indexed import festim as F From afc3e839440ec46c5c7bd1c88267fbe46ebacdd4 Mon Sep 17 00:00:00 2001 From: RemDelaporteMathurin Date: Fri, 13 Feb 2026 16:24:35 -0500 Subject: [PATCH 09/10] updated docs --- docs/source/userguide/troubleshooting.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/source/userguide/troubleshooting.rst b/docs/source/userguide/troubleshooting.rst index 5763270ea..6eb7da648 100644 --- a/docs/source/userguide/troubleshooting.rst +++ b/docs/source/userguide/troubleshooting.rst @@ -19,8 +19,8 @@ We are simply solving a set of equations using the finite element method, and ar Solver doesn't converge ^^^^^^^^^^^^^^^^^^^^^^^ -The first thing to check is the details of the Newton solver iterations. -To do so, you must set the ``log_level`` to ``20`` (default is ``40``). +The first thing to check is the details of the SNES Newton solver iterations. +To do so, you must set the ``log_level`` to ``INFO`` or ``DEBUG``. This will provide more information during the solving stage. .. testcode:: From 08f01a6ad107275e8935db00adb11ad456e7383e Mon Sep 17 00:00:00 2001 From: RemDelaporteMathurin Date: Fri, 13 Feb 2026 16:43:14 -0500 Subject: [PATCH 10/10] added monitors to Discontinuous --- src/festim/hydrogen_transport_problem.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/festim/hydrogen_transport_problem.py b/src/festim/hydrogen_transport_problem.py index 4ca121026..57ebf6022 100644 --- a/src/festim/hydrogen_transport_problem.py +++ b/src/festim/hydrogen_transport_problem.py @@ -40,6 +40,9 @@ as_fenics_constant, get_interpolation_points, is_it_time_to_export, + SnesMonitor, + KSPMonitor, + convergenceTest, ) from festim.material import SolubilityLaw @@ -1688,9 +1691,9 @@ def create_solver(self): "snes_divergence_tolerance": "PETSC_UNLIMITED", "ksp_type": "preonly", "pc_type": "lu", - "snes_monitor": None, - "ksp_monitor": None, "pc_factor_mat_solver_type": linear_solver, + "snes_error_if_not_converged": True, + "ksp_error_if_not_converged": True, } else: petsc_options = self.petsc_options @@ -1704,6 +1707,10 @@ def create_solver(self): petsc_options_prefix="festim_solver", ) + self.solver.solver.setMonitor(SnesMonitor) + self.solver.solver.getKSP().setMonitor(KSPMonitor) + self.solver.solver.setConvergenceTest(convergenceTest) + # Delete PETSc options post setting them, ref: # https://gitlab.com/petsc/petsc/-/issues/1201 snes = self.solver.solver