Skip to content

GEOPY-3115: Update SimPEG to 0.26 - #176

Merged
domfournier merged 77 commits into
developfrom
GEOPY-3115
Oct 31, 2026
Merged

domfournier merged 77 commits into
developfrom
GEOPY-3115

Conversation

@domfournier

@domfournier domfournier commented Oct 27, 2026 •

Copy link
Copy Markdown

GEOPY-3115 - Update SimPEG to 0.26

GrindingTheophile and others added 30 commits January 26, 2026 23:10
Fix bug in EM1D simulations through which if at least one element of the
chargeability array was zero, the IP effects weren't taken into account
when computing the complex conductivity matrix. Improve documentation,
specifying that the Pelton-Cole equation that is implemented makes use
of the conductivity at infinity frequency (and not zero frequency). Add
tests for the bugfix.

---------

Co-authored-by: Santiago Soler <santisoler@fastmail.com>
Hide the warning when the function is called within another function.
There's nothing actionable that users need to do or know about the
`get_indices_block` function when it's being called from within another
function.
Fix bug on `compute_complex_mu`: when `dchi` has at least one null
value, the VRM effects were not taken into account, returning only real
values of `mu`. Fix the bug by making the right check for all null
values in `dchi`. Add test for the bugfix.
#### Summary
Fix for an issue where a DC resistivity inversion prediction has wrong
output size because a return statement returns a vector product rather
than a scalar product. Resolves issue simpeg#1712 .

Error: When running a 3D DC resistivity inversion, if one specifies a
Pole-Dipole configuration then the receiver evaluation method fails
because it tries to populate a slice of dpred (dpred[src_rx_slice]) with
a flattened matix: mkvc(rx.eval(src, self.mesh, f))) that has an
inconsistent shape.

Source of error: The source of the error stems from the fact that
currently, rx.eval() returns a (nrx,nrx) matrix, where nrx is the number
of receivers. The output should instead be of shape (nrx,1). The reason
rx.eval() returns a (nrx,nrx) matrix rather than a a (nrx,1) matrix is
because it returns "v / self.geometric_factor[src]", where both v and
self.geometric_factor[src] are vectors of length nrx, but it does a
matrix division rather than a scalar devision.

Solution: Various solutions to change the math output to scalar
division. My working suggestion is:
Replace: "return v / self.geometric_factor[src]" on L188 of
simpeg/electromagnetics/static/resistivity/receivers.py
with: "return v / self.geometric_factor[src].reshape(-1, 1)" where the
reshape forces the operation to be scalar rather than vector, causing
the returned value to be of shape (nrx,1) rather than (nrx,nrx).

#### PR Checklist
* [X] If this is a work in progress PR, set as a Draft PR
* [X] Linted my code according to the [style
guides](https://docs.simpeg.xyz/latest/content/getting_started/contributing/code-style.html).
* [X] Added
[tests](https://docs.simpeg.xyz/latest/content/getting_started/contributing/testing.html)
to verify changes to the code.
* [X] Added necessary documentation to any new functions/classes
following the
expect
[style](https://docs.simpeg.xyz/latest/content/getting_started/contributing/documentation.html).
* [X] Marked as ready for review (if this is was a draft PR), and
converted
      to a Pull Request
* [X] Tagged ``@simpeg/simpeg-developers`` when ready for review.

#### Reference issue
<!--Example: write "Closes simpeg#1712" to automatically close that issue on
merge.-->

#### What does this implement/fix?
Replaced: "return v / self.geometric_factor[src]" on L188 of
simpeg/electromagnetics/static/resistivity/receivers.py
with: "return v / self.geometric_factor[src].reshape(-1, 1)" where the
reshape forces the operation to be scalar rather than vector, causing
the returned value to be of shape (nrx,1) rather than (nrx,nrx).

---------

Co-authored-by: Santiago Soler <santisoler@fastmail.com>
Co-authored-by: Joseph Capriotti <josephrcapriotti@gmail.com>
Improve the docs of `Survey.drape_electrodes_on_topography` and
`shift_to_discrete_topography`. Raise `TypeError` if the mesh is not a
`TreeMesh` or a `TensorMesh`, instead a `NotImplementedError`.
Change order of some steps in the release checklist.
Add changelog for path release of SimPEG: v0.25.1.
User lowercase SimPEG in the PyPI link.
#### Summary
This pull request adds the functionality to simulate and invert
admittance and tipper data for 2D problem geometry.

#### PR Checklist
* [x] If this is a work in progress PR, set as a Draft PR
* [x] Linted my code according to the [style
guides](https://docs.simpeg.xyz/latest/content/getting_started/contributing/code-style.html).
* [x] Added
[tests](https://docs.simpeg.xyz/latest/content/getting_started/contributing/testing.html)
to verify changes to the code.
* [ ] Added necessary documentation to any new functions/classes
following the
expect
[style](https://docs.simpeg.xyz/latest/content/getting_started/contributing/documentation.html).
* [ ] Marked as ready for review (if this is was a draft PR), and
converted
      to a Pull Request
* [ ] Tagged ``@simpeg/simpeg-developers`` when ready for review.

#### What does this implement/fix?
This pull request adds the functionality to simulate and invert
admittance and tipper data for 2D problem geometry.

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Santiago Soler <santisoler@fastmail.com>
Replace deprecated `newshape` argument for `shape` in `numpy.reshape`.
Replace the usage of the deprecated function `numpy.in1d` for
`numpy.isin`.

Fix bug in Richard's empirical classes: fix the order of operations
between projection matrices (as `spmatrix`) and 1D arrays. Use the `@`
operator to explicitly trigger a dot product between them. This way, the
`__call__` methods of such classes return always an ndarray with the
same shape as `u` (and not a `np.matrix`). Patch the
`SimulationNDCellCentered.Jfull` to convert the `J` `np.matrix` into an
array.

Patch FDEM example to avoid using `np.diff` and then having to unpack
the resulting array.

---------

Co-authored-by: Joseph Capriotti <josephrcapriotti@gmail.com>
Fix issue of equations not being correctly rendered.
Improve type hints of arguments of `distance_weigthing` by replacing the
usage of `Option[...]` for `... | None`, following recommendations
introduced in [PEP604](https://peps.python.org/pep-0604). Fix the
definition of a few arguments in the docstrings: e.g. don't allow the
exponent to be None.
Cherry-pick the commit that added the changelog for v0.25.2.
Fix release date.
Improve the 3D NSEM primary secondary formulation.
More suitable boundary conditions are implemented when solving the 1D
problem that is used as the primary solution on the 3D mesh.

The boundary conditions that are currently used to solve the 1D problem
for the 3D primary-secondary simulation are sub-optimal. As a result,
one needs to pad out excessively when using the 3D primary secondary
formulation to obtain numerically accurate results. Here, more suitable
boundary conditions are implemented to solve the 1D problem.

---------

Co-authored-by: Joseph Capriotti <josephrcapriotti@gmail.com>
Co-authored-by: Santiago Soler <santisoler@fastmail.com>
Remove the `homo1DModelSource` and `analytic1DModelSource` functions in
NSEM source utils since they weren't being used anymore in the code
base. This is related to simpeg#1661, that made these functions obsolete.
#### Summary
use the discretize volume averaging in the tile map so that it is robust
to the scenario where the local mesh is finer than the global one

#### PR Checklist
* [x] If this is a work in progress PR, set as a Draft PR
* [x] Linted my code according to the [style
guides](https://docs.simpeg.xyz/latest/content/getting_started/contributing/code-style.html).
* [x] Added
[tests](https://docs.simpeg.xyz/latest/content/getting_started/contributing/testing.html)
to verify changes to the code.
* [x] Added necessary documentation to any new functions/classes
following the
expect
[style](https://docs.simpeg.xyz/latest/content/getting_started/contributing/documentation.html).
* [x] Marked as ready for review (if this is was a draft PR), and
converted
      to a Pull Request
* [ ] Tagged ``@simpeg/simpeg-developers`` when ready for review.


#### What does this implement/fix?
Right now, if you ended up with a local mesh that had a higher level of
refinement than the global mesh, the tile map will run, but produce
nonsensical results. If we instead use the discretize volume averaging,
it is more stable (test added to show this)
#### Summary
Adds to the PR code checkout step of the `pull_request` github action
that analyzes the pull request code. Neither black, nor flake8 execute
the code they analyze here, so this should be safe to do.

#### Additional information
See
[securely-using-pull_request_target](https://docs.github.com/en/actions/reference/security/securely-using-pull_request_target).
…eg#1772)

#### Summary
While doing some other random work, I found out that the newline
characters in the natural_source/simulation.py file were all CRLF, this
fixes that.
Remove the extra $-i \omega$ factor from the $s_m$ terms in the
docstrings of all FDEM simulation classes and RHS methods.
#### Summary
Adds data types corresponding to the Zyx impedance to and better testing
of receiver types for Simulation1DRecursion

#### What does this implement/fix?
As of right now, any source type and orientation can be used in the
survey for the Simulation1DRecursive class. No matter what is used, the
simulation outputs data corresponding to the Zxy impedance. This is a
problem orientation is set to xx, yx or yy. If orientation is set to xx
or yy, an error should be thrown. If orientation is set to yx, the sign
of the output data is wrong.

This PR adds the functionality required to properly output data
associated with the Zyx impedance. More thorough validation of sources
and receivers upon setting the survey object for the simulation are
added.

---------

Co-authored-by: Santiago Soler <santisoler@fastmail.com>
#### Summary
This PR ensures better stability of the 1D solutions used to generate
the RHSs of NSEM simulations.

#### What does this implement/fix?

In natural_source.utils.source_utils.py, we have two functions
'primary_e_1d_solution' and 'primary_h_1d_solution' which solve the 1D
problem along the vertical discretization used for the 3D simulation. We
add additional padding cells to the bottom to ensure the boundary
conditions at the bottom are respected. There is a problem with the
current implementation.

The extent of the padding for the 1D problem is determined by setting
the number of padding cells. For a tree mesh, the base cell widths is
used and the extent of the padding is reasonable compared to the scale
of the problem. For a tensor mesh, we add an extreme number of very
large cells. If the Dirichlet condition is set as the bottom BC, the
analytic propagator matrix solution is used to solve the 1D problem. For
a tensor mesh with the default number of padding cells, this solution is
unstable.

It would be better to set the extend of the padding for the 1D problem
based on the additional number of skin depths.
Since the Robin condition is more stable, it should be set as the
default option for the bottom BC in both the e_1d and h_1d solution.
This pull request implements this.

---------

Co-authored-by: Santiago Soler <santisoler@fastmail.com>
)

Make `simpeg.utils.download` to only print out messages to stdout if
`verbose` is True. Test the bugfix by mocking `urllib` to avoid
requiring network connection.
#### Summary

Remove the `getSourceTermLineCurrentPolygon` function listed in the
`simpeg/electromagnetics/utils.py` API reference.

#### PR Checklist
* [ ] If this is a work in progress PR, set as a Draft PR
* [ ] Linted my code according to the [style
guides](https://docs.simpeg.xyz/latest/content/getting_started/contributing/code-style.html).
* [ ] Added
[tests](https://docs.simpeg.xyz/latest/content/getting_started/contributing/testing.html)
to verify changes to the code.
* [ ] Added necessary documentation to any new functions/classes
following the
expect
[style](https://docs.simpeg.xyz/latest/content/getting_started/contributing/documentation.html).
* [ ] Marked as ready for review (if this is was a draft PR), and
converted
      to a Pull Request
* [ ] Tagged ``@simpeg/simpeg-developers`` when ready for review.

#### Reference issue
<!--Example: write "Closes #NNNN" to automatically close that issue on
merge.-->

#### What does this implement/fix?
<!--Please explain your changes.-->

#### Additional information
<!--Any additional information you think is important.-->


<!--
Once all tests pass and the code has been reviewed and approved, it will
be merged into main
-->
Move the Contributing guide in the docs from the Getting Started section
into its own section listed after the How to Guide. Redirect old links
to the new location of the Contributing guide to preserve them.
Fix rst syntax in "Merging a Pull Request". Simplify the instructions to
new contributors on how to check their new local installation of SimPEG:
instead of running an old tutorial in the website, instruct them to
import `simpeg` within Python.
Solve bad length in underline of sections (Ruff D409) and mistype of the
`Examples` section in docs.
Update URL to `pymatsolver` in `intersphinx` config: this should enable
Sphinx to create links to `pymatsolver` classes when they are referenced
in SimPEG documentation. Use links to `pymatsolver` and apply some minor
fixes to the Choosing Solvers guide.
Fix `sphinx-gallery` config by passing the `"FileNameSortKey"` string
instead of the actual class. This makes its configuration pickable, and
therefore cacheable.
Add `.github/dependabot.yml` configuration file.
Remove the `pull_request.yml` workflow that checked style and made
`reviewdog` to comment suggestions in Pull Requests to fix those style
issues. Remove some `zizmor` rules added to ignore some warnings related
to the deleted workflow.
dccowan and others added 21 commits October 20, 2026 09:09
#### Summary

This pull request covers the addition of face and edge conductivities to
FDEM and TDEM simulations. Because most of the properties are part of a
base EMsimulation class, work can be done to add this functionality to
static problems in the future. Due to the amount of invertible and
non-invertible properties, we will make new simulation classes to handle
this type of problem, and leave the original EM simulation classes as
is.

#### PR Checklist
* [x] If this is a work in progress PR, set as a Draft PR
* [x] Linted my code according to the [style
guides](https://docs.simpeg.xyz/content/getting_started/contributing/code-style.html).
* [x] Added
[tests](https://docs.simpeg.xyz/content/getting_started/practices.html#testing)
to verify changes to the code.
* [x] Added necessary documentation to any new functions/classes
following the
expect
[style](https://docs.simpeg.xyz/content/getting_started/practices.html#documentation).
* [x] Marked as ready for review (if this is was a draft PR), and
converted
      to a Pull Request
* [x] Tagged ``@simpeg/simpeg-developers`` when ready for review.

#### What does this implement/fix?

* Add the ability to define face and edge conductivities on for 2D and
3D FDEM and TDEM simulations.
* Add the Jvec and Jtvec methods to allow differentiation with respect
to these properties
* Add utilities to project surfaces to tensor and tree meshes

---------

Co-authored-by: Joseph Capriotti <josephrcapriotti@gmail.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Santiago Soler <santisoler@fastmail.com>
…#1812)

Update the HJ implementation of the line current so that the current
flows in the right direction, from locations[0] to locations[-1].
Previously, the EB and HJ formulations had the current flowing in
different directions.

Note that this is a breaking change.

---------

Co-authored-by: Santiago Soler <santisoler@fastmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Replace the usage of the deprecated
`discretize.utils.closest_points_index` function for the
`mesh.closest_points_index` method of meshes. Configure `pytest` to
error out if that warning is thrown when running the tests.
Optimize the `deriv` methods of the parametric maps to avoid building
the sparse matrix if the `v` argument is not `None`. Instead use a new
`columns_dot_vector` utility function that computes the dot product
between a matrix represented as a collection of *columns*. Each one of
these columns can be a 1D array that represents a single column, or a 2D
array that represents a column block in the matrix. The function accepts
a list of pre-allocated matrices, but also a generator that will produce
each one of the columns on the fly during the iterations, will use it to
compute a portion of the total dot product, and discard it later. This
approach allows to reduce memory usage.
#### Summary

`ComboMap`/`SumMap` shapes now propagate through neighboring maps that
have an unconstrained shape (`("*", "*")`) instead of reporting `"*"`
when it's actually resolvable. `maps` is also now a validated, cached
property on both classes.

#### PR Checklist
* [x] If this is a work in progress PR, set as a Draft PR
* [x] Linted my code according to the [style
guides](https://docs.simpeg.xyz/latest/content/getting_started/contributing/code-style.html).
* [x] Added
[tests](https://docs.simpeg.xyz/latest/content/getting_started/contributing/testing.html)
to verify changes to the code.
* [x] Added necessary documentation to any new functions/classes
following the
expect
[style](https://docs.simpeg.xyz/latest/content/getting_started/contributing/documentation.html).
* [x] Marked as ready for review (if this is was a draft PR), and
converted
      to a Pull Request
* [x] Tagged ``@simpeg/simpeg-developers`` when ready for review.

#### Reference issue
N/A

#### What does this implement/fix?

- `ComboMap`/`SumMap` shape resolution now propagates a known dimension
through neighboring maps with shape `("*", "*")`, rather than leaving it
as `"*"`.
- Fixes a `SumMap` bug (comparing a shape tuple to the string `"*"`)
that made it wrongly reject valid combinations of unconstrained +
fixed-shape maps.
- `maps` is now a validated property: an empty list or non-`IdentityMap`
entry raises immediately (`ValueError`/`TypeError`), instead of failing
later with a confusing `IndexError`/`AttributeError`.
- `shape` is computed once when `maps` is set and cached; `.maps` is
stored as an immutable `tuple`.
- **Compatibility note:** shape mismatches are now detected through the
full resolved chain rather than just adjacent raw shapes, so some
internally-inconsistent `ComboMap`s that used to construct fine (and
only fail later when applied) now raise at construction time — see
example 3.

**1. Resolving shape through an unconstrained map**
```python
>>> combo = ComboMap([ExpMap(), Projection(1, np.zeros(5, dtype=int))])
>>> combo.shape
```
`main`: `('*', 1)` &nbsp;→&nbsp; this branch: `(5, 1)`

**2. `SumMap` used to crash on a valid combination**
```python
>>> SumMap([ExpMap(), IdentityMap(nP=7)])
```
`main`: raises `ValueError: Dimension mismatch in map[ExpMap] (*, *) and
map[IdentityMap] (7, 7).` &nbsp;→&nbsp; this branch: succeeds, `.shape
== (7, 7)`.

**3. Inconsistent chain now fails at construction, not at use**
```python
>>> maps_list = [IdentityMap(), IdentityMap(nP=5), IdentityMap(), IdentityMap(nP=10)]
>>> combo = ComboMap(maps_list)
```
`main`: construction succeeds (`shape == ('*', 10)`); only `combo *
np.ones(10)` reveals the problem, raising `ValueError: Dimension
mismatch in IdentityMap(5,5) and np.ndarray(10,)`.
this branch: `ComboMap(maps_list)` itself raises `ValueError: Dimension
mismatch in map[IdentityMap] (*, *) and map[IdentityMap] (10, 10).`

**4. Misusing `.maps` fails fast**
```python
>>> c = ComboMap([IdentityMap(nP=3)])
>>> c.maps = []
```
`main`: accepted silently; `c.shape` later raises `IndexError`.
&nbsp;→&nbsp; this branch: `c.maps = []` itself raises `ValueError:
'maps' must have at least 1 item.`

#### Additional information

Found myself wanting this functionality to validate input sizes in
simpeg#1601, so split it off as it is a good change on its own!

---------

Co-authored-by: Santiago Soler <santisoler@fastmail.com>
…urce `b`, and array `mu` (simpeg#1815)

#### Summary
Four bug fixes in the natural source and frequency domain EM code, each
with a regression test that fails without it. The most consequential is
the 2D NSEM side boundary data on a `TreeMesh`, which was wrong for any
mesh whose bottom isn't at z = 0.

#### PR Checklist
* [x] If this is a work in progress PR, set as a Draft PR
* [x] Linted my code according to the [style
guides](https://docs.simpeg.xyz/latest/content/getting_started/contributing/code-style.html).
* [x] Added
[tests](https://docs.simpeg.xyz/latest/content/getting_started/contributing/testing.html)
to verify changes to the code.
* [x] Added necessary documentation to any new functions/classes
following the
expect
[style](https://docs.simpeg.xyz/latest/content/getting_started/contributing/documentation.html).
* [x] Marked as ready for review (if this is was a draft PR), and
converted
      to a Pull Request
* [x] Tagged ``@simpeg/simpeg-developers`` when ready for review.

#### Reference issue
None.

#### What does this implement/fix?

**1. 2D NSEM side boundary data on a `TreeMesh`.**
`Simulation2DElectricField` and `Simulation2DMagneticField` build 1D
side columns to set their default side boundary data. On a `TreeMesh`,
the column cell widths are rebuilt from the boundary edge centers with
`_centers_to_widths`, which expects positions measured from the bottom
of the mesh, but it was given absolute positions. The widths are only
right when the mesh bottom is at z = 0, which almost no MT mesh has,
since the surface usually sits at z = 0. The fix measures the edge
centers from the bottom of the mesh.

A fully refined `TreeMesh` compared with the identical `TensorMesh`
(layered earth, mesh bottom at −4 km), as maximum error over three
stations:

| | ρa error at 0.1 / 1 / 10 Hz, before | phase error, before | after |
|---|---|---|---|
| xy (`Simulation2DElectricField`) | 1278 / 487 / 12% | up to 41° |
identical |
| yx (`Simulation2DMagneticField`) | 20 / 75 / 16% | up to 32° |
identical |

The existing `TreeMesh` tests only check derivatives and adjoints, which
stay self-consistent with wrong boundary data, so this wasn't caught.

**2. Scalar `sigma_primary` in 3D.** `PlanewaveXYPrimary._get_sigmas`
called `len()` on the primary conductivity before checking for a scalar,
so a scalar `sigmaPrimary` raised in 3D, although the docstring allows
one.

**3. FDEM `b` for several sources at once.**
`Fields3DElectricField._bSecondary` never advanced its column counter
(`i = ii` was missing), so requesting `f[sources, "b"]` scaled every
source with the first source's frequency and wrote it into the first
source's columns. It's harmless while receivers request one source at a
time, but wrong for multi-source requests.

**4. NSEM `h` for an array of permeabilities without a map.**
`_EField._h` and `_hDeriv_u` only gave `mui` a trailing axis when
`muiMap` was set. An array `mu` without a map broadcast against the
source columns, so `h` came out with shape `(n_cells, n_cells)` instead
of `(n_cells, n_sources)`, using the wrong cell's permeability in each
column. The fix broadcasts whenever `mui` is an array.

This PR also corrects the `Simulation1DElectricField` docstring, which
had the electric field on cell centers and the magnetic field on edges.
The class puts the electric field on nodes and the magnetic field on
cell centers.

**Tests:**
- `tests/em/nsem/forward/test_Simulation2D_tree_mesh.py`: both 2D
simulations on a fully refined `TreeMesh` with a negative origin match
the identical `TensorMesh` to 1e-5.
- `tests/em/nsem/forward/test_sources_sigma_primary.py`: a scalar
primary gives the expected 1D and 3D conductivities.
- `tests/em/fdem/forward/test_fields_multiple_sources.py`: `b` for three
sources at different frequencies, requested together, matches each
source's own `b`.
- `tests/em/nsem/forward/test_1D_mu_array.py`: an array `mu` without a
map gives the same `h`, with the right shape, as the same values through
a `muMap`.

---------

Co-authored-by: Santiago Soler <santisoler@fastmail.com>
#### Summary
Adds an optional `store_factors` to the TDEM simulations so the
factorizations get reused between `fields`, `Jvec` and `Jtvec`.

#### PR Checklist
* [x] If this is a work in progress PR, set as a Draft PR
* [x] Linted my code according to the [style
guides](https://docs.simpeg.xyz/latest/content/getting_started/contributing/code-style.html).
* [x] Added
[tests](https://docs.simpeg.xyz/latest/content/getting_started/contributing/testing.html)
to verify changes to the code.
* [x] Added necessary documentation to any new functions/classes
following the
expect
[style](https://docs.simpeg.xyz/latest/content/getting_started/contributing/documentation.html).
* [x] Marked as ready for review (if this is was a draft PR), and
converted
      to a Pull Request
* [ ] Tagged ``@simpeg/simpeg-developers`` when ready for review.

#### Reference issue
Supersedes simpeg#1151.

#### What does this implement/fix?
With `store_factors=True` the factorization of the system matrix is kept
for each unique time step length, and released when the model changes.
`Jtvec` uses the transposed solve (`.T`) of the same factorization. It
defaults to `False` since it costs memory.

This is simpeg#1151 redone on the current `simpeg` layout. The `.T` solve
shares the factorization for `Pardiso` and `Mumps`, but `SolverLU`
currently refactors `A.T` on each `.T` call, so `Jtvec` will be slower
with it until that's fixed in pymatsolver.

#### Additional information
Haven't benchmarked the speedup on this version yet.
Use Python 3.15 as the new default version for the GitHub Actions
workflow that run the tests against the latest Python and dependencies.
Add a new changelog for SimPEG v0.26.0, and add the new version to the
`versions.json` file.

---------

Co-authored-by: Joseph Capriotti <josephrcapriotti@gmail.com>
Co-authored-by: Lindsey Heagy <lindseyheagy@gmail.com>
# Conflicts:
#	.github/dependabot.yml
#	.github/workflows/pull_request.yml
#	.github/workflows/zizmor-security-upstream.yml
#	.pre-commit-config.yaml
#	pyproject.toml
#	simpeg/electromagnetics/natural_source/receivers.py
#	simpeg/electromagnetics/time_domain/fields.py
#	simpeg/maps/_base.py
#	simpeg/regularization/cross_gradient.py
#	zizmor.yml
Copilot AI balanced review requested due to automatic review settings October 27, 2026 21:16
@domfournier

Copy link
Copy Markdown
Author

Related PR on main
simpeg#1836

@github-actions github-actions Bot changed the title GEOPY-3115 GEOPY-3115: Update SimPEG to 0.26 Oct 27, 2026

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Unresolved critical defects cause CI failures, break existing optimizer callers, and produce incorrect phase and saturated-conductivity results.

11 open issues
What changed in this PR

Updates the Mira Geoscience SimPEG fork to 0.26, incorporating API removals, numerical changes, expanded regression coverage, and refreshed development tooling.

Changes:

  • Update simulation, mapping, optimization, and directive APIs.
  • Expand numerical, derivative, adjoint, and multiprocessing tests; migrate examples and tutorials.
  • Refresh Python environments, CI, linting, contributor documentation, and release information.

This pull request requires changes. Unresolved findings include failing CI imports, numerical regressions, incomplete API migrations, and compatibility problems. The findings are noted alongside the affected files below.

File Description
zizmor.yml Whitespace only.
tutorials/​13-joint_inversion/​plot_inv_3_cross_gradient_pf.py Update inversion-output arguments.
tutorials/​12-seismic/​plot_inv_1_tomography_2D.py Update inversion-output arguments.
tutorials/​08-tdem/​plot_inv_1_em1dtm.py Simplify mesh construction and update output arguments.
tutorials/​08-tdem/​plot_fwd_3_tem_3d.py Whitespace only.
tutorials/​08-tdem/​plot_fwd_1_em1dtm_waveforms.py Whitespace only.
tutorials/​07-fdem/​plot_inv_1_em1dfm.py Simplify mesh construction and update output arguments.
tutorials/​07-fdem/​plot_fwd_3_fem_3d.py Whitespace only.
tutorials/​06-ip/​plot_inv_3_dcip3d.py Update inversion-output arguments.
tutorials/​06-ip/​plot_inv_2_dcip2d.py Update output arguments and whitespace.
tutorials/​02-linear_inversion/​plot_inv_2_inversion_irls.py Update inversion-output arguments.
tutorials/​_temporary/​plot_inv_1_em1dtm_stitched_skytem.py Update inversion-output arguments.
tutorials/​_temporary/​plot_4c_fdem3d_inversion.py Update inversion-output arguments.
tests/​utils/​test_mesh_utils.py Check revised mesh-validation errors.
tests/​utils/​test_io_utils.py Whitespace only.
tests/​utils/​test_deprecate.py Whitespace only.
tests/​utils/​test_default_solver.py Test removal of the solver warning argument.
tests/​pf/​test_pf_quadtree_inversion_linear.py Migrate point refinement to mesh methods.
tests/​pf/​test_magnetics_analytics.py Whitespace only.
tests/​pf/​test_mag_vector_amplitude.py Migrate surface refinement to mesh methods.
tests/​pf/​test_mag_nonLinear_Amplitude.py Migrate surface refinement to mesh methods.
tests/​pf/​test_mag_MVI_Octree.py Migrate surface refinement to mesh methods.
tests/​pf/​test_mag_inversion_linear_Octree.py Update surface refinement and padding.
tests/​pf/​test_mag_differential_jvecjtvec.py Replace deprecated box refinement.
tests/​pf/​test_mag_differential_functionality.py Replace deprecated box refinement.
tests/​pf/​test_forward_mag_differential.py Update box refinement and whitespace.
tests/​pf/​test_base_pf_simulation.py Add shared-memory kernel regression tests.
tests/​em/​utils/​test_linecurrents.py Check consistent current directions.
tests/​em/​tdem/​test_TDEM_inductive_permeable.py Whitespace only.
tests/​em/​tdem/​test_large_loop.py Add trapezoidal-waveform loop comparisons.
tests/​em/​static/​test_SPjvecjtvecadj.py Whitespace only.
tests/​em/​static/​test_DC_jvecjtvecadj.py Expand source and apparent-resistivity cases.
tests/​em/​static/​test_DC_Boundaries.py Whitespace only.
tests/​em/​static/​test_DC_2D_jvecjtvecadj.py Expand pole/dipole combinations.
tests/​em/​nsem/​utils/​test_source_utils.py Test invalid primary-field sizes.
tests/​em/​nsem/​inversion/​test_Problem3D_Derivs.py Add absolute comparison tolerance.
tests/​em/​nsem/​inversion/​test_Problem3D_Adjoint.py Whitespace only.
tests/​em/​nsem/​inversion/​test_Problem1D_Derivs.py Refactor tests and cover both impedance orientations.
tests/​em/​nsem/​inversion/​test_NSEM_3D_jvecjtvecadj_pytest.py Expand transfer-function derivative and adjoint cases.
tests/​em/​nsem/​inversion/​test_NSEM_2D_jvecjtvecadj_pytest.py Add admittance and tipper coverage.
tests/​em/​nsem/​forward/​test_sources_sigma_primary.py Test scalar primary conductivity.
tests/​em/​nsem/​forward/​test_Simulation2D_vs_Analytic_pytest.py Expand analytic comparisons and update tolerances.
tests/​em/​nsem/​forward/​test_Simulation2D_tree_mesh.py Compare tree and tensor mesh predictions.
tests/​em/​nsem/​forward/​test_scalar_rho.py Compare scalar and array material properties.
tests/​em/​nsem/​forward/​test_Recursive1D_VsAnalyticHalfspace.py Expand orientation and validation tests. moderate, 3 votes: Line 42 expects 135° for positive yx real/imaginary components; use their actual 45° phase.
tests/​em/​nsem/​forward/​test_Problem3D_VsAnalyticSolution.py Whitespace only.
tests/​em/​nsem/​forward/​test_fields_1d_vs_propagator_pytest.py Cross-check primary fields and boundary conditions.
tests/​em/​nsem/​forward/​test_AnalyticFunctionVsAppResPhs.py Whitespace only.
tests/​em/​nsem/​forward/​test_1D_mu_array.py Test mapped and explicit permeability consistency.
tests/​em/​nsem/​forward/​test_1D_finite_volume.py Whitespace only.
tests/​em/​fdem/​muinverse/​test_muinverse.py Use mesh-based closest-point lookup.
tests/​em/​fdem/​inverse/​test_FDEM_derivs.py Add parameterized derivative tests.
tests/​em/​fdem/​inverse/​test_FDEM_adjoint.py Add parameterized adjoint tests.
tests/​em/​fdem/​inverse/​derivs/​test_FDEM_getJ.py Compare explicit and matrix-free sensitivities.
tests/​em/​fdem/​inverse/​derivs/​test_FDEM_derivs_supplemental.py Add supplemental derivative checks. moderate, 3 votes: Line 31 ignores src, repeating identical expensive checks five times; pass [src] or remove the redundant loop.
tests/​em/​fdem/​inverse/​derivs/​__init__.py Remove the standalone test runner.
tests/​em/​fdem/​forward/​test_permittivity.py Update electric-dipole current directions.
tests/​em/​fdem/​forward/​test_fields_multiple_sources.py Test multi-source field extraction.
tests/​em/​fdem/​forward/​test_FDEM_casing.py Whitespace only.
tests/​em/​fdem/​forward/​test_FDEM_analytics.py Use mesh-based closest-point lookup.
tests/​em/​em1d/​test_bugfix_one_null_eta.py Test IP calculations containing zero chargeability.
tests/​em/​em1d/​test_bugfix_one_null_dchi.py Test VRM calculations containing zero susceptibility changes.
tests/​dask/​test_mag_nonLinear_Amplitude.py Migrate surface refinement to mesh methods.
tests/​dask/​test_mag_MVI_Octree.py Migrate surface refinement to mesh methods.
tests/​dask/​test_mag_inversion_linear_Octree.py Migrate surface refinement to mesh methods.
tests/​base/​test_utils.py Test download verbosity.
tests/​base/​test_maps_utils.py Test column-wise matrix-vector products.
tests/​base/​test_directives.py Update expectations for removed directive APIs.
tests/​base/​test_directives_removals.py Test removal of compatibility modules.
tests/​base/​regularizations/​test_regularization.py Whitespace only.
tests/​base/​regularizations/​test_cross_gradient.py Test the replacement 2D cross-product helper.
simpeg/​utils/​solver_utils.py Remove the deprecated warning argument and modernize annotations.
simpeg/​utils/​model_utils.py Refine distance-weighting annotations and documentation.
simpeg/​utils/​model_builder.py Suppress internal breaking-change warnings.
simpeg/​utils/​mesh_utils.py Clarify topography APIs and unsupported-mesh errors.
simpeg/​utils/​io_utils/​io_utils_general.py Make download logging respect verbosity.
simpeg/​utils/​io_utils/​io_utils_electromagnetics.py Whitespace only.
simpeg/​utils/​code_utils.py Formatting only.
simpeg/​regularization/​jtv.py Whitespace only.
simpeg/​regularization/​cross_gradient.py Replace deprecated NumPy 2D cross-product usage.
simpeg/​potential_fields/​magnetics/​simulation.py Correct docstring section formatting.
simpeg/​potential_fields/​gravity/​simulation.py Correct docstring formatting and whitespace.
simpeg/​potential_fields/​base.py Build parallel sensitivity kernels in shared memory.
simpeg/​optimization.py Remove deprecated options and update CG defaults. critical, 3 votes: At line 1118, removed arguments still used by the SIP inversion helper and a TDEM tutorial now raise NotImplementedError; migrate those callers.
simpeg/​maps/​_utils.py Add column-wise matrix-vector multiplication.
simpeg/​maps/​_parametric.py Avoid constructing full derivatives for vector products.
simpeg/​maps/​__init__.py Export additional mapping classes. critical, 1 vote: Exporting TileMapNested at line 9 breaks automatic map tests because its required arguments are missing; update exclusions or provide a suitable factory.
simpeg/​flow/​richards/​simulation.py Normalize full sensitivities to array output.
simpeg/​flow/​richards/​empirical.py Update conductivity projection calculations. critical, 3 votes: Line 252 casts Ks=0.00944 to zero for integer pressure arrays. critical, 3 votes: Line 536 similarly truncates Ks=24.96 to 24. Preserve conductivity dtype in both broadcasts.
simpeg/​electromagnetics/​viscous_remanent_magnetization/​waveforms.py Update reshape argument usage. moderate, 3 votes: Lines 125 and 279 use shape=, which fails on supported NumPy 1.26 and 2.0; pass the shape positionally.
simpeg/​electromagnetics/​viscous_remanent_magnetization/​survey.py Whitespace only.
simpeg/​electromagnetics/​viscous_remanent_magnetization/​receivers.py Whitespace only.
simpeg/​electromagnetics/​utils/​current_utils.py Correct face-current direction and update closest-point lookup.
simpeg/​electromagnetics/​utils/​__init__.py Remove an obsolete documentation entry.
simpeg/​electromagnetics/​time_domain/​__init__.py Export hierarchical simulations and adjust equations.
simpeg/​electromagnetics/​static/​utils/​static_utils.py Correct source-generator return documentation.
simpeg/​electromagnetics/​static/​spectral_induced_polarization/​receivers.py Replace deprecated NumPy membership testing.
simpeg/​electromagnetics/​static/​spectral_induced_polarization/​__init__.py Whitespace only.
simpeg/​electromagnetics/​static/​resistivity/​survey.py Clarify electrode-draping documentation.
simpeg/​electromagnetics/​static/​resistivity/​receivers.py Normalize geometric-factor broadcasting.
simpeg/​electromagnetics/​static/​resistivity/​__init__.py Export the hierarchical nodal simulation.
simpeg/​electromagnetics/​natural_source/​utils/​test_utils.py Correct background conductivity initialization.
simpeg/​electromagnetics/​natural_source/​utils/​plot_utils.py Whitespace only.
simpeg/​electromagnetics/​natural_source/​utils/​__init__.py Export primary-field utilities.
simpeg/​electromagnetics/​natural_source/​sources.py Update primary-field construction and scalar handling.
simpeg/​electromagnetics/​natural_source/​simulation_1d.py Add survey validation and impedance-orientation handling. critical, 3 votes: Lines 283 and 350 incorrectly negate phase, producing 135° instead of 45° for yx; apply the orientation sign to the complex impedance before arctan2.
simpeg/​electromagnetics/​natural_source/​fields.py Broadcast scalar and array material properties.
simpeg/​electromagnetics/​frequency_domain/​sources.py Reflow documentation text.
simpeg/​electromagnetics/​frequency_domain/​simulation_1d.py Whitespace only.
simpeg/​electromagnetics/​frequency_domain/​fields.py Correct multi-source column offsets and docstrings.
simpeg/​electromagnetics/​frequency_domain/​__init__.py Export hierarchical simulations and revise equations.
simpeg/​electromagnetics/​base_1d.py Correct zero-property checks and document formulations.
simpeg/​electromagnetics/​analytics/​DC.py Adjust a documentation heading.
simpeg/​directives/​sim_directives.py Remove a deprecated import shim.
simpeg/​directives/​pgi_directives.py Remove a deprecated import shim.
simpeg/​directives/​directives.py Remove a deprecated import shim.
simpeg/​directives/​_directives.py Enforce scheduled property and keyword removals.
simpeg/​data.py Correct docstring formatting and whitespace.
simpeg/​base/​__init__.py Export hierarchical PDE infrastructure and property helpers.
simpeg/​__init__.py Document face and edge injection maps.
pyproject.toml Update linting, coverage, and warning configuration. moderate, 1 vote: Line 272 duplicates D406 instead of enabling D407, leaving missing section underlines unchecked.
Makefile Add Ruff and expand combined checks.
examples/​08-vrm/​plot_inv_vrm_eq.py Whitespace only.
examples/​08-vrm/​plot_fwd_vrm.py Whitespace only.
examples/​06-tdem/​plot_0_tdem_analytic.py Whitespace only.
examples/​05-fdem/​plot_inv_fdem_loop_loop_2Dinversion.py Rework core-cell calculations. moderate, 3 votes: Line 101 divides the vertical extent by csx, producing 4 cells instead of 16; divide by csz.
examples/​05-fdem/​plot_0_fdem_analytic.py Whitespace only.
examples/​04-dcip/​plot_dc_analytic.py Whitespace only.
examples/​03-magnetics/​plot_inv_mag_nonLinear_Amplitude.py Update surface refinement and padding.
examples/​03-magnetics/​plot_inv_mag_MVI_VectorAmplitude.py Update refinement and remove debug output.
examples/​03-magnetics/​plot_inv_mag_MVI_Sparse_TreeMesh.py Whitespace only.
examples/​02-gravity/​plot_inv_grav_tiled.py Update refinement and output APIs.
examples/​_archived/​plot_inv_mag_linear.py Update inversion-output arguments.
examples/​_archived/​plot_inv_grav_linear.py Update inversion-output arguments.
environment.yml Update Python and development tools.
docs/​content/​user-guide/​index.rst Reorganize contributor navigation.
docs/​content/​user-guide/​how-to-guide/​choosing-solvers.rst Refresh solver references and guidance.
docs/​content/​user-guide/​getting-started/​version-compatibility.rst Record the last Python 3.11-compatible release.
docs/​content/​user-guide/​getting-started/​contributing/​code-style.rst Remove the old code-style page location.
docs/​content/​user-guide/​contributing/​working-with-github.rst Update relative image paths.
docs/​content/​user-guide/​contributing/​testing.rst Add relocated testing guidance.
docs/​content/​user-guide/​contributing/​setting-up-environment.rst Simplify installation verification.
docs/​content/​user-guide/​contributing/​pull-requests.rst Correct inline markup.
docs/​content/​user-guide/​contributing/​introduction.rst Remove superseded navigation.
docs/​content/​user-guide/​contributing/​documentation.rst Add documentation contribution and build guidance.
docs/​content/​user-guide/​contributing/​code-style.rst Add relocated style guidance, including Ruff.
docs/​content/​user-guide/​contributing/​advanced.rst Add solver-installation guidance.
docs/​content/​release/​index.rst Link additional release notes.
docs/​content/​release/​0.25.2-notes.rst Add patch-release notes.
docs/​content/​release/​0.25.1-notes.rst Add patch-release notes.
docs/​conf.py Update integrations and contributor redirects. moderate, 3 votes: Source keys at line 610 include .html, generating .html.html paths; remove source suffixes, including the index key, while retaining destination suffixes.
docs/​_static/​versions.json Update the documentation version selector.
.pre-commit-config.yaml Update linters and simplify hooks.
.github/​workflows/​test-latest.yml Add latest-Python testing. critical, 2 votes: At line 92, the environment lacks geoh5py and --no-deps prevents installation, causing every test job to fail during import.
.github/​pull_request_template.md Add a final newline.
.github/​ISSUE_TEMPLATE/​release-checklist.md Revise release and compatibility steps.
.github/​dependabot.yml Change dependency-update configuration. moderate, 3 votes: Unresolved conflict markers at line 8 make the YAML invalid; resolve all three markers and retain the intended entries.
.gitattributes Enable automatic text normalization.
.ci/​azure/​test.yml Update the default test interpreter to Python 3.12.
.ci/​azure/​style.yml Update Python and add Ruff checks.
.ci/​azure/​pypi.yml Update packaging jobs to Python 3.12.
.ci/​azure/​docs.yml Update documentation builds to Python 3.12.

Review effort: Balanced

Comment thread .github/workflows/test-latest.yml Resolved
Comment on lines +283 to +285
pm
* (180.0 / np.pi)
* np.arctan2(Z[i_freq].imag, Z[i_freq].real)
P_p, P_n = _get_projections(u) # Compute the positive/negative domains
f_p = P_p * np.ones(len(u)) * Ks # ensures scalar Ks works
f_n = P_n * Ks * A / (A + abs(u) ** gamma)
f_p = P_p @ np.full_like(u, fill_value=Ks)
theta_e = 1.0 / ((1.0 + abs(alpha * u) ** n) ** m)
f_p = P_p * np.ones(len(u)) * Ks # ensures scalar Ks works
f_n = P_n * Ks * theta_e**I * ((1.0 - (1.0 - theta_e ** (1.0 / m)) ** m) ** 2)
f_p = P_p @ np.full_like(u, fill_value=Ks)
Comment thread simpeg/maps/__init__.py Resolved
Comment thread .github/dependabot.yml Resolved
Comment thread docs/conf.py
Comment on lines +610 to +611
redirects = {f"{old}/{f}": f"{new}/{f}" for f in files}
redirects[f"{old}/index.html"] = f"{new}/introduction.html"
ncx = int(np.diff(core_domain_x) / csx)
ncz = int(np.diff(core_domain_z) / csz)
ncx = int((xmax - xmin) / csx)
ncz = int((zmax - zmin) / csx)
Comment on lines +125 to +128
chi0 = np.kron(np.reshape(chi0, shape=(nC, 1)), np.ones((1, nT)))
dchi = np.kron(np.reshape(dchi, shape=(nC, 1)), np.ones((1, nT)))
tau1 = np.kron(np.reshape(tau1, shape=(nC, 1)), np.ones((1, nT)))
tau2 = np.kron(np.reshape(tau2, shape=(nC, 1)), np.ones((1, nT)))
-pm * np.sqrt(np.pi * freq * mu_0 / sigma_half),
1 / sigma_half,
-135.0,
-pm * 135.0,
@domfournier
domfournier merged commit 3611190 into develop Oct 31, 2026
16 checks passed
@domfournier
domfournier deleted the GEOPY-3115 branch October 31, 2026 16:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

10 participants