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 3 - Sensitivities and smoothing

Copy
%matplotlib inline
# This notebook will use this variable to determine which
# remote site to run on.
import os
import time
import salvus.namespace as sn

SALVUS_FLOW_SITE_NAME = os.environ.get("SITE_NAME", "local")
p = sn.Project(path="project")
Before triggering the iterations, most applications necessitate at least some amount of quality control, which makes it inevitable to run a few simulations manually. Let start by computing some misfits for the initial model.
Wait!
Do we actually need to run the simulations again? We have already computed shot gathers for the initial model, haven't we? Let's see what the function call will do.
p += sn.MisfitConfiguration(
    name="L2",
    observed_data="true_model_100kHz",
    misfit_function="L2",
    receiver_field="phi",
)
print(
    p.actions.inversion.compute_misfits(
        simulation_configuration="initial_model",
        misfit_configuration="L2",
        events=p.events.list(),
        store_checkpoints=False,
        site_name=SALVUS_FLOW_SITE_NAME,
        ranks_per_job=4,
    )
)
{'event_0000': 0.023496759816011896, 'event_0001': 0.019519408864323722, 'event_0002': 0.016727805094916563, 'event_0003': 0.012159256871235088, 'event_0004': 0.016545869679131874}
Hm. We did not include any output in the previous run, but since we are now expecting to run an adjoint simulation soon, we had to rerun the forward simulations to store some checkpoints.
If you closely study the output, you will notice that we did not repeat any simulations this time, but just queries the precomputed values.
What's next? Sensitivities!
while not p.actions.inversion.compute_gradients(
    simulation_configuration="initial_model",
    misfit_configuration="L2",
    events=p.events.list(),
    site_name=SALVUS_FLOW_SITE_NAME,
    ranks_per_job=4,
):
    time.sleep(10.0)
[2021-08-05 08:41:16,749] INFO: The following events have been simulated before, but checkpoints are not available for this combination of `site_name` and `ranks_per_job`. They will be run again: ['event_0000', 'event_0001', 'event_0002', 'event_0003', 'event_0004']
[2021-08-05 08:41:16,822] INFO: Submitting job array with 5 jobs ...

[2021-08-05 08:41:17,251] INFO: Launched simulations for 5 events. Please check again to see if they are finished.
[2021-08-05 08:41:38,691] INFO: Submitting job array with 5 jobs ...
[2021-08-05 08:41:38,829] INFO: Launched adjoint simulations for 5 events. Please check again to see if they are finished.
[2021-08-05 08:41:49,289] INFO: 5 events have already been submitted. They will not be submitted again.
[2021-08-05 08:41:49,481] INFO: Some simulations are still running. Please check again to see if they are finished.
[2021-08-05 08:41:59,941] INFO: 5 events have already been submitted. They will not be submitted again.
This function returns individual gradients, which can be useful for event-dependent or batch inversions. Again, take a close look at the verbose output. The forward runs were cached and not repeated to obtain the gradients.
Even better, in 2D you can immediately visualize them in a widget.
p.viz.nb.gradients(
    simulation_configuration="initial_model",
    misfit_configuration="L2",
    events=p.events.list(),
)
We can also obtain the summed gradient over all selected events in one go.
gradient = p.actions.inversion.sum_gradients(
    simulation_configuration="initial_model",
    misfit_configuration="L2",
    events=p.events.list(),
)
gradient