SimPEG v0.25.0 Release Notes#

October 22nd, 2025

Updates#

New features#

New differential simulation for magnetic fields#

This release ships with a new and improved version of the magnetic differential simulation Simulation3DDifferential by @johnweis0480. This simulation computes the magnetic field on every cell of the mesh by numerically solving the magnetostatic PDE. It accounts for self-demagnetization effects, model both induced and remanent magnetizations, and is faster and less memory intensive than the integral simulation for large problems.

See simpeg/simpeg#1682 for more details.

Add utility function to shift electrodes to discrete topography#

A new simpeg.utils.shift_to_discrete_topography() function shifts locations relative to discrete surface topography. When performing MT surveys, we measure electric fields at the Earth’s surface. Similar to DC/IP, the original measurement locations of the electric fields can end up in air cells when we discretize surface topography. This function allows the user to shift locations relative to discrete topography on Tensor and Tree meshes. For Airborne NSEM, they also allow the user to preserve the original flight heights.

See simpeg/simpeg#1683 for more details.

Calculate B/H fields with a step-off waveform closed-loop wire source in TDEM#

We can now calculate the B and H fields using a closed-loop wire as source in the TDEM code with a step-off waveform. The simulation will first compute the vector potential using the Biot-Savart Law and then take the curl of it to get the initial \(\mathbf{B}\) field.

See simpeg/simpeg#1651 for more details.

Sensitivity matrix as a LinearOperator in gravity and magnetic equivalent layers#

Gravity and magnetic equivalent sources can now define the sensitivity matrix J as a scipy.sparse.linalg.LinearOperator when store_sensitivities="forward_only". This extends the behaviour previously implemented in the integral gravity and magnetic simulations to the equivalent layer classes.

See simpeg/simpeg#1674 and simpeg/simpeg#1676 for more details.

Choosing the default solver is easier now#

The get_default_solver() can now be imported directly from simpeg.utils making it easier to use it.

Check out the new How to Guide on Choosing solvers for more information on how we can use this function.

Improved inversion printout#

The information table displayed during an inversion has been improved. Now, the zero-th iteration corresponds to the status of the inversion problem before any optimization steps, while subsequent iterations show information after each iteration but before directives are applied. The final iteration of the inversion is shown in the last row of the table. Additionally, some non-very-useful messages have been removed to produce a cleaner output.

See simpeg/simpeg#1626 for more details.

Standardized directives for saving outputs#

Directives that store and save inversion outputs have been standardized and made more reliable. They now respect the output directory chosen by the user, and output filenames follow a standardized name-timestamp-iteration format to make it easier to sort and identify files from different inversions.

See simpeg/simpeg#1657 for more details.

Updates to the Conjugate Gradient minimizers#

The conjugate gradient minimizers were updated to be consistent with the latest versions of SciPy. They can now accept both relative and absolute tolerances through the cg_rtol and cg_atol arguments, respectively.

The tolCG argument will be removed in the future, making cg_rtol and cg_atol the preferred way to set tolerances in these minimizers.

See simpeg/simpeg#1656 for more details.

Documentation#

This release introduces a fresh new landing page for SimPEG docs, and a new How to Guide section in our SimPEG User Guide with pages on Choosing solvers and Locating mesh on survey area.

We also included a new page that clarifies Python and Numpy Version compatibility with SimPEG, and explain the criteria for dropping older versions of our dependencies.

We started removing the gravity, magnetic and DC tutorials from SimPEG’s docs, as part of our plan of moving all tutorials to our User Tutorials.

Now we can navigate our docs using our arrow keys in the keyboard (for those power users that don’t want to leave the keyboard) thanks to @prisae.

Finally, we improved and fixed a few things in the docs: mathematical expressions, added missing classes to the API reference, updated admonitions in docstrings, and more.

Bugfixes#

In this release we included a few bugfixes:

Breaking changes#

We introduced a few breaking changes in SimPEG v0.25.0.

Dropped support for Python 3.10#

We dropped support for Python 3.10, inline with our Version compatibility schedule. So, remember to use Python 3.11 or higher when installing SimPEG v0.25.0. If you still need to use Python 3.10, please pin your SimPEG version to v0.24.0.

Modified how mappings are applied in regularizations#

We updated how mappings are applied in most of our regularization classes (WeightedLeastSquares, Smallness, SmoothnessFirstOrder, Sparse, etc.). The mapping was applied, for example in the Smallness regularization, to the difference between the model and the reference_model:

\[\phi (\mathbf{m}) = \left\lVert \mathbf{W} \left[ \mu(\mathbf{m} - \mathbf{m}^\text{ref}) \right] \right\rVert^2.\]

where \(\mu()\) is the mapping.

Since SimPEG v0.25.0 the regularizations are applied to the difference between the mapped model and the mapped regularization model:

\[\phi (\mathbf{m}) = \left\lVert \mathbf{W} \left[ \mu(\mathbf{m}) - \mu(\mathbf{m}^\text{ref}) \right] \right\rVert^2.\]

This impacts only non-linear mappings, since the two expressions are equivalent for linear ones.

Changed the output of get_indices_block()#

The get_indices_block() function previously returned a tuple with just a single element: the array with cell indices that correspond the given block. We standardized its output to be in agreement with similar functions in the module. It now returns a single NumPy array with the cell indices of the block.

If you were using this function as follows, where you used to extract the first element of the tuple:

ind = get_indices_block(p0, p1, mesh.cell_centers)[0]

You’ll need to update it to:

ind = get_indices_block(p0, p1, mesh.cell_centers)

An informative warning will be printed out every time the function is used to remind users of this new behaviour.

Removals#

We also removed several deprecated items marked for removal in previous releases, including:

  • The Data.index_dictionary property. Use the new get_slice method of Survey (for example: simpeg.potential_fields.gravity.Survey.get_slice()).

  • The gtg_diagonal property from gravity simulation.

  • The components property from gravity and magnetic surveys.

Contributors#

Contributors:

Pull Requests#