import numpy as np
import xarray as xr
import salvus.namespace as sn
import salvus.mesh.layered_meshing as lm
lm.mesh_from_domain(
domain=sn.domain.dim2.BoxDomain(x0=0.0, x1=1.0, y0=0.0, y1=1.0),
model=lm.material.elastic.Velocity.from_params(rho=1.0, vp=1.0, vs=0.5),
mesh_resolution=sn.MeshResolution(reference_frequency=10.0),
)
<salvus.mesh.data_structures.unstructured_mesh.unstructured_mesh.UnstructuredMesh object at 0x7f7a7e94c4d0>
m0 = lm.material.elastic.Velocity.from_params(rho=1.0, vp=1.0, vs=0.5)
xarray
Dataset, which can be queried by the materials .ds
variable.m0.ds
<xarray.Dataset> Size: 24B Dimensions: () Data variables: RHO float64 8B 1.0 VP float64 8B 1.0 VS float64 8B 0.5
<xarray.Dataset> Size: 24B Dimensions: () Data variables: RHO float64 8B 1.0 VP float64 8B 1.0 VS float64 8B 0.5
xarray
representation of the material parameters we specified. You might notice that no coordinates are specified here. This is no problem, as the coordinates will be "realized" when the model is eventually used in the meshing process. Realization in this context refers to ensuring that all coordinates present in a layered model are consistent with the spatial dimension and domain they are being used within. As no coordinates are present here, the realization stage will thus ensure that the model values are propagated to all locations in the host domain. In the future we will see how realization can be exploited to define models on only a subset of a domain's coordinate axes, and additionally define them relative to either the domain bounds, or to the bounds of a host layer.m0_lame = lm.material.elastic.isotropic.LameParameters.from_params(
lam=0.5, mu=0.25, rho=1.0
)
print(lm.material.elastic.Velocity.from_material(m0_lame))
Velocity(RHO=ConstantParameter(p=1.0), VP=ConstantParameter(p=1.0), VS=ConstantParameter(p=0.5))
.to_wavelength_oracle()
that will automatically compute the critical parameter required to determine the required mesh size. For isotropic elastic models this is simply the model's shear wave velocity, but for less symmetric materials the oracle may instead be a combination of the material's parameters.print(
f"{m0.to_wavelength_oracle(n_dim=3)}\n{m0_lame.to_wavelength_oracle(n_dim=3)}"
)
ConstantParameter(p=0.5) ConstantParameter(p=0.5)
m0_lame
in terms of , , and , Salvus automatically computed it for us. The presence of this oracle for each parameterization means that the tedious process of manually computing the minimum wavelength is a thing of the past -- Salvus will take care of this for you.LayeredModel
to tell Salvus that we are ready to proceed to the next stage of mesh generation.lm_0 = lm.LayeredModel(m0)
LayeredModel
object has some interesting properties. First off, we can query the models it contains and see our material stored therein. Note that the models are presented as a list with one element; again, the utility of this will be apparent later on.lm_0.models
[Velocity(RHO=ConstantParameter(p=1.0), VP=ConstantParameter(p=1.0), VS=ConstantParameter(p=0.5))]
.interfaces
property. Here, we see an empty list.lm_0.interfaces
[]
.complete()
method on the layered model and inspect the interfaces added.print("\n\n".join(str(s) for s in lm_0.complete().interfaces))
Hyperplane(da=<xarray.DataArray ()> Size: 8B array(0.) Attributes: reference_elevation: Depth(value=0.0), extender=<cyfunction extrude_like_and_pad at 0x7f7a86c18450>, interpolation_method='linear') Hyperplane(da=<xarray.DataArray ()> Size: 8B array(0.) Attributes: reference_elevation: Height(value=0.0), extender=<cyfunction extrude_like_and_pad at 0x7f7a86c18450>, interpolation_method='linear')
strata
.print("\n\n".join(str(s) for s in lm_0.complete().strata))
Hyperplane(da=<xarray.DataArray ()> Size: 8B array(0.) Attributes: reference_elevation: Depth(value=0.0), extender=<cyfunction extrude_like_and_pad at 0x7f7a86c18450>, interpolation_method='linear') Velocity(RHO=ConstantParameter(p=1.0), VP=ConstantParameter(p=1.0), VS=ConstantParameter(p=0.5)) Hyperplane(da=<xarray.DataArray ()> Size: 8B array(0.) Attributes: reference_elevation: Height(value=0.0), extender=<cyfunction extrude_like_and_pad at 0x7f7a86c18450>, interpolation_method='linear')
i0, i1 = lm_0.complete().interfaces
print(i0.da.reference_elevation)
print(i1.da.reference_elevation)
Depth(value=0.0) Height(value=0.0)
Domain
object. For now, let's just use a simple 2-D Box domain.d_2d = sn.domain.dim2.BoxDomain(x0=0, x1=1, y0=0, y1=1)
d_2d.plot()
MeshResolution
object. Here we can set the desired elements per wavelength, reference frequency, and order of model representation as follows:mr = sn.MeshResolution(
reference_frequency=2.0, elements_per_wavelength=1.5, model_order=2
)
mesh_from_domain
function as follows:mesh = lm.mesh_from_domain(domain=d_2d, model=lm_0, mesh_resolution=mr)
mesh
<salvus.mesh.data_structures.unstructured_mesh.unstructured_mesh.UnstructuredMesh object at 0x7f7aaae11110>
LayeredModel
is optional for models with only 1 layer and no explicitly defined interfaces. Indeed, executing the above cell with the m0
model instance directly achieves the same result.lm.mesh_from_domain(domain=d_2d, model=m0, mesh_resolution=mr)
<salvus.mesh.data_structures.unstructured_mesh.unstructured_mesh.UnstructuredMesh object at 0x7f7aaae10c90>
d_3d = sn.domain.dim3.BoxDomain(x0=0, x1=1, y0=0, y1=1, z0=0, z1=1)
lm.mesh_from_domain(domain=d_3d, model=m0, mesh_resolution=mr)
<salvus.mesh.data_structures.unstructured_mesh.unstructured_mesh.UnstructuredMesh object at 0x7f7a75f94750>
vp_grad = xr.DataArray(
np.linspace(1.0, 2.0, 11), [("y", np.linspace(1.0, 0.0, 11))]
)
m1 = lm.material.elastic.Velocity.from_params(
rho=1.0, vp=vp_grad, vs=0.5 * vp_grad
)
lm.mesh_from_domain(domain=d_2d, model=m1, mesh_resolution=mr)
<salvus.mesh.data_structures.unstructured_mesh.unstructured_mesh.UnstructuredMesh object at 0x7f7a75fce950>
lm.mesh_from_domain(domain=d_3d, model=m1, mesh_resolution=mr)
<salvus.mesh.data_structures.unstructured_mesh.unstructured_mesh.UnstructuredMesh object at 0x7f7a76057c90>
"y"
coordinate above. "y"
is indeed the vertical coordinate in 2-D domains, and to get this in 3-D we simply need to rename the coordinate.vp_grad_z = vp_grad.rename({"y": "z"})
m1_z = lm.material.elastic.Velocity.from_params(
rho=1.0, vp=vp_grad_z, vs=0.5 * vp_grad_z
)
lm.mesh_from_domain(domain=d_3d, model=m1_z, mesh_resolution=mr)
<salvus.mesh.data_structures.unstructured_mesh.unstructured_mesh.UnstructuredMesh object at 0x7f7a75e669d0>
lm.mesh_from_domain(
domain=d_3d,
model=lm.material.elastic.Velocity.from_params(
rho=1.0, vp=vp_grad, vs=0.5 * vp_grad_z
),
mesh_resolution=mr,
)
<salvus.mesh.data_structures.unstructured_mesh.unstructured_mesh.UnstructuredMesh object at 0x7f7a760ddc50>
"v"
(for "vertical"), which will map between y
and z
depending on the domain's dimension.vp_grad_v = xr.DataArray(
np.linspace(1.0, 2.0, 11), [("v", np.linspace(1.0, 0.0, 11))]
)
m1_v = lm.material.elastic.Velocity.from_params(
rho=1.0, vp=vp_grad_v, vs=0.5 * vp_grad_v
)
# 2d
lm.mesh_from_domain(domain=d_2d, model=m1_v, mesh_resolution=mr)
<salvus.mesh.data_structures.unstructured_mesh.unstructured_mesh.UnstructuredMesh object at 0x7f7a75ee2590>
# 3d
lm.mesh_from_domain(domain=d_3d, model=m1_v, mesh_resolution=mr)
<salvus.mesh.data_structures.unstructured_mesh.unstructured_mesh.UnstructuredMesh object at 0x7f7a75dc7f90>
m2_l0 = lm.material.acoustic.Velocity.from_params(rho=0.5, vp=0.5)
m2_l1 = m1_v
m2_i0 = lm.interface.Hyperplane.at(0.5)
LayeredModel
object with a list of strata, defined in a top-down order.lm_2 = lm.LayeredModel([m2_l0, m2_i0, m2_l1])
lm.mesh_from_domain(domain=d_2d, model=lm_2, mesh_resolution=mr)
<salvus.mesh.data_structures.unstructured_mesh.unstructured_mesh.UnstructuredMesh object at 0x7f7a75c73c10>
lm.mesh_from_domain(domain=d_3d, model=lm_2, mesh_resolution=mr)
<salvus.mesh.data_structures.unstructured_mesh.unstructured_mesh.UnstructuredMesh object at 0x7f7a75cbb5d0>
x = np.linspace(0, 1, 51)
m3_i0 = lm.interface.Curve.from_points(
x,
np.sin(2 * np.pi * x) * 0.1 - 0.1,
reference_elevation=lm.interface.Depth(0.0),
axis="x",
)
m3_i1 = lm.interface.Curve.from_points(
x,
np.sin(np.pi * x) * 0.2,
reference_elevation=lm.interface.Depth(0.5),
axis="x",
)
lm_3 = lm.LayeredModel([m3_i0, m2_l0, m3_i1, m2_l1])
lm.mesh_from_domain(domain=d_2d, model=lm_3, mesh_resolution=mr)
<salvus.mesh.data_structures.unstructured_mesh.unstructured_mesh.UnstructuredMesh object at 0x7f7a75b77910>
lm_3_z = lm.LayeredModel([m3_i0, m2_l0, m3_i1, m2_l1])
lm.mesh_from_domain(domain=d_3d, model=lm_3_z, mesh_resolution=mr)
<salvus.mesh.data_structures.unstructured_mesh.unstructured_mesh.UnstructuredMesh object at 0x7f7a75fa1410>