2.4.8 Solver comparison

This example shows how to set up solvers explicitly and how to extract diagnostic information.

Deviation: 8.8e-05, 0.00019, 9.3e-05, 9.3e-05, 9.4e-05, explicit Euler solver, explicit, adaptive Runge-Kutta solver, implicit solver, Crank-Nicolson solver, Adam-Bashforth solver, scipy solver
Diagnostic information for explicit Euler solver:
{'controller': {'mpi_run': False, 't_start': 0, 't_end': 1.0, 'profiler': {'solver': 0.0016955800000033605, 'tracker': 7.696999999495802e-05, 'compilation': 6.112589580000005}, 'solver_start': '2026-03-16 10:45:25.060409+00:00', 'successful': True, 'stop_reason': 'Reached final time', 'solver_duration': '0:00:00.001762', 't_final': 1.0}, 'package_version': 'unknown', 'solver': {'class': 'EulerSolver', 'pde_class': 'DiffusionPDE', 'backend': {'name': 'numba'}, 'dt_statistics': {'min': inf, 'max': -inf, 'mean': 0.0, 'std': nan, 'count': 0.0}, 'scheme': 'euler', 'dt': 0.001, 'dt_adaptive': False, 'steps': 1000, 'post_step_data': None, 'stochastic': False}}

Diagnostic information for explicit, adaptive Runge-Kutta solver:
{'controller': {'mpi_run': False, 't_start': 0, 't_end': 1.0, 'profiler': {'solver': 0.0004279199999928096, 'tracker': 5.355000000406562e-05, 'compilation': 7.267058684999995}, 'solver_start': '2026-03-16 10:45:32.337586+00:00', 'successful': True, 'stop_reason': 'Reached final time', 'solver_duration': '0:00:00.000472', 't_final': 1.0}, 'package_version': 'unknown', 'solver': {'class': 'RungeKuttaSolver', 'pde_class': 'DiffusionPDE', 'backend': {'name': 'numba'}, 'dt_statistics': {'min': 0.001, 'max': 0.16414537609657268, 'mean': 0.08333333333333333, 'std': 0.05150846996300837, 'count': 12.0}, 'dt': 0.001, 'dt_adaptive': True, 'steps': 12, 'stochastic': False, 'post_step_data': None}}

Diagnostic information for implicit solver:
{'controller': {'mpi_run': False, 't_start': 0, 't_end': 1.0, 'profiler': {'solver': 0.008178181000005225, 'tracker': 4.709899998545097e-05, 'compilation': 4.167869843000005}, 'solver_start': '2026-03-16 10:45:36.516537+00:00', 'successful': True, 'stop_reason': 'Reached final time', 'solver_duration': '0:00:00.008217', 't_final': 1.0}, 'package_version': 'unknown', 'solver': {'class': 'ImplicitSolver', 'pde_class': 'DiffusionPDE', 'backend': {'name': 'numba'}, 'dt_statistics': {'min': inf, 'max': -inf, 'mean': 0.0, 'std': nan, 'count': 0.0}, 'function_evaluations': 0, 'scheme': 'implicit-euler', 'stochastic': False, 'dt': 0.001, 'dt_adaptive': False, 'steps': 1000, 'post_step_data': None}}

Diagnostic information for Crank-Nicolson solver:
{'controller': {'mpi_run': False, 't_start': 0, 't_end': 1.0, 'profiler': {'solver': 0.012765749999999798, 'tracker': 5.351000000075601e-05, 'compilation': 6.324975011999996}, 'solver_start': '2026-03-16 10:45:42.857716+00:00', 'successful': True, 'stop_reason': 'Reached final time', 'solver_duration': '0:00:00.012812', 't_final': 1.0}, 'package_version': 'unknown', 'solver': {'class': 'CrankNicolsonSolver', 'pde_class': 'DiffusionPDE', 'backend': {'name': 'numba'}, 'dt_statistics': {'min': inf, 'max': -inf, 'mean': 0.0, 'std': nan, 'count': 0.0}, 'function_evaluations': 0, 'stochastic': False, 'dt': 0.001, 'dt_adaptive': False, 'steps': 1000, 'post_step_data': None}}

Diagnostic information for Adam-Bashforth solver:
{'controller': {'mpi_run': False, 't_start': 0, 't_end': 1.0, 'profiler': {'solver': 3.8306609029999947, 'tracker': 6.23500000074273e-05, 'compilation': 1.8905862179999957}, 'solver_start': '2026-03-16 10:45:44.771271+00:00', 'successful': True, 'stop_reason': 'Reached final time', 'solver_duration': '0:00:03.832488', 't_final': 1.0}, 'package_version': 'unknown', 'solver': {'class': 'AdamsBashforthSolver', 'pde_class': 'DiffusionPDE', 'backend': {'name': 'numba'}, 'dt_statistics': {'min': inf, 'max': -inf, 'mean': 0.0, 'std': nan, 'count': 0.0}, 'dt': 0.001, 'dt_adaptive': False, 'steps': 1000, 'post_step_data': None, 'stochastic': False}}

Diagnostic information for scipy solver:
{'controller': {'mpi_run': False, 't_start': 0, 't_end': 1.0, 'profiler': {'solver': 0.6683350200000007, 'tracker': 5.036999999674663e-05, 'compilation': 0.0015163700000044855}, 'solver_start': '2026-03-16 10:45:48.608127+00:00', 'successful': True, 'stop_reason': 'Reached final time', 'solver_duration': '0:00:00.668657', 't_final': np.float64(1.0)}, 'package_version': 'unknown', 'solver': {'class': 'ScipySolver', 'pde_class': 'DiffusionPDE', 'dt': 0.001, 'steps': 61, 'stochastic': False, 'backend': {'name': 'numba'}}}

import pde

# initialize the grid, an initial condition, and the PDE
grid = pde.UnitGrid([32, 32])
field = pde.ScalarField.random_uniform(grid, -1, 1)
eq = pde.DiffusionPDE()


def run_solver(solver, label):
    """Helper function testing the solver."""
    controller = pde.Controller(solver, t_range=1, tracker=None)
    sol = controller.run(field, dt=1e-3)
    sol.label = label + " solver"
    print(f"Diagnostic information for {sol.label}:")
    print(controller.diagnostics)
    print()
    return sol


# try different solvers
solutions = [
    run_solver(pde.EulerSolver(eq), "explicit Euler"),
    run_solver(
        pde.RungeKuttaSolver(eq, adaptive=True), "explicit, adaptive Runge-Kutta"
    ),
    run_solver(pde.ImplicitSolver(eq), "implicit"),
    run_solver(pde.CrankNicolsonSolver(eq), "Crank-Nicolson"),
    run_solver(pde.AdamsBashforthSolver(eq), "Adam-Bashforth"),
    run_solver(pde.ScipySolver(eq), "scipy"),
]

# plot both fields and give the deviation as the title
deviations = [(solutions[0] - sol).fluctuations for sol in solutions]
title = "Deviation: " + ", ".join(f"{deviation:.2g}" for deviation in deviations[1:])
pde.FieldCollection(solutions).plot(title=title, arrangement=(2, 3))

Total running time of the script: (0 minutes 30.999 seconds)