Please note that the underlying theory for this 3D-to-2D conversion can be found within the following two publications and the references therein:Forbriger, T., L. Groos, M. Schäfer (2014). Line-source simulation for shallow-seismic data. Part 1: theoretical background. Geophysical Journal International, 198(3), 1387-1404. https://dx.doi.org/10.1093/gji/ggu199Schäfer, T., M., L. Groos, T. Forbriger, T. Bohlen (2014). Line-source simulation for shallow-seismic data. Part 2: full-waveform inversion — a synthetic 2-D case study. Geophysical Journal International, 198(3), 1405-1418. https://dx.doi.org/10.1093/gji/ggu171
PROJECT_DIR = "project"
import matplotlib.pyplot as plt
import numpy as np
import salvus.namespace as sn
from salvus.modules.near_surface.processing import convert_point_to_line_source
p = sn.Project(path=PROJECT_DIR)
obspy.Stream
containing the information about the traces we want to apply the processing to along with the Salvus source/receiver objects.ProcessingConfiguration
which specifies which data we want to apply the processing to in addition to the callback function itself.velocity_m_s
: Reference velocity for the medium. While this theoretically assumes that the medium consists of a homogeneous full-space, using an average of the velocities within the top portion of the medium generally seems to yield adequate results.hybrid_transformation_transition_zone
: The distances within which each transform should be applied. In this case, hybrid_transformation_transition_zone
should be a list of distances where the the single-velocity method is applied to the receivers below the first value in the transition zone while the direct-wave method is applied to the receivers beyond the second value in the transition zone.velocity_m_s
by averaging the "VS"
from our initial model over the first ~5.0 m depth of the model. We start by getting the mesh of the starting model.m = p.simulations.get_mesh("volumetric_model")
"VS"
over this depth range.depth = -5.0
field = "VS"
# Create a mask of the elements which are above a depth of 5.0 m
mask = m.get_element_centroid()[:, 1] > -5.0
# Take the mean of the "VS" for the masked out elements
velocity_m_s = np.mean(m.elemental_fields[field][mask, :])
print(
f"The average `{field}` above {np.abs(depth)} m is {np.round(velocity_m_s, 1)} m/s"
)
The average `VS` above 5.0 m is 166.9 m/s
def processing_3d_to_2d(st, sources, receiver):
st = convert_point_to_line_source(
st=st,
source_coordinates=np.array(sources[0].location),
receiver_coordinates=np.array(receiver.location),
transform_type="hybrid",
velocity_m_s=velocity_m_s,
hybrid_transformation_transition_zone=[5.1, 10.1],
)
return st
ProcessingConfiguration
which we will use to apply the 3D-to-2D conversion onto the EXTERNAL_DATA:survey_data
, which was added during the first tutorial of this series.p.add_to_project(
sn.processing.ProcessingConfiguration(
name="calibrated_3d_to_2d",
data_source_name="EXTERNAL_DATA:survey_data",
processing_function=processing_3d_to_2d,
),
overwrite=True,
)
p.viz.shotgather(
data=["EXTERNAL_DATA:survey_data", "PROCESSED_DATA:calibrated_3d_to_2d"],
event=p.events.list()[0],
receiver_field="velocity",
component="X",
)
<Axes: title={'center': 'Event: 00 | field: velocity | component: X'}, xlabel='Receiver Index', ylabel='Time [s]'>
p.viz.nb.waveforms(
data=["EXTERNAL_DATA:survey_data", "PROCESSED_DATA:calibrated_3d_to_2d"],
receiver_field="velocity",
)