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 4 - Iterations

Copy
%matplotlib inline
import numpy as np
import os
import salvus.namespace as sn
SALVUS_FLOW_SITE_NAME = os.environ.get("SITE_NAME", "local")
p = sn.Project(path="project")
The inverse problem is a similar entity like all the other configuration objects. We want to be able to keep track of all the individual steps, and avoid unnecessary repetitions of the same task. Fortunately, SalvusProject takes care of data management and book keeping.
We need to specify the prior, which is just the SimulationConfiguration object of the initial model we created above. Furthermore, we need to specify all possible events that we might consider during the inversion. This could be a subset of events defined in the project, and we could add more events later on. Together with the events, we need to pass the observed data. Because we created it synthetically, this is also just a SimulationConfiguration object. The remaining parameters specify which parameters to invert for (VP and RHO), what misfit functional to use, preconditioner and descent method, and where to run the simulations.
p += sn.InverseProblemConfiguration(
    name="my_inversion",
    prior_model="initial_model",
    events=[e.event_name for e in p.events.get_all()],
    mapping=sn.Mapping(scaling="absolute", inversion_parameters=["VP", "RHO"]),
    preconditioner=sn.ConstantSmoothing({"VP": 0.01, "RHO": 0.01}),
    method=sn.TrustRegion(initial_trust_region_linf=10.0),
    misfit_configuration="L2",
    job_submission=sn.SiteConfig(
        site_name=SALVUS_FLOW_SITE_NAME, ranks_per_job=4
    ),
)
Instead of monolithic inversions and a linear flow of iteration, SalvusOpt uses a tree-based framework of iteration. At any point during the inversion, you can branch off, modify the settings, and run one or more streams simultaneously.
Ready for our first iteration? Without specifying any additional information, all parameters will be inherited from the InverseProblemConfiguration.
p.inversions.add_iteration(inverse_problem_configuration="my_inversion")
[2021-07-09 22:31:46,426] INFO: Adding new iteration #0.
True
Many steps within a single iteration involve expensive simulations, e.g., for computing misfits or adjoint simulations to compute gradients. In order to be able to closely monitor the progress, SalvusOpt steps through an iteration, and automatically dispatches simulations whenever necessary. The function resume will return whenever SalvusOpt is waiting for other tasks to finish first. Calling it several time, will step through the iteration in sequence.
p.inversions.resume(
    inverse_problem_configuration="my_inversion",
)
[2021-07-09 22:31:46,485] INFO: Resuming iteration #0.
Current stage: initialize
[2021-07-09 22:31:46,486] INFO: 1 new tasks have been issued.
[2021-07-09 22:31:46,487] INFO: Processing task `misfit_and_gradient`
p.inversions.resume(
    inverse_problem_configuration="my_inversion",
)
[2021-07-09 22:31:47,128] INFO: Resuming iteration #0.
Current stage: check_convergence
[2021-07-09 22:31:47,129] INFO: Processing task `misfit_and_gradient`
[2021-07-09 22:31:47,751] INFO: 
Iteration 0: Number of events: 5	 chi = 0.017689824583734397	 ||g|| = 0.027660701959153447
pred = ---	ared = ---	norm_update = ---	tr_radius = ---
p.viz.nb.iteration(
    inverse_problem_configuration="my_inversion", iteration_id=0
)
If you feel confident and don't want to be bothered with every single task, you can also tell SalvusOpt to run an entire iteration at once. Note the parameter timeout_in_seconds, which will force the cell to return even if the iteration has not been completed yet, and there might still be a few simulations running in the back.
Again, you can execute the cell several times or mix it with calls to the previous one until the iteration is complete.
p.inversions.iterate(
    inverse_problem_configuration="my_inversion",
    timeout_in_seconds=360,
    ping_interval_in_seconds=10,
)

p.viz.nb.inversion(inverse_problem_configuration="my_inversion")
[2021-07-09 22:31:49,024] INFO: Resuming iteration #0.

[2021-07-09 22:31:49,037] INFO: 1 new tasks have been issued.
[2021-07-09 22:31:49,037] INFO: Processing task `preconditioner`

[2021-07-09 22:31:59,410] INFO: Processing task `preconditioner`
[2021-07-09 22:31:59,676] INFO: 1 new tasks have been issued.
[2021-07-09 22:31:59,677] INFO: Processing task `misfit`
[2021-07-09 22:31:59,818] INFO: Submitting job array with 5 jobs ...

[2021-07-09 22:32:00,113] INFO: Launched simulations for 5 events. Please check again to see if they are finished.
[2021-07-09 22:32:10,162] INFO: Processing task `misfit`
[2021-07-09 22:32:10,357] INFO: Some tasks of iteration #0 are still running. Please check again later.
[2021-07-09 22:32:20,407] INFO: Processing task `misfit`
[2021-07-09 22:32:21,984] INFO: 
old misfit control group: 0.017689824583734397
new misfit control group: 0.006267217062432136
predicted reduction control group: -0.012011166512076208
actual reduction control group: -0.011422607521302261
5 out of 5 event(s) improved the misfit.
[2021-07-09 22:32:21,986] INFO: 
Model update accepted.
[2021-07-09 22:32:22,067] INFO: Succesfully completed iteration #0.
[2021-07-09 22:32:22,069] INFO: Adding new iteration #1.