Salvus 2024.1.2
This is a minor release with several bug fixes and performance improvements.
New features include utilities for switching the material parameterization and extracting spatial gradients of a model, improved support for meshes stored in the ExodusII file format, the ability to add new sites on the fly, a callback option for post-processing model updates in an inversion, and experimental support for importing sources on a fault using the Standard Rupture Format (SRF).
The performance improvements provide significant speed-ups for interpolating volumetric models and local mesh refinements.
Further details are listed below.
Changes
Salvus on local sites typically fully decouples processes (e.g. running
computations) from its parent process to allow for async workflows. In some
situations this is not desirable (e.g. one wants to ensure that all Salvus
runs are terminated when the Python process is terminated). An optional
"do_not_decouple_child_processes" flag for local sites has been introduced to
support that behavior.
Added the possibility to add new executors/sites on-the-fly, skipping all the
checks from the salvus-cli init-site step.
Usage as a context manager is optional.
with sn.functions.add_new_executor(
site_name="my_other_site",
executor_type="local",
salvus_binary=salvus_binary,
run_directory=run_directory_2,
tmp_directory=tmp_directory_2,
use_cuda_capable_gpus=False,
default_ranks=1,
max_ranks=2,
):
# Site is available here.
sn.functions.get_site("my_other_site")Filter out the warning regarding cryptography’s moved import, as with the current environment as distributed, this doesn’t affect Salvus users.
Fix for misfit computation when time axis is improperly subsampled. Happens i.e. when the last sample on a receiver (the last simulation time step) doesn’t align with regular time grid. This occurs when using a sampling interval greater than one time step in the receiver output.
Fix bug where attenuating tensor components are not split in base and visco parts when computing wavelengths.
Add functions to compute spatial derivatives of arbitrary fields defined at the GLL points on an unstructured mesh using the Lagrangian basis.
import sympy, numpy as np
import salvus.namespace as sn
from salvus.mesh import layered_meshing as lm
n = 4 # polynomial order
domain = sn.domain.dim2.BoxDomain(x0=0, x1=1, y0=0, y1=1)
# Create a simple mesh to use as a test. Let parameters vary only in a
# single direction so that we know their gradients in advance.
mesh = lm.mesh_from_domain(
domain=domain,
model=lm.material.from_params(
vp=1 + sympy.symbols("x"), rho=sympy.symbols("v")
),
mesh_resolution=sn.MeshResolution(
reference_frequency=10.0,
elements_per_wavelength=1.0,
model_order=n,
),
)
# Compute the spatial derivatives of the model
mesh.compute_spatial_gradients(fields=["VP", "RHO"])
# VP varies only in the x direction.
np.testing.assert_allclose(mesh.element_nodal_fields["dVP/dx"], 1.0)
np.testing.assert_allclose(
mesh.element_nodal_fields["dVP/dy"], 0.0, atol=1e-10
)
# RHO varies only in the y direction.
np.testing.assert_allclose(
mesh.element_nodal_fields["dRHO/dx"], 0.0, atol=1e-10
)
np.testing.assert_allclose(
mesh.element_nodal_fields["dRHO/dy"],
1.0,
)When interpolating xarray datasets using get_interpolator(...) from
xarray_tools, faster interpolations are now provided via the fast_interp
package. This package will be used automatically if the interpolation source is
regularly spaced, 2- or 3-D, and the “linear” interpolation method is selected.
Note that if the source grid has a variable grid spacing in any one dimension
scipy’s regular grid interpolation routines will be fallen back on.
Adds a new argument enclosing_elements_method to the simple_post_refinements
generator. The default value is "inverse_coordinate_transform", which retains
legacy behavior. Another value "bounding_box" is also supported, which trades
the accuracy of the enclosing element search to performance, as only a simple
bounding box check is done to determine point ownership.
Fix a bug that erroneously tried to truncate discrete relative models when two neighboring interfaces had coincident reference elevations.
Fix a bug in the mesher where certain non-monotonic models would cause an error.
Salvus can now read Exodus files with multiple element blocks, read them partially and optionally store the element block index in the mesh.
# To attach the block ids to the mesh
m = sn.UnstructuredMesh.from_exodus(
filename, attach_element_block_indices=True
)
# To only read given blocks
m = sn.UnstructuredMesh.from_exodus(
filename, select_element_block_indices=[2, 4],
)Allow conversion of unstructured mesh parameters using
mesh.transform_parameter, which will automatically try to convert the
parameters defined on a mesh to your chosen material, if they are compatible.
Returns a new mesh. Ideal when a model in a different parametrization is
desired.
When creating meshes from materials, typically the converted mesh will be identical to a mesh generated from the converted material itself.
import salvus.namespace as sn
from salvus import material
d = sn.domain.dim2.BoxDomain(x0 =0, x1=10, y0=0,y1=10)
mr = sn.MeshResolution(reference_frequency=1)
mesh_material_iso = sn.layered_meshing.mesh_from_domain(
domain=d,
model=material.acoustic.Velocity.from_params(vp=1.0, rho=1.0),
mesh_resolution=mr,
)
mesh_material_tho = sn.layered_meshing.mesh_from_domain(
domain=d,
model=material.acoustic.elliptical_hexagonal.Velocity.from_params(
vpv=1.0, vph=1.0, rho=1.0
),
mesh_resolution=mr,
)
converted_mesh = mesh_material_iso.transform_material(
material.acoustic.elliptical_hexagonal.Velocity
)
assert converted_mesh == mesh_material_thoAn elastic version of the Thomsen parameters material
(material.elastic.hexagonal.Thomsen) is added, which has
from_acoustic which needs injection of just 2 extra parameters.
Additionally, it can convert back using to_acoustic.
Fix a bug where linear solids would not be properly passed to viscoelastic cartesian models in SalvusProject resulting in an error during mesh generation.
Changes to Experimental Features
Add a reader for specifying seismic ruptures in the Standard Rupture Format Version 2.0. This is useful for modeling a rupture along a fault by generating a collection of point sources in Salvus.
Example:
from salvus.flow.simple_config.source.srf_file_reader import _read_srf_file
from salvus.flow.simple_config.source.srf_to_salvus_sources import (
_create_sources_from_srf_data
)
srf_data = _read_srf_file(
"example.srf",
plot=True,
)
# To generate the corresponding sources in a UTM domain:
salvus_sources = _create_sources_From_srf_data(
srf_data,
utm_crs,
)
This is an experimental feature and the API might change in the future.
Add a callback function to the Mapping class which allows to postprocess proposed model updates before validation of the misfit reduction. This feature can be useful to introduce prior knowledge on material properties and to emphasize certain features in the model updates.
Example:
def fixed_vp_vs_ratio(
proposed_model: sn.UnstructuredMesh,
prior_model: sn.UnstructuredMesh,
) -> sn.UnstructuredMesh:
vp_vs_ratio = ... # some value
model_update = proposed_model.copy()
model_update.elemental_fields["VP"] = vp_vs_ratio * model_update.elemental_fields["VS"]
return model_update
mapping = sn.Mapping(
inversion_parameters=["VS"],
scaling="relative_deviation_from_prior",
postprocess_model_update=fixed_vp_vs_ratio,
)
mapping can then be passed to an InverseProblemConfiguration to enforce a
fixed VP/VS ratio without inverting for VP.