Skip to content

Commit d7d8372

Browse files
Merge pull request #1070 from festim-dev/logger
Logger
2 parents 6620bd7 + 643e84c commit d7d8372

9 files changed

Lines changed: 82 additions & 46 deletions

File tree

docs/source/userguide/troubleshooting.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ We are simply solving a set of equations using the finite element method, and ar
1919
Solver doesn't converge
2020
^^^^^^^^^^^^^^^^^^^^^^^
2121

22-
The first thing to check is the details of the Newton solver iterations.
23-
To do so, you must set the ``log_level`` to ``20`` (default is ``40``).
22+
The first thing to check is the details of the SNES Newton solver iterations.
23+
To do so, you must set the ``log_level`` to ``INFO`` or ``DEBUG``.
2424
This will provide more information during the solving stage.
2525

2626
.. testcode::

src/festim/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,13 @@
3939
from .exports.xdmf import XDMFExport
4040
from .heat_transfer_problem import HeatTransferProblem
4141
from .helpers import (
42+
KSPMonitor,
43+
SnesMonitor,
4244
Value,
4345
as_fenics_constant,
4446
as_fenics_interp_expr_and_function,
4547
as_mapped_function,
48+
convergenceTest,
4649
get_interpolation_points,
4750
)
4851
from .hydrogen_transport_problem import (

src/festim/helpers.py

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
from collections.abc import Callable
22

3+
from mpi4py import MPI
4+
35
import dolfinx
46
import numpy as np
57
import ufl
@@ -341,3 +343,56 @@ def is_it_time_to_export(
341343
return True
342344

343345
return False
346+
347+
348+
_residual0 = 0
349+
_prev_xnorm = 0
350+
351+
352+
def convergenceTest(snes, it, norms):
353+
global _residual0
354+
xnorm, gnorm, f = norms # ||x_k||, ||x_k-x_k-1||, ||F(x_k)||
355+
356+
rtol, atol, stol, max_its = snes.getTolerances()
357+
358+
if it == 0:
359+
_residual0 = f
360+
if it > max_its:
361+
return snes.ConvergedReason.DIVERGED_MAX_IT
362+
elif f < atol:
363+
# elif f < atol and it > 0:
364+
return snes.ConvergedReason.CONVERGED_FNORM_ABS
365+
elif f / _residual0 < rtol:
366+
return snes.ConvergedReason.CONVERGED_FNORM_RELATIVE
367+
elif gnorm < stol and it > 0:
368+
return snes.ConvergedReason.CONVERGED_SNORM_RELATIVE
369+
else:
370+
return snes.ConvergedReason.ITERATING
371+
372+
373+
def SnesMonitor(snes, iter, rnorm):
374+
global _prev_xnorm
375+
if MPI.COMM_WORLD.rank == 0:
376+
rtol, atol, stol, max_its = snes.getTolerances()
377+
x = snes.getSolution()
378+
xnorm = x.norm()
379+
380+
stepsize_rel = abs(xnorm - _prev_xnorm) / xnorm if iter > 0 else float("inf")
381+
if iter == 0:
382+
relative_residual = float("inf")
383+
else:
384+
relative_residual = rnorm / _residual0
385+
386+
dolfinx.log.log(
387+
dolfinx.log.LogLevel.INFO,
388+
f"SNES {iter=} ; {rnorm=:.5e} ({atol=}) ; {relative_residual=:.5e} ({rtol=}) ; {stepsize_rel=:.5e} ({stol=:.5e})",
389+
)
390+
391+
# Update previous xnorm
392+
_prev_xnorm = xnorm
393+
394+
395+
def KSPMonitor(ksp, iter, rnorm):
396+
dolfinx.log.log(dolfinx.log.LogLevel.DEBUG, f"KSP {iter=}, {_residual0=:.5e}")
397+
if MPI.COMM_WORLD.rank == 0:
398+
dolfinx.log.log(dolfinx.log.LogLevel.DEBUG, f"KSP {iter=} {rnorm=:.5e}")

src/festim/hydrogen_transport_problem.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@
4040
as_fenics_constant,
4141
get_interpolation_points,
4242
is_it_time_to_export,
43+
SnesMonitor,
44+
KSPMonitor,
45+
convergenceTest,
4346
nmm_interpolate,
4447
)
4548
from festim.material import SolubilityLaw
@@ -1696,9 +1699,9 @@ def create_solver(self):
16961699
"snes_divergence_tolerance": "PETSC_UNLIMITED",
16971700
"ksp_type": "preonly",
16981701
"pc_type": "lu",
1699-
"snes_monitor": None,
1700-
"ksp_monitor": None,
17011702
"pc_factor_mat_solver_type": linear_solver,
1703+
"snes_error_if_not_converged": True,
1704+
"ksp_error_if_not_converged": True,
17021705
}
17031706
else:
17041707
petsc_options = self.petsc_options
@@ -1712,6 +1715,10 @@ def create_solver(self):
17121715
petsc_options_prefix="festim_solver",
17131716
)
17141717

1718+
self.solver.solver.setMonitor(SnesMonitor)
1719+
self.solver.solver.getKSP().setMonitor(KSPMonitor)
1720+
self.solver.solver.setConvergenceTest(convergenceTest)
1721+
17151722
# Delete PETSc options post setting them, ref:
17161723
# https://gitlab.com/petsc/petsc/-/issues/1201
17171724
snes = self.solver.solver

src/festim/problem.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,8 @@ def create_solver(self):
185185
"ksp_type": "preonly",
186186
"pc_type": "lu",
187187
"pc_factor_mat_solver_type": linear_solver,
188+
"snes_error_if_not_converged": True,
189+
"ksp_error_if_not_converged": True,
188190
}
189191
else:
190192
petsc_options = self.petsc_options
@@ -196,6 +198,10 @@ def create_solver(self):
196198
petsc_options=petsc_options,
197199
petsc_options_prefix="festim_solver",
198200
)
201+
202+
self.solver.solver.setMonitor(F.helpers.SnesMonitor)
203+
self.solver.solver.getKSP().setMonitor(F.helpers.KSPMonitor)
204+
self.solver.solver.setConvergenceTest(F.helpers.convergenceTest)
199205
# Delete PETSc options post setting them, ref:
200206
# https://gitlab.com/petsc/petsc/-/issues/1201
201207
snes = self.solver.solver

test/benchmark.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
from petsc4py import PETSc
66

77
import basix
8-
import dolfinx
98
import numpy as np
109
import tqdm.autonotebook
1110
from dolfinx.fem import (

test/test_multispecies_problem.py

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -84,12 +84,12 @@ def test_multispecies_permeation_problem():
8484
),
8585
]
8686
my_model.settings = F.Settings(
87-
atol=1e10,
87+
atol=1e2,
8888
rtol=1e-10,
8989
max_iterations=30,
9090
final_time=10,
9191
)
92-
my_model.settings.stepsize = F.Stepsize(initial_value=1 / 20)
92+
my_model.settings.stepsize = F.Stepsize(initial_value=0.08)
9393

9494
outgassing_flux_spe_1 = F.SurfaceFlux(
9595
field=spe_1,
@@ -124,17 +124,7 @@ def test_multispecies_permeation_problem():
124124
opts[f"{option_prefix}pc_type"] = "gamg"
125125
opts[f"{option_prefix}pc_factor_mat_solver_type"] = "mumps"
126126
ksp.setFromOptions()
127-
elif Version(dolfinx.__version__) > Version("0.9.0"):
128-
snes = my_model.solver.solver
129-
opts = PETSc.Options()
130-
option_prefix = snes.getOptionsPrefix()
131-
opts[f"{option_prefix}snes_atol"] = 0
132-
opts[f"{option_prefix}snes_rtol"] = 0
133-
opts[f"{option_prefix}snes_stol"] = 1e-8
134-
opts[f"{option_prefix}ksp_type"] = "cg"
135-
opts[f"{option_prefix}pc_type"] = "gamg"
136-
opts[f"{option_prefix}pc_factor_mat_solver_type"] = "mumps"
137-
snes.setFromOptions()
127+
138128
my_model.run()
139129

140130
times = outgassing_flux_spe_1.t

test/test_permeation_problem.py

Lines changed: 4 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -83,13 +83,13 @@ def test_permeation_problem(mesh_size=1001):
8383
]
8484

8585
my_model.settings = F.Settings(
86-
atol=1e10,
86+
atol=1e2,
8787
rtol=1e-10,
8888
max_iterations=30,
8989
final_time=50,
9090
)
9191

92-
my_model.settings.stepsize = F.Stepsize(initial_value=1 / 20)
92+
my_model.settings.stepsize = F.Stepsize(initial_value=0.3)
9393

9494
my_model.initialise()
9595

@@ -101,17 +101,6 @@ def test_permeation_problem(mesh_size=1001):
101101
opts[f"{option_prefix}ksp_type"] = "cg"
102102
opts[f"{option_prefix}pc_type"] = "gamg"
103103
ksp.setFromOptions()
104-
elif Version(dolfinx.__version__) > Version("0.9.0"):
105-
snes = my_model.solver.solver
106-
opts = PETSc.Options()
107-
option_prefix = snes.getOptionsPrefix()
108-
opts[f"{option_prefix}snes_atol"] = 0
109-
opts[f"{option_prefix}snes_rtol"] = 0
110-
opts[f"{option_prefix}snes_stol"] = 1e-8
111-
opts[f"{option_prefix}snes_max_it"] = 30
112-
opts[f"{option_prefix}ksp_type"] = "cg"
113-
opts[f"{option_prefix}pc_type"] = "gamg"
114-
snes.setFromOptions()
115104

116105
my_model.run()
117106

@@ -196,13 +185,13 @@ def test_permeation_problem_multi_volume(tmp_path):
196185
]
197186

198187
my_model.settings = F.Settings(
199-
atol=1e10,
188+
atol=1e2,
200189
rtol=1e-10,
201190
max_iterations=30,
202191
final_time=50,
203192
)
204193

205-
my_model.settings.stepsize = F.Stepsize(initial_value=1 / 20)
194+
my_model.settings.stepsize = F.Stepsize(initial_value=0.4)
206195

207196
my_model.initialise()
208197

@@ -215,17 +204,6 @@ def test_permeation_problem_multi_volume(tmp_path):
215204
opts[f"{option_prefix}pc_type"] = "gamg"
216205
opts[f"{option_prefix}pc_factor_mat_solver_type"] = "mumps"
217206
ksp.setFromOptions()
218-
elif Version(dolfinx.__version__) > Version("0.9.0"):
219-
snes = my_model.solver.solver
220-
opts = PETSc.Options()
221-
option_prefix = snes.getOptionsPrefix()
222-
opts[f"{option_prefix}snes_atol"] = 0
223-
opts[f"{option_prefix}snes_rtol"] = 0
224-
opts[f"{option_prefix}snes_stol"] = 1e-8
225-
opts[f"{option_prefix}ksp_type"] = "cg"
226-
opts[f"{option_prefix}pc_type"] = "gamg"
227-
opts[f"{option_prefix}pc_factor_mat_solver_type"] = "mumps"
228-
snes.setFromOptions()
229207

230208
my_model.run()
231209

test/test_species.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
from mpi4py import MPI
22

3-
import dolfinx
43
import numpy as np
54
import pytest
65
import ufl
76
from dolfinx.fem import Function, functionspace
87
from dolfinx.mesh import create_unit_cube
9-
from ufl.indexed import Indexed
108

119
import festim as F
1210

0 commit comments

Comments
 (0)