Version:
This tutorial is presented as Python code running inside a Jupyter Notebook, the recommended way to use Salvus. To run it yourself you can copy/type each individual cell or directly download the full notebook, including all required files.

Point Sources and Receivers for the Wave Equation

Without injected energy there is nothing to simulate and the most common scenario is to do this at individual points. Point evaluations of the resulting wavefield are similarly the most widely used output of waveform simulations. Salvus is particularly flexible in this regard and the tutorials in this section will explain all possible options.
SalvusCompute internally operates in Cartesian x, y(, z) coordinates and thus everything has to be specified in this reference system. For simple domains this is no problem, but for complicated, unstructured domains using higher order shape functions for the individual elements this poses a significant challenge.
This notebook explains the straightforward case of directly specifying the coordinates and other parameters. It is also possible to specifiy coordinates relative to specific surfaces in a mesh and in a seismological reference system. For this, please have a look at the other tutorials.
We will again use SalvusFlow's simple_config interface.
Copy
# 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 SalvusFlow. This is completely optional and a convenience
# option.
%config Completer.use_jedi = False

import os
from salvus.flow import simple_config

SALVUS_FLOW_SITE_NAME = os.environ.get("SITE_NAME", "local")

Receivers

There are two basic receiver classes:
  • simple_config.receiver.cartesian.Point2D
  • simple_config.receiver.cartesian.Point3D
The only difference is that (as the name implies) one is for 2D simulations, and the other one for 3D simulations. Otherwise they behave identically. Like all objects in the simple_config, it is not possible to initialize invalid objects.
rec = simple_config.receiver.cartesian.Point2D(
    # Cartesian coordinates.
    x=2000.0,
    y=2000.0,
    # The network is optional but helps to group receivers.
    network_code="XX",
    # The name of the receiver.
    station_code="A1",
    # An additional level to group receivers.
    location_code="",
    # At least one output field is required. More are possible.
    # Have a look at the API documentation for a list of all
    # available fields.
    fields=["displacement", "acceleration"],
)

# They are internally represented as dictionaries exactly
# corresponding to what SalvusCompute demands.
print(rec)
{'fields': ['displacement', 'acceleration'],
 'location': [2000.0, 2000.0],
 'location_code': '',
 'network_code': 'XX',
 'station_code': 'A1'}
Source by necessity are a bit more complicated. As of new we support 4 types of point sources, in 2 as well as 3 dimensions, with self-explaining names.

Sources in acoustic media

  • simple_config.source.cartesian.ScalarPoint2D
  • simple_config.source.cartesian.ScalarPoint3D
  • simple_config.source.cartesian.ScalarGradientPoint2D
  • simple_config.source.cartesian.ScalarGradientPoint3D

Source in elastic media

  • simple_config.source.cartesian.VectorPoint2D
  • simple_config.source.cartesian.VectorPoint3D
  • simple_config.source.cartesian.MomentTensorPoint2D
  • simple_config.source.cartesian.MomentTensorPoint3D
src = simple_config.source.cartesian.VectorPoint2D(
    # Coordinates of the source.
    x=500.0,
    y=1000.0,
    # Force vector in x and y direction in Nm.
    fx=1e5,
    fy=-1e4,
    # It also requires a source time function.
    source_time_function=simple_config.stf.Ricker(center_frequency=1.0),
)

# They are again internally represented as a dictionary.
print(src)
{'location': [500.0, 1000.0],
 'source_time_function': {'center_frequency': 1.0, 'wavelet': 'ricker'},
 'spatial_type': 'vector',
 'spatial_weights': [100000.0, -10000.0]}

Source time functions

SalvusCompute as of now supports 4 parameterized source time functions as well as a custom source time function. A source object cannot be initialized without one.
  • simple_config.stf.Delta
  • simple_config.stf.GaussianRate
  • simple_config.stf.Heaviside
  • simple_config.stf.Ricker
  • simple_config.stf.Custom
Our Python based configuration interface is now used to assemble mesh, source, and receiver into a single simulation object that can be visualized in the browser.
from salvus.mesh import simple_mesh

m = simple_mesh.CartesianHomogeneousIsotropicElastic2D(
    vp=2000.0,
    vs=1500.0,
    rho=2000.0,
    x_max=3000.0,
    y_max=2000.0,
    max_frequency=2.0,
)

w = simple_config.simulation.Waveform(mesh=m.create_mesh())
w.add_receivers(rec)
w.add_sources(src)
w
<salvus.flow.simple_config.simulation.waveform.Waveform object at 0x7fc65bb12950>
This can now finally be used to actually run the simulation.
import salvus.flow.api

salvus.flow.api.run(
    site_name=SALVUS_FLOW_SITE_NAME, input_file=w, output_folder="output"
)
SalvusJob `job_2403150917329782_33b2735591` running on `local` with 4 rank(s).
Site information:
  * Salvus version: 0.12.16
  * Floating point size: 32
-> Current Task: Time loop complete* Downloaded 17.9 KB of results to `output`.
* Total run time: 1.93 seconds.
* Pure simulation time: 1.44 seconds.
<salvus.flow.sites.salvus_job.SalvusJob at 0x7fc72cf90610>
PAGE CONTENTS