Mondaic

Salvus 2025.1.1

Released: 2025-07-22

This release brings a range of improvements, new features, and bug fixes across the Salvus ecosystem. Key public developments include a faster regular grid extraction for Cartesian meshes, new customization options for preconditioners and the trust region optimization, and a QC measures for meshes and material.

Furthermore, we improved the documentation and fixed a few bugs listed below.

Changes

SalvusCompute

The computation of the Jacobians for reference -> physical element mappings has been updated and improved, which should result in speedups for the simulation setup stage.

SalvusCore

Fixed an edge case in the serialization logic of functions containing paths on Windows.

SalvusFlow

Fix component names for rotated receivers and HDF5 receiver file output.

SalvusFlow

Special paramiko connection arguments can now be separately configured for the direct connection + the jump host connection to deal with tricky cases.

Usage in the site config file:

[sites.my_site.ssh_settings]
    hostname = "some_host"
    username = "some_user"
    # Example: Disable different pubkey algorithms for the direct + jump host.
    [sites.my_site.ssh_settings.extra_paramiko_connect_arguments.disabled_algorithms]
        pubkeys = ["rsa-sha2-512"]
    [sites.my_site.ssh_settings.extra_paramiko_connect_arguments_jump_host.disabled_algorithms]
        pubkeys = ["rsa2-sha2-256"]
SalvusMaterial

Fix the __repr__ methods of the oriented and attenuating materials.

SalvusMaterial

Bugfix for a case where realization information would be lost when copying symmetric tensor components.

SalvusMesh

extract_model_to_regular_grid() is now significantly more performant for cartesian meshes. Since the underlying algorithm was changed, the results can be slightly different compared to what was obtained with the previous version. The updated function is parallelized and, by default, uses the maximum number of cores available on your system. You can limit the number of cores like this:

from salvus.mesh.algorithms.unstructured_mesh.utils (
    import extract_model_to_regular_grid
)

extract_model_to_regular_grid(number_of_threads=4)
SalvusMesh

Added better documentation to UnstructuredMesh.rotate_coordinates. It should now be clear in which convention the rotations are applied, and what the units of the angles are.

SalvusMesh

Add QC system to materials and meshes, accessed by the member function mesh.qc_test() or material.qc_test(). This will run a set of tests on the mesh or material and return a dictionary with possible issues of varying severity. The tests are not exhaustive, but should catch common issues.

SalvusMesh API CHANGE

Fix a bug that could cause a meshing failure when using anisotropic elements per wavelength with absorbing boundaries. The fix involved changing the signature of some public-facing layered model reductions. In particular, the signatures for both get_min_wavelength_reduction_function and get_max_element_size_reduction_function have been updated to be more explicit, and now directly take the reference frequency and elements per wavelength as parameters.

SalvusMesh

Add a new model filter in salvus.mesh.layered_meshing.layered_model.filters that allows for the selective resolution of s-waves based on the VP vs ratio. Primarily, this function take a parameter alpha. If alpha is 0, this means that the mesh’s resolution criterion is set only by the P-wave model, and when it is 1 it means the S-wave model is also resolved to the same degree. Values between 0 and 1 indicate partial resolution of the S-wave model, with a linear taper between wavelength oracles for the P- and S-wave components.

SalvusOpt

Users can now pass a custom preconditioner to an InverseProblemConfiguration. Custom preconditioners have to be defined as a callback function with a single input argument unstructured_mesh, corresponding to an UnstructuredMesh object and must again return an UnstructuredMesh object with the custom preconditioner applied.

Example:

import salvus.namespace as sn

# Define a custom preconditioner that applies a depth-dependent scaling
# to the gradient
def custom_preconditioner(unstructured_mesh):
    # Apply a depth-dependent scaling
    alpha = 1.0
    beta = 2.0
    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

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,
    job_submission=sn.SiteConfig("local", 4),
)
SalvusOpt

TrustRegion objects now accept an optional input argument to set a maximum number of trial model rejections. Once this number is exceeded, the inversion will either fail or accept the final model of the previous iteration and continue with the next iteration, depending on the setting chosen by the user.

Example:

import salvus.namespace as sn

sn.TrustRegion(
    max_trial_models_per_iteration=5,
    fail_if_max_trial_models_reached=False,
)
SalvusOpt

Relax validation of the mapping class in the presence of a region of interest. The parameter fields will only be checked for consistency inside the region of interest. This is necessary, for instance, when using a custom scaling when inverting elastic parameters in a coupled medium.

SalvusOpt

Add the ability to determine the initial trust region radius in a callback function. This is useful when the desired magnitude of the update is space- dependent.

Example:

def initial_radius_callback(
    current_model: UnstructuredModel, proposed_update: UnstructuredModel
) -> float:
    '''
    Simple callback function to return the step size.

    Args:
        current_model: The current model in the inversion.
        proposed_update: The proposed model update.

    Returns:
        A scalar factor by which the proposed model will be scaled.
    '''
    factor = 1.0 / proposed_update.norm_inf()
    return factor

tr = TrustRegion(
    initial_trust_region_linf=initial_radius_callback,
)
SalvusProject

Fixed a bug that resulted in the waveform visualization widget and the window picking function to be significantly less responsive and slower for large seismological data sets.

SalvusProject

Preserve the order of events in project operations.

p.waveforms.get(..., events=["event2", "event1"]) will for example now return the events in the order specified by the user.

SalvusProject

p.simulations.launch() now raises a consistent and correct error message it the site requires a wall time to be set.

SalvusProject

Fix a bug for Cartesian meshes where the material properties of an explicitly defined ocean layer would be overwritten by a volume model.