Salvus 2025.1.2
This is a minor release bringing in a range of improvements and bug fixes.
Notable changes include the ability to accurately compute a stable time step in Python prior to the simulation and new customization options for preconditioners and data selection routines.
This release also includes various internal improvements, bug fixes, and enhancements to stability and performance. Please refer to the detailed changelog for a complete list of changes.
Changes
Support for NumPy 2.0 and later versions. Numpy 1 is also still supported.
To upgrade, please reinstall your Salvus Mamba environment following the instructions on docs.mondaic.com.
Fix a bug that would prevent the temporal interpolation of data with a time axis specified in UTC time.
Ensure that the order of dependent functions in serialized code is deterministic.
Improve error reporting for using task chains.
Fix gradient validation tests for simultaneously testing multiple events.
p.actions.validation.validate_model_gradients() will now return dictionaries
with the finite-difference approximation and errors of each event, as well as
the aggegrated gradient from all events, which is available from the key
cumulative.
Allow for a more ergonomic way to add topography, bathymetry, and ocean loading
to smoothiesem meshes. In particular, a new function was added named
add_spherical_topography_and_bathymetry_to_model in the
_recipes.smoothiesem module which assists in adding topography to a
smoothiesem mesh.
Improve the Python-side computation of time steps for meshes by adding
UnstructuredMesh.compute_time_step. This method accounts for spectral
wavefield order and defaults to the Courant numbers used in SalvusCompute: 0.6
for 2D simulations and 0.47 for 3D simulations. The method
UnstructuredMesh.estimate_time_step has also been refined to produce results
matching those in SalvusCompute, but still allows for computationally cheaper
estimation of the time step.
Enable passing extra keywords arguments to a custom preconditioner callback.
Example:
# Custom preconditioner function with two extra keyword arguments `alpha` and
# `beta`.
def custom_preconditioner(unstructured_mesh, alpha, beta):
# Apply a depth-dependent scaling
scaling = (
alpha * (1.0 + np.abs(unstructured_mesh.get_element_nodes()[..., -1]))
) ** beta
inversion_parameters = ["VP", "VS", "RHO"]
for field in inversion_parameters:
unstructured_mesh.elemental_fields[field] *= scaling
return unstructured_mesh
# When passing the function to an inverse problem configuration, make sure to
# also pass the extra keyword arguments.
sn.InverseProblemConfiguration(
name="inversion",
prior_model="prior_model",
events=["event"],
method=sn.TrustRegion(initial_trust_region_linf=0.1),
misfit_configuration="L2",
mapping=sn.Mapping(
scaling="relative_deviation_from_prior",
inversion_parameters=["VP", "VS", "RHO"],
),
preconditioner=custom_preconditioner,
extra_kwargs_preconditioner={
"alpha": 1.0,
"beta": 2.0,
}
job_submission=sn.SiteConfig("local", 4),
)Enable passing extra keywords arguments to a custom temporal weights function.
Example:
def select_data(data_array, event, station_list, components):
'''
A temporal weights function that selects a subset of the data. It
includes the extra keyword arguments `station_list` and `components`,
specifying the components and stations that are kept.
'''
selection = [
(station, component)
for station, component in set(data_array.trace.data)
if (component in components and station in station_list)
]
weights = (data_array.sel(trace=selection)) * 0.0 + 1.0
weights.coords["trace_weights"] = (
("trace",),
np.ones(len(selection), dtype=np.float64),
)
return weights
# You can add this function to a project via a DataSelectionConfiguration
# where you would additionally pass a dictionary with the extra keyword
# arguments as so:
dsc = sn.DataSelectionConfiguration(
name="custom_data_selection",
receiver_field="displacement",
data_selection_function=select_data,
extra_kwargs_data_selection={
"station_list": ["XX.AA1.", "XX.AA2."],
"components": ["Z"],
}
)Changes to Experimental Features
Fix a bug in the SRF reader (standard rupture format) that caused seismic moments to be off by a factor 10.
All inputs from the SRF file are now converted already at the time of parsing
the file, and the dictionary returned by _read_srf_file will contain all
quantities in SI units.