Choosing solvers#
Several simulations available in SimPEG need to numerically solve a partial
differential equations system (PDE), such as
Simulation3DNodal (DC)
Simulation3DMagneticFluxDensity
(TDEM)
and
Simulation3DMagneticFluxDensity
(FDEM).
A numerical solver is needed to solve the PDEs.
SimPEG can make use of the solvers available in pymatsolver, like
pymatsolver.Pardiso, pymatsolver.Mumps or
pymatsolver.SolverLU.
The choice of an appropriate solver can affect the computation time required to
solve the PDE. Generally we recommend using direct solvers over iterative solvers
for SimPEG, but be aware that direct solvers have much larger memory requirements.
The Pardiso solver wraps the oneMKL PARDISO
solver available for x86_64 CPUs.
The Mumps solver wraps MUMPS, a fast solver available for
all CPU brands, including Apple silicon architecture.
The SolverLU wraps SciPy’s scipy.sparse.linalg.splu(). The
performance of this solver is not up to the level of Mumps and Pardiso.
Usage of the SolveLU is recommended only when it’s not possible to use
other faster solvers.
The default solver#
We can use simpeg.utils.get_default_solver() to obtain a reasonable default
solver available for our system:
import simpeg
import simpeg.electromagnetics.static.resistivity as dc
# Get default solver
solver = simpeg.utils.get_default_solver()
print(f"Solver: {solver}")
which would print out on an x86_64 cpu:
Solver: <class 'pymatsolver.direct.pardiso.Pardiso'>
We can then use this solver in a simulation:
# Define a simple mesh
h = [(1.0, 10)]
mesh = discretize.TensorMesh([h, h, h], origin="CCC")
# And a DC survey
receiver = dc.receivers.Dipole(locations_m=(-1, 0, 0), locations_n=(1, 0, 0))
source = dc.sources.Dipole(
    receiver_list=[receiver], location_a=(-2, 0, 0), location_b=(2, 0, 0)
)
survey = dc.Survey([source])
# Use the default solver in the simulation
simulation = dc.Simulation3DNodal(mesh=mesh, survey=survey, solver=solver)
Note
The priority list used to choose a default solver is:
- Pardiso
- Mumps
- SolverLU
Setting solvers manually#
Alternatively, we can manually set a solver. For example, if we want to use
Mumps in our DC resistivity simulation, we can import
pymatsolver.Mumps and pass it to our simulation:
import simpeg.electromagnetics.static.resistivity as dc
from pymatsolver import Mumps
# Manually set Mumps as our solver
simulation = dc.Simulation3DNodal(mesh=mesh, survey=survey, solver=Mumps)
Note
When sharing your notebook or script with a colleague, keep in mind that
your code might not work if Pardiso is not available in their system.
For such scenarios, we recommend using the
simpeg.utils.get_default_solver() function, that will always return
a suitable solver for the current system.
Ultimately, choosing the best solver is a mixture of the problem you are solving and your current system. Experiment with different solvers yourself to choose the best.
