Skip to content

Jupyter Notebook

This page is automatically generated from a Jupyter Notebook.

Note that everything here is fully automatically tested against - and thus guaranteed to work - only for the latest versions of all the Salvus packages. So please update if anything works differently on your machine.

Side Set Sources and Receivers for the Wave Equation

The previous tutorial introduced source and receivers for SalvusCompute where the coordinates are already known exactly. In many scenarios this is not necessarily the case. Imaging a mesh with potentially arbitrarily shaped and curved elements and you want to exactly locate a source or receiver relative to the local surface or for example at the ocean bottom. This problem is dependent on the exact mesh used for the simulation.

To this end we offer so called "side set relative" sources and receiver.

# This line helps with tab-completion of the simple_config objects.
# The IPython/Jupyter project default to a differnet inference based
# tab completion engine which unfortunately does not yet fully work
# with salvus_flow. This is completely optional and a convenience
# option.
%config Completer.use_jedi = False

# SalvusFlow and SalvusMesh convenience interfaces.
from salvus_flow import simple_config
from salvus_mesh import simple_mesh

# We'll also use numpy.
import numpy as np

Side Sets

Side set are just a way to flag edges (in 2D) or faces (in 3D) and giving these a name. In SalvusCompute these are used to specify boundary conditions, here we will use them to locate source and receiver relative to them. The following example mesh has 4 side sets, each denoting one side of the mesh. Please note, that the names are arbitrary and mesh dependent.

Side Set Relative Sources and Receivers

The following sketch illustrates how the location of sources and receivers on side sets is specified.

List of Available Classes

The available types of sources and receivers are exactly identical to the ones introduced in the previous tutorial, but prefixed with SideSet and all the coordinates are replaced with a point, direction, side_set_name, and offset parameters.

Receivers

  • simple_config.receiver.cartesian.SideSetPoint2D
  • simple_config.receiver.cartesian.SideSetPoint3D

Sources in Acoustic Media

  • simple_config.source.cartesian.SideSetScalarPoint2D
  • simple_config.source.cartesian.SideSetScalarPoint3D

  • simple_config.source.cartesian.SideSetScalarGradientPoint2D

  • simple_config.source.cartesian.SideSetScalarGradientPoint3D

Sources in Elastic Media

  • simple_config.source.cartesian.SideSetVectorPoint2D
  • simple_config.source.cartesian.SideSetVectorPoint3D

  • simple_config.source.cartesian.SideSetMomentTensorPoint2D

  • simple_config.source.cartesian.SideSetMomentTensorPoint3D

Usage

Let us construct a tad bit of a more complicated mesh - the elements of this mesh have fourth order polynomial shapes, thus finding their surface is a non-trivial undertaking.

m = simple_mesh.Cartesian2D()
m.basic.period = 1500.0
m.basic.model = "prem_iso_no_crust"
m.advanced.tensor_order = 4
mesh = m.create_mesh()

# Add a nice curve to the mesh surface.
# Note how it would not longer be trivial to add sources
# or receivers exactly at the surface of the mesh!
x_range = mesh.points[:, 0].ptp()
mesh.points[:, 1] += \
    np.sin(mesh.points[:, 0] / x_range * 2 * np.pi) * 3E5
mesh

<salvus_mesh.unstructured_mesh.UnstructuredMesh at 0x112fc27f0>
# NBVAL_SKIP
# One receiver at the top, one at the bottom.
recs = [
    simple_config.receiver.cartesian.SideSetPoint2D(
        point=(3e6, 0.0),
        # Locate vertically.
        direction=(0.0, 1.0),
        # Top side set.
        side_set_name="y1",
        # Followed by the normal receiver coordiantes.
        station_code="A1",
        fields=["displacement"]),
    # Second receiver.
    simple_config.receiver.cartesian.SideSetPoint2D(
        point=(5e6, 0.0),
        # Note that the direction vector can also be specified as the
        # name of the coordinate axis.
        direction="y",
        # Bottom
        side_set_name="y0",
        # Followed by the normal receiver coordiantes.
        station_code="A2",
        fields=["displacement"]),
]

srcs = simple_config.source.cartesian.SideSetVectorPoint2D(
        point=[2e6, 0.0],
        direction="y",
        side_set_name="y1",
        # Bury it a bit.
        offset=-2e6,
        fx=1.0, fy=2.0,
        source_time_function=simple_config.stf.Delta())


w = simple_config.simulation.Waveform()
w.set_mesh(mesh)
w.add_receivers(recs)
w.add_sources(srcs)

w
HBox(children=(IntProgress(value=0, description='Locating 2 item(s) on 1 core(s):', max=2, style=ProgressStyle






HBox(children=(IntProgress(value=0, description='Locating 1 item(s) on 1 core(s):', max=1, style=ProgressStyle

<salvus_flow.simple_config.simulation.Waveform object at 0x181ea3bc50>