
import os
import os, pathlib
from frequency_band import FrequencyBand
from salvus import namespace as sn
SIMULATION_TIME_IN_SECONDS = 1200.0
SALVUS_FLOW_SITE_NAME = os.environ.get("SITE_NAME", "local")
RANKS_PER_JOB = 4
PROJECT_DIR = "project_dir_central_europe"
fband_file = pathlib.Path("./frequency_band_70_120.pkl")
fband = FrequencyBand.load(fband_file)
fbandFrequencyBand(min_frequency_in_hertz=0.008333333333333333, max_frequency_in_hertz=0.014285714285714285)
SELECTED_EVENTS = [
"event_CRETE_GREECE_Mag_6.15_2015-04-16-18-07",
"event_ICELAND_REGION_Mag_5.75_2020-06-20-19-26",
"event_STRAIT_OF_GIBRALTAR_Mag_6.38_2016-01-25-04-22",
]# Load the project with the data from the previous parts.
p = sn.Project(path=PROJECT_DIR)events)misfit_configuration)prior_model)mapping)method)preconditioner)job_submission)InverseProblemConfiguration collects these parameters to setup the inverse problem.
Often enough, it is hard to choose the best setting a-prior, which is why the inverse problem is constructed as a tree that allows to branch off an ongoing inversion with changed parameters, or to run several scenarios concurrently.p += sn.InverseProblemConfiguration(
name=f"inv_{fband.period_band_name}",
events=SELECTED_EVENTS[:2],
misfit_configuration=f"tf_phase_misfit_{fband.period_band_name}",
wavefield_compression=sn.WavefieldCompression(
forward_wavefield_sampling_interval=10
),
prior_model=f"initial_model_{fband.period_band_name}",
mapping=sn.Mapping(
scaling="relative_deviation_from_prior",
inversion_parameters=["VSH", "VSV", "VP"],
map_to_physical_parameters={
"VPV": "VP",
"VPH": "VP",
},
source_cutout_radius_in_meters=300000,
receiver_cutout_radius_in_meters=50000,
),
method=sn.TrustRegion(initial_trust_region_linf=0.02),
preconditioner=sn.ModelDependentSmoothing(
smoothing_lengths_in_wavelengths={
"VSH": [0.2, 0.5, 0.5],
"VSV": [0.2, 0.5, 0.5],
"VP": [0.2, 0.5, 0.5],
},
reference_frequency_in_hertz=fband.max_frequency_in_hertz,
reference_model="prior",
reference_velocities={"VSH": "VSH", "VSV": "VSH", "VP": "VSH"},
),
job_submission={
"forward": sn.SiteConfig(
site_name=SALVUS_FLOW_SITE_NAME, ranks_per_job=RANKS_PER_JOB
),
"adjoint": sn.SiteConfig(
site_name=SALVUS_FLOW_SITE_NAME, ranks_per_job=RANKS_PER_JOB
),
"preconditioner": sn.SiteConfig(
site_name="local", ranks_per_job=RANKS_PER_JOB
),
},
)p.inversions.add_iteration(
inverse_problem_configuration=f"inv_{fband.period_band_name}"
)[2026-06-02 11:11:41,815] INFO: Adding new iteration #0.
True
p.viz.nb.inversion(
inverse_problem_configuration=f"inv_{fband.period_band_name}"
)Salvus operates a task-based workflow.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. The log messages inform about the current status and tasks.p.inversions.resume(
inverse_problem_configuration=f"inv_{fband.period_band_name}",
)[2026-06-02 11:11:44,530] INFO: Resuming iteration #0. Current stage: initialize [2026-06-02 11:11:44,533] INFO: 1 new tasks have been issued. [2026-06-02 11:11:44,534] INFO: Processing task `misfit_and_gradient` [2026-06-02 11:11:44,534] INFO: -> Mapping between inversion and simulation space: 0 ms [2026-06-02 11:11:46,778] INFO: Submitting job array with 2 jobs ... [2026-06-02 11:11:46,833] INFO: Launched adjoint simulations for 2 events. Please check again to see if they are finished. [2026-06-02 11:11:46,833] INFO: Some tasks of iteration #0 are still running. Please check again later.
True
p.inversions.resume(
inverse_problem_configuration=f"inv_{fband.period_band_name}",
)[2026-06-02 11:11:46,843] INFO: Resuming iteration #0. Current stage: check_convergence [2026-06-02 11:11:46,843] INFO: Processing task `misfit_and_gradient` [2026-06-02 11:11:46,850] INFO: -> Mapping between inversion and simulation space: 0 ms [2026-06-02 11:11:46,997] INFO: Some tasks of iteration #0 are still running. Please check again later.
False

p.inversions.resume(
inverse_problem_configuration=f"inv_{fband.period_band_name}",
)[2026-06-02 11:11:47,002] INFO: Resuming iteration #0. Current stage: check_convergence [2026-06-02 11:11:47,003] INFO: Processing task `misfit_and_gradient` [2026-06-02 11:11:47,003] INFO: -> Mapping between inversion and simulation space: 0 ms [2026-06-02 11:11:47,142] INFO: Some tasks of iteration #0 are still running. Please check again later.
False
p.viz.nb.inversion(
inverse_problem_configuration=f"inv_{fband.period_band_name}",
)Salvus 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=f"inv_{fband.period_band_name}",
timeout_in_seconds=1800,
ping_interval_in_seconds=100,
)[2026-06-02 11:11:47,700] INFO: Resuming iteration #0. [2026-06-02 11:11:47,701] INFO: Processing task `misfit_and_gradient` [2026-06-02 11:11:47,891] INFO: Some tasks of iteration #0 are still running. Please check again later. [2026-06-02 11:13:27,894] INFO: Processing task `misfit_and_gradient` [2026-06-02 11:13:28,098] INFO: Some tasks of iteration #0 are still running. Please check again later. [2026-06-02 11:15:08,101] INFO: Processing task `misfit_and_gradient` [2026-06-02 11:15:09,085] INFO: Some tasks of iteration #0 are still running. Please check again later. [2026-06-02 11:16:49,088] INFO: Processing task `misfit_and_gradient` [2026-06-02 11:16:50,135] INFO: Iteration 0: Number of events: 2 chi = 309.39193216585045 ||g|| = 1.2252180661846654e-05 pred = --- ared = --- norm_update = --- tr_radius = --- [2026-06-02 11:16:50,137] INFO: 1 new tasks have been issued. [2026-06-02 11:16:50,138] INFO: Processing task `preconditioner` [2026-06-02 11:16:50,610] INFO: Some tasks of iteration #0 are still running. Please check again later. [2026-06-02 11:18:30,824] INFO: Processing task `preconditioner` [2026-06-02 11:18:31,311] INFO: 1 new tasks have been issued. [2026-06-02 11:18:31,312] INFO: Processing task `misfit` [2026-06-02 11:18:31,557] INFO: Submitting job array with 2 jobs ... [2026-06-02 11:18:31,721] INFO: Launched simulations for 2 events. Please check again to see if they are finished. [2026-06-02 11:18:31,725] INFO: Some tasks of iteration #0 are still running. Please check again later. [2026-06-02 11:20:11,930] INFO: Processing task `misfit` [2026-06-02 11:20:11,997] INFO: Some tasks of iteration #0 are still running. Please check again later. [2026-06-02 11:21:52,218] INFO: Processing task `misfit` [2026-06-02 11:21:53,946] INFO: old misfit control group: 309.39193216585045 new misfit control group: 222.32369893481868 predicted reduction control group: -43.93685460090637 actual reduction control group: -87.06823323103177 2 out of 2 event(s) improved the misfit. [2026-06-02 11:21:53,946] INFO: Model update accepted. [2026-06-02 11:21:53,946] INFO: 1 new tasks have been issued. [2026-06-02 11:21:53,947] INFO: Processing task `finalize_iteration` [2026-06-02 11:21:54,172] INFO: Successfully completed iteration #0. [2026-06-02 11:21:54,174] INFO: Adding new iteration #1.


p.viz.nb.inversion(
inverse_problem_configuration=f"inv_{fband.period_band_name}",
)scp to transfer the data to your local machine.print(
p.inversions.get_iteration_directory(
inverse_problem_configuration=f"inv_{fband.period_band_name}",
iteration_id=0,
).absolute()
)/tmp/tmphwmcu52s/project_dir_central_europe/INVERSIONS/inv_70.0_120.0_seconds/00000
p.inversions.add_events(
f"inv_{fband.period_band_name}",
SELECTED_EVENTS[-1],
)
previous_events = p.inversions.get_iteration(
f"inv_{fband.period_band_name}", 0
).events
new_events = [
SELECTED_EVENTS[-1],
]
p.inversions.add_iteration(
inverse_problem_configuration=f"inv_{fband.period_band_name}",
parent_id=0,
events=previous_events + new_events,
)[2026-06-02 11:21:55,613] INFO: Adding new iteration #2.
True
p.inversion.iterate will always continue on the last added iteration marked by the green edge in the inversion tree.SalvusOpt will automatically trigger the simulation once we continue with the inversion.p.viz.nb.inversion(
inverse_problem_configuration=f"inv_{fband.period_band_name}",
)iterate function and create a few more model updates.for i in range(2):
p.inversions.iterate(
inverse_problem_configuration=f"inv_{fband.period_band_name}",
timeout_in_seconds=3600,
ping_interval_in_seconds=120,
)[2026-06-02 11:21:57,213] INFO: Resuming iteration #2. [2026-06-02 11:21:57,217] INFO: 2 new tasks have been issued. [2026-06-02 11:21:57,217] INFO: Processing task `misfit_and_gradient` [2026-06-02 11:21:57,298] INFO: Submitting job ... [2026-06-02 11:21:57,358] INFO: Launched simulations for 1 events. Please check again to see if they are finished. [2026-06-02 11:21:57,358] INFO: Processing task `gradient` [2026-06-02 11:21:57,510] INFO: Submitting job array with 2 jobs ... [2026-06-02 11:21:57,593] INFO: Launched adjoint simulations for 2 events. Please check again to see if they are finished. [2026-06-02 11:21:57,594] INFO: Some tasks of iteration #2 are still running. Please check again later. [2026-06-02 11:23:57,598] INFO: Processing task `misfit_and_gradient` [2026-06-02 11:23:59,350] INFO: Submitting job ... [2026-06-02 11:23:59,474] INFO: Launched adjoint simulations for 1 events. Please check again to see if they are finished. [2026-06-02 11:23:59,476] INFO: Processing task `gradient` [2026-06-02 11:23:59,635] INFO: Some tasks of iteration #2 are still running. Please check again later. [2026-06-02 11:25:59,640] INFO: Processing task `misfit_and_gradient` [2026-06-02 11:25:59,816] INFO: Processing task `gradient` [2026-06-02 11:25:59,996] INFO: Some tasks of iteration #2 are still running. Please check again later. [2026-06-02 11:28:00,018] INFO: Processing task `misfit_and_gradient` [2026-06-02 11:28:00,321] INFO: Processing task `gradient` [2026-06-02 11:28:00,496] INFO: Some tasks of iteration #2 are still running. Please check again later. [2026-06-02 11:30:00,540] INFO: Processing task `misfit_and_gradient` [2026-06-02 11:30:02,179] INFO: Processing task `gradient` [2026-06-02 11:30:02,595] INFO: Some tasks of iteration #2 are still running. Please check again later. [2026-06-02 11:32:02,597] INFO: Processing task `misfit_and_gradient` [2026-06-02 11:32:02,618] INFO: While looking for checkpoints, the following error occured: Remote input file `/builds/Mondaic/Code/integrations/TutorialsAndIntegrationTests/SALVUS_INSTALL/SalvusFlow/tmp/job_2606021121302540_4d628e07f1/output.h5` does not exist.. The simulations will be resubmitted. [2026-06-02 11:32:02,619] INFO: The following events have been simulated before, but checkpoints are not available for this combination of `site_name` and `ranks_per_job` and wavefield compression settings. They will be run again: ['event_STRAIT_OF_GIBRALTAR_Mag_6.38_2016-01-25-04-22'] [2026-06-02 11:32:02,824] INFO: Submitting job ... [2026-06-02 11:32:03,026] INFO: Launched simulations for 1 events. Please check again to see if they are finished. [2026-06-02 11:32:03,031] INFO: Processing task `gradient` [2026-06-02 11:32:04,575] INFO: Some tasks of iteration #2 are still running. Please check again later. [2026-06-02 11:34:04,583] INFO: Processing task `misfit_and_gradient` [2026-06-02 11:34:05,140] INFO: Processing task `gradient` [2026-06-02 11:34:05,575] INFO: Iteration 2: Number of events: 3 chi = 264.84418874911387 ||g|| = 1.226447955970411e-05 pred = -43.93685460090637 ared = -87.06823323103177 norm_update = 9578671.303933548 tr_radius = 9578671.303933548 [2026-06-02 11:34:05,755] INFO: 1 new tasks have been issued. [2026-06-02 11:34:05,755] INFO: Processing task `preconditioner` [2026-06-02 11:34:06,221] INFO: Some tasks of iteration #2 are still running. Please check again later. [2026-06-02 11:36:06,358] INFO: Processing task `preconditioner` [2026-06-02 11:36:06,695] INFO: 1 new tasks have been issued. [2026-06-02 11:36:06,695] INFO: Processing task `misfit` [2026-06-02 11:36:06,923] INFO: Submitting job array with 3 jobs ... [2026-06-02 11:36:07,040] INFO: Launched simulations for 3 events. Please check again to see if they are finished. [2026-06-02 11:36:07,041] INFO: Some tasks of iteration #2 are still running. Please check again later. [2026-06-02 11:38:07,177] INFO: Processing task `misfit` [2026-06-02 11:38:07,326] INFO: Some tasks of iteration #2 are still running. Please check again later. [2026-06-02 11:40:07,702] INFO: Processing task `misfit` [2026-06-02 11:40:11,803] INFO: old misfit control group: 264.84418874911387 new misfit control group: 173.93149155395216 predicted reduction control group: -65.16557931900024 actual reduction control group: -90.91269719516171 3 out of 3 event(s) improved the misfit. [2026-06-02 11:40:11,805] INFO: Model update accepted. [2026-06-02 11:40:11,805] INFO: 1 new tasks have been issued. [2026-06-02 11:40:11,807] INFO: Processing task `finalize_iteration` [2026-06-02 11:40:12,063] INFO: Successfully completed iteration #2. [2026-06-02 11:40:12,067] INFO: Adding new iteration #3. [2026-06-02 11:40:12,085] INFO: Resuming iteration #3. [2026-06-02 11:40:12,091] INFO: 1 new tasks have been issued. [2026-06-02 11:40:12,093] INFO: Processing task `gradient` [2026-06-02 11:40:12,420] INFO: Submitting job array with 3 jobs ... [2026-06-02 11:40:12,524] INFO: Launched adjoint simulations for 3 events. Please check again to see if they are finished. [2026-06-02 11:40:12,533] INFO: Some tasks of iteration #3 are still running. Please check again later. [2026-06-02 11:42:12,539] INFO: Processing task `gradient` [2026-06-02 11:42:12,787] INFO: Some tasks of iteration #3 are still running. Please check again later. [2026-06-02 11:44:12,794] INFO: Processing task `gradient` [2026-06-02 11:44:13,130] INFO: Some tasks of iteration #3 are still running. Please check again later. [2026-06-02 11:46:13,134] INFO: Processing task `gradient` [2026-06-02 11:46:13,392] INFO: Some tasks of iteration #3 are still running. Please check again later. [2026-06-02 11:48:13,397] INFO: Processing task `gradient` [2026-06-02 11:48:13,680] INFO: Some tasks of iteration #3 are still running. Please check again later. [2026-06-02 11:50:13,691] INFO: Processing task `gradient` [2026-06-02 11:50:15,044] INFO: Iteration 3: Number of events: 3 chi = 173.93149155395216 ||g|| = 9.615511578028334e-06 pred = -65.16557931900024 ared = -90.91269719516171 norm_update = 19157342.25208998 tr_radius = 19157342.607867096 [2026-06-02 11:50:15,412] INFO: 1 new tasks have been issued. [2026-06-02 11:50:15,413] INFO: Processing task `preconditioner` [2026-06-02 11:50:15,981] INFO: Some tasks of iteration #3 are still running. Please check again later. [2026-06-02 11:52:16,183] INFO: Processing task `preconditioner` [2026-06-02 11:52:16,604] INFO: 1 new tasks have been issued. [2026-06-02 11:52:16,605] INFO: Processing task `misfit` [2026-06-02 11:52:16,868] INFO: Submitting job array with 3 jobs ... [2026-06-02 11:52:17,035] INFO: Launched simulations for 3 events. Please check again to see if they are finished. [2026-06-02 11:52:17,045] INFO: Some tasks of iteration #3 are still running. Please check again later. [2026-06-02 11:54:17,290] INFO: Processing task `misfit` [2026-06-02 11:54:17,380] INFO: Some tasks of iteration #3 are still running. Please check again later. [2026-06-02 11:56:17,551] INFO: Processing task `misfit` [2026-06-02 11:56:17,736] INFO: Some tasks of iteration #3 are still running. Please check again later. [2026-06-02 11:58:17,956] INFO: Processing task `misfit`
[2026-06-02 11:58:23,053] INFO: old misfit control group: 173.93149155395216 new misfit control group: 145.9613644102302 predicted reduction control group: -19.67347526550293 actual reduction control group: -27.970127143721953 3 out of 3 event(s) improved the misfit. [2026-06-02 11:58:23,056] INFO: Model update accepted. [2026-06-02 11:58:23,058] INFO: 1 new tasks have been issued. [2026-06-02 11:58:23,059] INFO: Processing task `finalize_iteration` [2026-06-02 11:58:23,499] INFO: Successfully completed iteration #3. [2026-06-02 11:58:23,504] INFO: Adding new iteration #4.
p.viz.nb.inversion(
inverse_problem_configuration=f"inv_{fband.period_band_name}"
)p.viz.nb.misfit_comparison(
reference_data=f"initial_model_{fband.period_band_name}",
other_data=[
p.inversions.get_simulation_name(
inverse_problem_configuration=f"inv_{fband.period_band_name}",
iteration_id=4,
)
],
misfit_configuration=f"tf_phase_misfit_{fband.period_band_name}",
event=SELECTED_EVENTS[-1],
)| ini... (reference) | inv... | Reduction inv... | |
|---|---|---|---|
| II.BORG.00 | 5.7307e+01 | 4.6823e+01 | 1.0484e+01 |
| II.ESK.00 | 6.1278e+01 | 2.6356e+01 | 3.4921e+01 |
| II.LVZ.00 | 3.6493e+01 | 2.1352e+01 | 1.5142e+01 |
| II.OBN.00 | 1.7480e+01 | 8.6162e+00 | 8.8638e+00 |
| IU.GRFO. | 5.9087e+01 | 2.4190e+01 | 3.4897e+01 |
| IU.KEV.00 | 5.8860e+01 | 1.6968e+01 | 4.1891e+01 |
| IU.KONO.00 | 3.5909e+01 | 2.4192e+01 | 1.1717e+01 |
| IU.MACI. | 5.6660e+01 | 4.1488e+01 | 1.5172e+01 |
| IU.PAB.00 | 2.6027e+00 | 2.0444e+00 | 5.5826e-01 |
<pandas.io.formats.style.Styler at 0x78e6040fb110>
p.viz.misfit_histogram(
simulation_configuration_a=f"initial_model_{fband.period_band_name}",
simulation_configuration_b=p.inversions.get_simulation_name(
inverse_problem_configuration=f"inv_{fband.period_band_name}",
iteration_id=4,
),
misfit_configuration=f"tf_phase_misfit_{fband.period_band_name}",
events=SELECTED_EVENTS[-1],
merge_all_components=False,
)STRAIT_OF_GIBRALTAR and station GB.GAL1 for a good example.
Note that only the parts of the waveforms within the shaded windows informed the inverse problem about the model space.
Interestingly, however, as we approach better models some wiggles that were not selected also match the data better now then they did initially; see station RO.BUR31 for an example.
We could make use of this, re-pick windows and then continue with more iterations and a modified MisfitConfiguration.p.viz.nb.waveforms(
[
f"PROCESSED_DATA:{fband.period_band_name}",
f"initial_model_{fband.period_band_name}",
p.inversions.get_simulation_name(
inverse_problem_configuration=f"inv_{fband.period_band_name}",
iteration_id=4,
),
],
receiver_field="displacement",
data_selection_configuration=f"initial_selection_{fband.period_band_name}",
)