Version:

This documentation is not for the latest stable Salvus 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.

Full-Waveform Inversion

Part 2 - Initial model and synthetics

We can easily split the workflow into multiple notebooks. Reloading the project from disk will continue at exactly the same stage where we have stopped in the first part.
Copy
%matplotlib inline
# This notebook will use this variable to determine which
# remote site to run on.
import os
import salvus.namespace as sn
--> Server: 'https://data.mondaic.com/license_server/licensing_server', User: '_MONDAIC_INTERNAL_', Group: '_MONDAIC_INTERNAL_'.
--> Negotiating 1 license instance(s) for 'SalvusMesh' [license version 1.0.0] for 1 seconds ...
--> Success! [Total duration: 0.58 seconds]
SALVUS_FLOW_SITE_NAME = os.environ.get("SITE_NAME", "local")
p = sn.Project(path="project")
Now, it is actually time to focus on the inversion.
How do we start? Well, we need a model of course.
What do we already know about the medium? Let's pretend we haven't seen the figures above and have no idea about the phantom. The best prior knowledge we have is that the domain is filled with water and we assume that the speed of sound is 1500 m/s and the density is 980 kg/m^3.
We create a homogeneous background model and set up a simulation configuration that contains the same events as the true data.
bm = sn.model.background.homogeneous.IsotropicAcoustic(vp=1500.0, rho=980.0)
mc = sn.ModelConfiguration(background_model=bm)
wsc = sn.WaveformSimulationConfiguration(end_time_in_seconds=0.00015)

p += sn.SimulationConfiguration(
    name="initial_model",
    #
    # Settings that influence the mesh.
    elements_per_wavelength=2,
    tensor_order=2,
    max_frequency_in_hertz=100000.0,
    #
    model_configuration=mc,
    # Potentially event dependent settings.
    event_configuration=sn.EventConfiguration(
        waveform_simulation_configuration=wsc,
        wavelet=sn.simple_config.stf.Ricker(center_frequency=50000.0),
    ),
)
With the model in hand, we could start iterating right away if we were brave enough. However, in all relevant cases we would want to do some quality checks first before burning many CPU hours. So let's start by just looking at the synthetic waveforms that the initial model produces.
p.simulations.launch(
    simulation_configuration="initial_model",
    events=p.events.get_all(),
    site_name=SALVUS_FLOW_SITE_NAME,
    ranks_per_job=4,
)
[2021-10-19 10:02:17,212] INFO: Creating mesh. Hang on.
[2021-10-19 10:02:17,635] INFO: Submitting job array with 5 jobs ...
5
p.simulations.query(block=True)
True
synthetic_data = p.waveforms.get(
    data_name="initial_model", events=p.events.get_all()
)
synthetic_data[0].plot(component="A", receiver_field="phi")
p.viz.nb.waveforms(
    ["true_model_100kHz", "initial_model"], receiver_field="phi"
)
This looks alright, and we are moving on to the next step and compute initial misfits and gradients.
PAGE CONTENTS