import numpy as np
import os
import salvus.namespace as sn
# Run simulations on this site.
SALVUS_FLOW_SITE_NAME = os.environ.get("SITE_NAME", "local")
# Either load an existing project or create a new one.
p = sn.Project.from_domain(
path="project",
# Should match the volume model.
domain=sn.domain.dim2.BoxDomain(x0=0, x1=3000, y0=-1000, y1=0),
load_if_exists=True,
)
bm
model file.%%writefile layered_model.bm
NAME radial_model
ACOUSTIC true
UNITS m
COLUMNS depth rho vp
0.0 1000.0 1500.0
200.0 1000.0 1500.0
200.0 1300.0 1900.0
500.0 1300.0 1900.0
500.0 2200.0 3200.0
4000.0 2200.0 3200.0
Writing layered_model.bm
%%writefile layered_model_ani.bm
NAME radial_model
ACOUSTIC true
ANISOTROPIC true
UNITS m
COLUMNS depth rho vpv vph
0.0 1000.0 1500.0 1500.0
200.0 1000.0 1500.0 1500.0
200.0 1300.0 1900.0 2100.0
500.0 1300.0 1900.0 2100.0
500.0 2200.0 3200.0 3500.0
4000.0 2200.0 3200.0 3500.0
Writing layered_model_ani.bm
VPV
and VPH
.%%writefile layered_model_fake_ani.bm
NAME radial_model
ACOUSTIC true
ANISOTROPIC true
UNITS m
COLUMNS depth rho vpv vph
0.0 1000.0 1500.0 1500.0
200.0 1000.0 1500.0 1500.0
200.0 1300.0 1900.0 1900.0
500.0 1300.0 1900.0 1900.0
500.0 2200.0 3200.0 3200.0
4000.0 2200.0 3200.0 3200.0
Writing layered_model_fake_ani.bm
for name, bm in zip(
["isotropic", "anisotropic", "fake-anisotropic"],
["layered_model.bm", "layered_model_ani.bm", "layered_model_fake_ani.bm"],
):
p.add_to_project(
sn.SimulationConfiguration(
name=name,
max_frequency_in_hertz=20.0,
elements_per_wavelength=1.5,
model_configuration=sn.ModelConfiguration(
background_model=sn.model.background.one_dimensional.FromBm(
filename=bm, reference_datum=0.0
),
),
event_configuration=sn.EventConfiguration(
wavelet=sn.simple_config.stf.Ricker(center_frequency=10.0),
waveform_simulation_configuration=sn.WaveformSimulationConfiguration(
end_time_in_seconds=1.5,
),
),
absorbing_boundaries=sn.AbsorbingBoundaryParameters(
reference_velocity=2200.0,
reference_frequency=10.0,
number_of_wavelengths=7,
),
),
)
p.viz.nb.simulation_setup("anisotropic")
[2025-07-23 21:26:37,890] INFO: Creating mesh. Hang on.
<salvus.mesh.data_structures.unstructured_mesh.unstructured_mesh.UnstructuredMesh object at 0x7a7a44c3fed0>
UnstructuredMeshSimulationConfiguration
.def convert_thomsen_params_to_vti_tensor(
dim: int,
rho: np.ndarray,
vp: np.ndarray,
delta: np.ndarray,
epsilon: np.ndarray,
):
if dim == 2:
model = {
"M0": 1 / (vp**2 * rho),
"D11": (1 + 2 * epsilon) / rho,
"D12": (delta - epsilon) / rho,
"D22": 1 / rho,
}
elif dim == 3:
model = {
"M0": 1 / (vp**2 * rho),
"D11": (1 + 2 * epsilon) / rho,
"D12": np.zeros_like(rho),
"D13": (delta - epsilon) / rho,
"D22": (1 + 2 * epsilon) / rho,
"D23": (delta - epsilon) / rho,
"D33": 1 / rho,
}
return model
def interpolate_vti_model_onto_mesh(mesh: sn.UnstructuredMesh):
if "VPV" in mesh.elemental_fields.keys():
vti_model = convert_thomsen_params_to_vti_tensor(
dim=2,
rho=mesh.elemental_fields["RHO"],
vp=mesh.elemental_fields["VPV"],
delta=0.5
* (
mesh.elemental_fields["VPH"] ** 2
/ mesh.elemental_fields["VPV"] ** 2
- 1.0
),
epsilon=0.5
* (
mesh.elemental_fields["VPH"] ** 2
/ mesh.elemental_fields["VPV"] ** 2
- 1.0
),
)
for k, v in vti_model.items():
mesh.elemental_fields[k] = v
del mesh.elemental_fields["VPV"]
del mesh.elemental_fields["VPH"]
del mesh.elemental_fields["RHO"]
else:
vti_model = convert_thomsen_params_to_vti_tensor(
dim=2,
rho=mesh.elemental_fields["RHO"],
vp=mesh.elemental_fields["VP"],
delta=np.zeros_like(mesh.elemental_fields["VP"]),
epsilon=np.zeros_like(mesh.elemental_fields["VP"]),
)
for k, v in vti_model.items():
mesh.elemental_fields[k] = v
del mesh.elemental_fields["VP"]
del mesh.elemental_fields["RHO"]
return mesh
mesh = p.simulations.get_mesh("isotropic")
mesh = interpolate_vti_model_onto_mesh(mesh)
p.add_to_project(
sn.UnstructuredMeshSimulationConfiguration(
unstructured_mesh=mesh,
name="thomsen-isotropic",
event_configuration=p.entities.get(
"simulation_configuration", "anisotropic"
).event_configuration,
)
)
mesh = p.simulations.get_mesh("anisotropic")
mesh = interpolate_vti_model_onto_mesh(mesh)
p.add_to_project(
sn.UnstructuredMeshSimulationConfiguration(
unstructured_mesh=mesh,
name="thomsen-anisotropic",
event_configuration=p.entities.get(
"simulation_configuration", "anisotropic"
).event_configuration,
)
)
[2025-07-23 21:26:38,124] INFO: Creating mesh. Hang on.
src = sn.simple_config.source.cartesian.ScalarPoint2D(x=1500, y=0, f=1.0)
recs = sn.simple_config.receiver.cartesian.collections.ArrayPoint2D(
x=np.linspace(100, 2900, 141), y=np.zeros(141), fields=["phi"]
)
p += sn.Event(event_name="event", sources=src, receivers=recs)
p.viz.nb.domain()
for name in [
"isotropic",
"anisotropic",
"fake-anisotropic",
"thomsen-anisotropic",
"thomsen-isotropic",
]:
p.simulations.launch(
simulation_configuration=name,
events=p.events.list(),
site_name=SALVUS_FLOW_SITE_NAME,
ranks_per_job=1,
)
p.simulations.query(block=True)
[2025-07-23 21:26:38,347] INFO: Submitting job ... Uploading 1 files... 🚀 Submitted job_2507232126436118_4333030ed5@local
[2025-07-23 21:26:39,907] INFO: Submitting job ... Uploading 1 files... 🚀 Submitted job_2507232126911521_b12ed1e588@local
[2025-07-23 21:26:41,615] INFO: Creating mesh. Hang on. [2025-07-23 21:26:41,681] INFO: Submitting job ... Uploading 1 files... 🚀 Submitted job_2507232126685777_9c69f4de50@local
[2025-07-23 21:26:43,259] INFO: Submitting job ... Uploading 1 files... 🚀 Submitted job_2507232126262763_bd8d7689c8@local
[2025-07-23 21:26:44,957] INFO: Submitting job ... Uploading 1 files... 🚀 Submitted job_2507232126961143_51fdd52fbd@local
p.viz.nb.waveforms(
data=["isotropic", "fake-anisotropic", "thomsen-isotropic"],
receiver_field="phi",
)
p.viz.nb.waveforms(
data=["anisotropic", "thomsen-anisotropic"],
receiver_field="phi",
)
p.viz.nb.waveforms(
data=["isotropic", "anisotropic"],
receiver_field="phi",
)
p.waveforms.get(data_name="isotropic", events=p.events.list())[0].plot(
component="A",
receiver_field="phi",
plot_types=["shotgather"],
)
p.waveforms.get(data_name="anisotropic", events=p.events.list())[0].plot(
component="A",
receiver_field="phi",
plot_types=["shotgather"],
)