Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@santisoler
Copy link
Member

Summary

Add a new page to the How to Guide that explains how to move a mesh to a given survey area. This is handy when working with real-world data, whose coordinates are going to be given in projected plain coordinates.

PR Checklist

  • If this is a work in progress PR, set as a Draft PR
  • Linted my code according to the style guides.
  • Added tests to verify changes to the code.
  • Added necessary documentation to any new functions/classes following the
    expect style.
  • 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

What does this implement/fix?

Additional information

Add a new page to the How to Guide that explains how to move a mesh to
a given survey area. This is handy when working with real-world data,
whose coordinates are going to be given in projected plain coordinates.
@codecov
Copy link

codecov bot commented Sep 16, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 86.22%. Comparing base (f0086d1) to head (9499e8e).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1699      +/-   ##
==========================================
- Coverage   86.22%   86.22%   -0.01%     
==========================================
  Files         433      433              
  Lines       56199    56199              
  Branches     5219     5219              
==========================================
- Hits        48459    48457       -2     
- Misses       6341     6342       +1     
- Partials     1399     1400       +1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@jcapriot
Copy link
Member

As a corollary, how about moving survey to mesh?

@santisoler
Copy link
Member Author

Do you mean moving sources and receivers to the default location of the mesh (around 0, 0, 0)?

@jcapriot
Copy link
Member

Yeah, or on a centered mesh with origin an ‘CCN’

@santisoler santisoler added this to the 0.25.0 milestone Sep 22, 2025
@santisoler
Copy link
Member Author

That could be a good addition. I think the goal of this page is to address a common question that users have: "how to locate the mesh in the coordinates of the survey", from a more applied point of view. I'd recommend practitioners to move the mesh rather than the survey, so at least for now I think I'd prefer to keep only this guide, just to avoid any confusion of what is the preferred method.

My point is having the mesh in the survey coordinates ultimately simplify workflows: mesh slices and plots will be already in survey coordinates, exported meshes (that sometimes are opened with other software like Geoscience ANALYST) are already in those coordinates.

@santisoler santisoler merged commit 42a5db9 into main Sep 26, 2025
22 checks passed
@santisoler santisoler deleted the move-mesh-to-survey branch September 26, 2025 20:46
@ahmedbeshr93
Copy link

I am moving the mesh to the location of the survey by doing the following:

Width of magnetic survey

x_width = np.max(x_ds) - np.min(x_ds)
y_width = np.max(y_ds) - np.min(y_ds)
width_max = np.maximum(x_width, y_width)

Midpoint of magnetic survey

x_midpoint = (np.max(x_ds) + np.min(x_ds)) / 2
y_midpoint = (np.max(y_ds) + np.min(y_ds)) / 2
xy_midpoint = np.array([x_midpoint, y_midpoint])

Core cell size

cell_size_x, cell_size_y, cell_size_z = 50, 50, 50

Domain width in each directions

pad_thk = 1 * width_max
domain_width = width_max + 2 * pad_thk

Calculate the number of core cells required to fill the domain in each direction

n_cells_x = int(2np.round(np.log(domain_width / cell_size_x) / np.log(2)))
n_cells_y = int(2
np.round(np.log(domain_width / cell_size_y) / np.log(2)))
n_cells_z = int(2**np.round(np.log(domain_width / cell_size_z) / np.log(2)))

hx = [(cell_size_x, n_cells_x)]
hy = [(cell_size_y, n_cells_y)]
hz = [(cell_size_z, n_cells_z)]

Calculate domain effective width

domain_eff_width_x = utils.unpack_widths(hx).sum()
domain_eff_width_y = utils.unpack_widths(hy).sum()
domain_eff_width_z = utils.unpack_widths(hz).sum()

Define the mesh origin = mesh bottom-left-frontmost corner

mesh_origin_x = int(np.round(x_midpoint - domain_eff_width_x / 2))
mesh_origin_y = int(np.round(y_midpoint - domain_eff_width_y / 2))
mesh_origin_z = int(np.round(np.max(z_Topo) - domain_eff_width_z / 2))
mesh_origin = (mesh_origin_x, mesh_origin_y, mesh_origin_z)

Create the base mesh

mesh = TreeMesh(h=[hx, hy, hz], origin=mesh_origin, diagonal_balance=True)

Refine surface topography

mesh.refine_surface(xyz=SRTM_DEM, level=-1, padding_cells_by_level=None, diagonal_balance=True, finalize=False)

Refine around receiver locations

mesh.refine_points(points=xyz_TEM_ds, level=-1, padding_cells_by_level=[1], diagonal_balance=True, finalize=False)

Refine region of interest

x_core_min = np.min(x_ds) - 0 * cell_size_x
x_core_max = np.max(x_ds) + 0 * cell_size_x
y_core_min = np.min(y_ds) - 0 * cell_size_y
y_core_max = np.max(y_ds) + 0 * cell_size_y
z_core_min = np.max(z_Topo) - 1000 # up to a depth of 1000 m
z_core_max = np.max(z_Topo)

meshgrid_x_core, meshgrid_y_core, meshgrid_z_core = np.meshgrid([x_core_min, x_core_max], [y_core_min, y_core_max], [z_core_min, z_core_max])
xyz_core_edge_points = np.c_[mkvc(meshgrid_x_core), mkvc(meshgrid_y_core), mkvc(meshgrid_z_core)]

mesh.refine_bounding_box(points=xyz_core_edge_points, level=-1, padding_cells_by_level=None, diagonal_balance=True, finalize=False)

mesh.finalize()

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.

4 participants