import numpy as np
import xarray as xr
import salvus.namespace as snsn.layered_meshing.mesh_from_domain(
domain=sn.domain.dim2.BoxDomain(x0=0.0, x1=1.0, y0=0.0, y1=1.0),
model=sn.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 0x745e05a7a890>
# We cant actually access any material much faster by letting salvus figure
# out which one we want by the arguments supplied
# m0 = sn.material.elastic.Velocity.from_params(rho=1.0, vp=1.0, vs=0.5)
m0 = sn.material.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.5xarray 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 = sn.material.from_params(lam=0.5, mu=0.25, rho=1.0)print(sn.material.elastic.Velocity.from_material(m0_lame))Salvus material: salvus.material.elastic.isotropic.Velocity
Physics: isotropic, elastic
Components:
RHO: Constant parameter
Spatially constant
Value: 1
VP : Constant parameter
Spatially constant
Value: 1
VS : Constant parameter
Spatially constant
Value: 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{m0_lame.to_wavelength_oracle()}")Constant parameter Spatially constant Value: 0.5 Constant parameter Spatially constant Value: 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 = sn.layered_meshing.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[salvus.material.elastic.isotropic.Velocity]
.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 0x745e085e74c0>, 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 0x745e085e74c0>, 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 0x745e085e74c0>, interpolation_method='linear')
Salvus material: salvus.material.elastic.isotropic.Velocity
Physics: isotropic, elastic
Components:
RHO: Constant parameter
Spatially constant
Value: 1
VP : Constant parameter
Spatially constant
Value: 1
VS : Constant parameter
Spatially constant
Value: 0.5
Hyperplane(da=<xarray.DataArray ()> Size: 8B
array(0.)
Attributes:
reference_elevation: Height(value=0.0), extender=<cyfunction extrude_like_and_pad at 0x745e085e74c0>, 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 = sn.layered_meshing.mesh_from_domain(
domain=d_2d, model=lm_0, mesh_resolution=mr
)
mesh<salvus.mesh.data_structures.unstructured_mesh.unstructured_mesh.UnstructuredMesh object at 0x745e1e6a8550>
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.sn.layered_meshing.mesh_from_domain(domain=d_2d, model=m0, mesh_resolution=mr)<salvus.mesh.data_structures.unstructured_mesh.unstructured_mesh.UnstructuredMesh object at 0x745e1e70c350>
d_3d = sn.domain.dim3.BoxDomain(x0=0, x1=1, y0=0, y1=1, z0=0, z1=1)
sn.layered_meshing.mesh_from_domain(domain=d_3d, model=m0, mesh_resolution=mr)<salvus.mesh.data_structures.unstructured_mesh.unstructured_mesh.UnstructuredMesh object at 0x745e1e8cdfd0>
vp_grad = xr.DataArray(
np.linspace(1.0, 2.0, 11), [("y", np.linspace(1.0, 0.0, 11))]
)
m1 = sn.material.from_params(rho=1.0, vp=vp_grad, vs=0.5 * vp_grad)sn.layered_meshing.mesh_from_domain(domain=d_2d, model=m1, mesh_resolution=mr)<salvus.mesh.data_structures.unstructured_mesh.unstructured_mesh.UnstructuredMesh object at 0x745e1e9098d0>
sn.layered_meshing.mesh_from_domain(domain=d_3d, model=m1, mesh_resolution=mr)<salvus.mesh.data_structures.unstructured_mesh.unstructured_mesh.UnstructuredMesh object at 0x745e1e906010>
"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 = sn.material.from_params(rho=1.0, vp=vp_grad_z, vs=0.5 * vp_grad_z)
sn.layered_meshing.mesh_from_domain(
domain=d_3d, model=m1_z, mesh_resolution=mr
)<salvus.mesh.data_structures.unstructured_mesh.unstructured_mesh.UnstructuredMesh object at 0x745e1e512210>
sn.layered_meshing.mesh_from_domain(
domain=d_3d,
model=sn.material.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 0x745e1e526b90>
"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 = sn.material.from_params(rho=1.0, vp=vp_grad_v, vs=0.5 * vp_grad_v)# 2d
sn.layered_meshing.mesh_from_domain(
domain=d_2d, model=m1_v, mesh_resolution=mr
)<salvus.mesh.data_structures.unstructured_mesh.unstructured_mesh.UnstructuredMesh object at 0x745e0070a3d0>
# 3d
sn.layered_meshing.mesh_from_domain(
domain=d_3d, model=m1_v, mesh_resolution=mr
)<salvus.mesh.data_structures.unstructured_mesh.unstructured_mesh.UnstructuredMesh object at 0x745e007192d0>
m2_l0 = sn.material.from_params(rho=0.5, vp=0.5)
m2_l1 = m1_vm2_i0 = sn.layered_meshing.interface.Hyperplane.at(0.5)LayeredModel object with a list of strata, defined
in a top-down order.lm_2 = sn.layered_meshing.LayeredModel([m2_l0, m2_i0, m2_l1])sn.layered_meshing.mesh_from_domain(
domain=d_2d, model=lm_2, mesh_resolution=mr
)<salvus.mesh.data_structures.unstructured_mesh.unstructured_mesh.UnstructuredMesh object at 0x745e1e6e4490>
sn.layered_meshing.mesh_from_domain(
domain=d_3d, model=lm_2, mesh_resolution=mr
)<salvus.mesh.data_structures.unstructured_mesh.unstructured_mesh.UnstructuredMesh object at 0x745e0064d390>
x = np.linspace(0, 1, 51)
m3_i0 = sn.layered_meshing.interface.Curve.from_points(
x,
np.sin(2 * np.pi * x) * 0.1 - 0.1,
reference_elevation=sn.layered_meshing.interface.Depth(0.0),
axis="x",
)
m3_i1 = sn.layered_meshing.interface.Curve.from_points(
x,
np.sin(np.pi * x) * 0.2,
reference_elevation=sn.layered_meshing.interface.Depth(0.5),
axis="x",
)lm_3 = sn.layered_meshing.LayeredModel([m3_i0, m2_l0, m3_i1, m2_l1])sn.layered_meshing.mesh_from_domain(
domain=d_2d, model=lm_3, mesh_resolution=mr
)<salvus.mesh.data_structures.unstructured_mesh.unstructured_mesh.UnstructuredMesh object at 0x745e1e90dfd0>
lm_3_z = sn.layered_meshing.LayeredModel([m3_i0, m2_l0, m3_i1, m2_l1])
sn.layered_meshing.mesh_from_domain(
domain=d_3d, model=lm_3_z, mesh_resolution=mr
)<salvus.mesh.data_structures.unstructured_mesh.unstructured_mesh.UnstructuredMesh object at 0x745e005e7d90>