Please note that although all materials below are available in SalvusPy, for now the solver still needs either anelastic.isotropic.Velocity
orelastic.triclinic.TensorComponents
, material. This is because the solver currently only supports those forms and materials are not automatically converted. The notebook will end with a small example of how to convert to a solver-compatible form.
# Import Salvus' material module
from salvus import material
# It is also exposed via the namespace module
import salvus.namespace as sn
sn.material
<module 'salvus.material' from '/miniconda/envs/salvus-py311/lib/python3.11/site-packages/salvus/material/__init__.py'>
from_params
method, which takes a set of keywords
and values.material_1_elastic_velocity = material.from_params(
vp=5000,
vs=3500,
rho=2500,
)
material_1_elastic_velocity
<IPython.core.display.HTML object>
salvus.material.elastic.isotropic.Velocity
to_wavelength_oracle
method. This method is used internally by the mesher to create something that
predicts the wavelength of the material (hence why we called it an
"oracle") at 1 Hz.material_1_elastic_velocity.to_wavelength_oracle()
Constant parameter Spatially constant Value: 3.5e+03
material_2_elastic_Lame = (
material.elastic.isotropic.LameParameters.from_params(
lam=1.0e9,
mu=30.0e9,
rho=2500,
)
)
material_2_elastic_Lame
<IPython.core.display.HTML object>
salvus.material.elastic.isotropic.LameParameters
material_2_elastic_Lame.to_wavelength_oracle()
Constant parameter Spatially constant Value: 3.5e+03
from_material
method that takes another material as an argument and returns a material in
that parameterization. In other words, we can make a material parametrized
with velocities from a material parametrized with Lame parameters, and vice
versa:material_2_elastic_converted = (
material.elastic.isotropic.Velocity.from_material(
material_2_elastic_Lame,
)
)
material_2_elastic_converted
<IPython.core.display.HTML object>
salvus.material.elastic.isotropic.Velocity
material_2_elastic_converted.VP
Constant parameter Spatially constant Value: 4.9e+03
.p
property of the
parameter (VP
in this case):material_2_elastic_converted.VP.p, material_2_elastic_converted.VS.p
(4939.635614091388, 3464.1016151377544)
.p
property, we also implemented a way to retrieve all the data for a material
as an XArray Dataset, which allows convenient numerical operations.material_2_elastic_converted.ds
<xarray.Dataset> Size: 24B Dimensions: () Data variables: RHO float64 8B 2.5e+03 VP float64 8B 4.94e+03 VS float64 8B 3.464e+03
<xarray.Dataset> Size: 24B Dimensions: () Data variables: RHO float64 8B 2.5e+03 VP float64 8B 4.94e+03 VS float64 8B 3.464e+03
print("Elastic isotropic parameterizations:")
for el_iso_mat in sn.material.elastic.isotropic.__all__:
print(f"\t- {el_iso_mat}")
print("Acoustic isotropic parameterizations:")
for ac_iso_mat in sn.material.acoustic.isotropic.__all__:
print(f"\t- {ac_iso_mat}")
Elastic isotropic parameterizations: - Velocity - LameParameters - BulkAndShearModulus - ShearModulusAndPoissonsRatio - TensorComponents - YoungsAndShearModulus - YoungsModulusAndPoissonsRatio - ShearModulusAndPoissonsRatio2D - YoungsAndShearModulus2D - YoungsModulusAndPoissonsRatio2D Acoustic isotropic parameterizations: - BulkModulus - LinearCoefficients - Velocity
(
# This won't work if the material is not the same parameterization
material_2_elastic_Lame
== sn.material.elastic.isotropic.LameParameters.from_material(
sn.material.elastic.isotropic.YoungsAndShearModulus.from_material(
sn.material.elastic.isotropic.Velocity.from_material(
material_2_elastic_Lame,
)
)
)
)
False
import xarray as xr
vp = xr.DataArray(
data=[5000, 5500, 6000],
dims=["z"],
coords={"z": [0, 1000, 2000]},
)
# The materials module supports mixed parameter types, i.e. floats together
# with DataArrays.
vs = 3500
rho = 2500
material_3_elastic_velocity_spatial = sn.material.from_params(
vp=vp,
vs=vs,
rho=rho,
)
material_3_elastic_velocity_spatial
<IPython.core.display.HTML object>
salvus.material.elastic.isotropic.Velocity
sn.material.elastic.isotropic.BulkAndShearModulus.from_material(
material_3_elastic_velocity_spatial
)
<IPython.core.display.HTML object>
salvus.material.elastic.isotropic.BulkAndShearModulus
material_3_elastic_velocity_spatial.to_wavelength_oracle()
Constant parameter Spatially constant Value: 3.5e+03
P-wave velocity
's spatial
information against all parameters that are dependent on it in the
transformation), the wavelength oracle will be a DataArray as well:sn.material.elastic.isotropic.YoungsAndShearModulus.from_material(
material_3_elastic_velocity_spatial
).to_wavelength_oracle()
Discrete parameter Coordinates: 'z' [0 to 2e+03] Range: 3.5e+03 to 3.5e+03 - shape: (3,) - 24.0 bytes
import numpy as np
x = np.linspace(0, 2000, 100)
y = np.linspace(0, 2000, 100)
z = np.linspace(0, 2000, 100)
vp_2 = xr.DataArray(
data=5000 + 100 * np.sin(z / 1000),
dims=["z"],
coords={"z": z},
)
# The materials module supports mixed parameter types, i.e. floats together
# with DataArrays.
vs_2 = xr.DataArray(
data=3500 + 100 * np.sin(y * 2 / 1000),
dims=["y"],
coords={"y": y},
)
rho_2 = xr.DataArray(
data=2500 + 100 * np.sin(x * 3 / 1000),
dims=["x"],
coords={"x": x},
)
material_4_elastic_velocity_spatial = sn.material.from_params(
vp=vp_2, vs=vs_2, rho=rho_2
)
material_4_elastic_velocity_spatial.ds
<xarray.Dataset> Size: 24MB Dimensions: (x: 100, y: 100, z: 100) Coordinates: * x (x) float64 800B 0.0 20.2 40.4 60.61 ... 1.96e+03 1.98e+03 2e+03 * y (y) float64 800B 0.0 20.2 40.4 60.61 ... 1.96e+03 1.98e+03 2e+03 * z (z) float64 800B 0.0 20.2 40.4 60.61 ... 1.96e+03 1.98e+03 2e+03 Data variables: RHO (x, y, z) float64 8MB 2.5e+03 2.5e+03 ... 2.472e+03 2.472e+03 VP (x, y, z) float64 8MB 5e+03 5.002e+03 ... 5.092e+03 5.091e+03 VS (x, y, z) float64 8MB 3.5e+03 3.5e+03 ... 3.424e+03 3.424e+03
<xarray.Dataset> Size: 24MB Dimensions: (x: 100, y: 100, z: 100) Coordinates: * x (x) float64 800B 0.0 20.2 40.4 60.61 ... 1.96e+03 1.98e+03 2e+03 * y (y) float64 800B 0.0 20.2 40.4 60.61 ... 1.96e+03 1.98e+03 2e+03 * z (z) float64 800B 0.0 20.2 40.4 60.61 ... 1.96e+03 1.98e+03 2e+03 Data variables: RHO (x, y, z) float64 8MB 2.5e+03 2.5e+03 ... 2.472e+03 2.472e+03 VP (x, y, z) float64 8MB 5e+03 5.002e+03 ... 5.092e+03 5.091e+03 VS (x, y, z) float64 8MB 3.5e+03 3.5e+03 ... 3.424e+03 3.424e+03
mu_retrieved = sn.material.elastic.isotropic.LameParameters.from_material(
material_4_elastic_velocity_spatial
).MU # This is only the internal Salvus representation of the parameter
mu_retrieved_dataarray = mu_retrieved.p # This is the underlying DataArray
# Standard XArray plotting
mu_retrieved_dataarray.sel(z=400, method="nearest").plot()
<matplotlib.collections.QuadMesh at 0x70f43febed90>
domain = sn.domain.dim3.BoxDomain(x0=0, x1=2000, y0=0, y1=2000, z0=0, z1=2000)
mesh_material_4 = sn.layered_meshing.mesh_from_domain(
domain=domain,
model=material_4_elastic_velocity_spatial,
mesh_resolution=sn.MeshResolution(reference_frequency=10),
)
mesh_material_4
<salvus.mesh.data_structures.unstructured_mesh.unstructured_mesh.UnstructuredMesh object at 0x70f44250ffd0>
sn.layered_meshing.mesh_from_domain(
domain=domain,
model=sn.material.elastic.isotropic.LameParameters.from_material(
material_4_elastic_velocity_spatial
),
mesh_resolution=sn.MeshResolution(reference_frequency=10),
)
<salvus.mesh.data_structures.unstructured_mesh.unstructured_mesh.UnstructuredMesh object at 0x70f514743310>
import sympy as sp
depth_symbol = sp.symbols("depth")
vp_sp = (
2000 + 25 * sp.cos(depth_symbol / 50) + 100 * sp.exp(depth_symbol / 2000)
)
material_5_elastic_velocity_spatial = sn.material.from_params(
vp=vp_sp, vs=1000, rho=2500
)
sn.layered_meshing.mesh_from_domain(
domain=domain,
model=material_5_elastic_velocity_spatial,
mesh_resolution=sn.MeshResolution(reference_frequency=10),
)
<salvus.mesh.data_structures.unstructured_mesh.unstructured_mesh.UnstructuredMesh object at 0x70f434dfa350>
sn.material.elastic.isotropic.YoungsModulusAndPoissonsRatio.from_material(
material_5_elastic_velocity_spatial
) # (Not that these expressions are particularly nice to look at)
<IPython.core.display.HTML object>
salvus.material.elastic.isotropic.YoungsModulusAndPoissonsRatio
vp_np, vs_np, rho_np = [
mesh_material_4.element_nodal_fields[par] for par in ["VP", "VS", "RHO"]
]
vp_np.shape, vs_np.shape, rho_np.shape
((729, 8), (729, 8), (729, 8))
material_6_converted_from_mesh = (
sn.material.elastic.isotropic.YoungsModulusAndPoissonsRatio.from_material(
sn.material.from_params(
vp=vp_np,
vs=vs_np,
rho=rho_np,
)
)
)
mesh_material_6 = mesh_material_4.copy()
mesh_material_6.elemental_fields.clear() # Remove old fields
for field_name, numpy_array in material_6_converted_from_mesh.ds.items():
mesh_material_6.attach_field(name=field_name, data=numpy_array)
mesh_material_6
<salvus.mesh.data_structures.unstructured_mesh.unstructured_mesh.UnstructuredMesh object at 0x70f4347bbd10>
from salvus.mesh.algorithms.unstructured_mesh import (
material_operations as mesh_material_ops,
)
# To create a material from a mesh
material_7_from_mesh = mesh_material_ops.to_material(mesh_material_4)
# To directly convert a mesh to have a different material
mesh_material_4.transform_material(
sn.material.elastic.transversely_isotropic.Velocity
)
<salvus.mesh.data_structures.unstructured_mesh.unstructured_mesh.UnstructuredMesh object at 0x70f432e52f90>