Mondaic
This API reference is not for the latest stable Salvus version.

salvus.mesh.unstructured_mesh_utils

A set of routines to help with some mesh operations. Moving out of the unstructured mesh class as it is getting too large.

Functions

add_element_nodal_fields()

def add_element_nodal_fields(
    meshes: List[salvus.mesh.unstructured_mesh.UnstructuredMesh],
) -> salvus.mesh.unstructured_mesh.UnstructuredMesh:
    ...

Sum the element nodal fields with the same name across several meshes.

Meshes must have identical points, element nodal fields names, and connectivity. Only fields with the same names across all mesh instances will be summed.

Parameters
  • meshes List[salvus.mesh.unstructured_mesh.UnstructuredMesh] — List of UnstructuredMesh objects to add together.
Returns salvus.mesh.unstructured_mesh.UnstructuredMesh — A new UnstructuredMesh with the same elemental fields in each summed.

compute_topological_facet_normals()

def compute_topological_facet_normals(
    topological_facets: numpy.ndarray, points: numpy.ndarray
) -> numpy.ndarray:
    ...

Compute unit normal vectors for each topological facet on each element.

As topological facets are required for this function, it is not suitable for general normal vector computation (see the salvus.fem.jacobian module for this use case). This function is useful, however, if one wants to cheaply compute the general orientation of a facet.

Parameters
  • topological_facets numpy.ndarray — An array of a mesh’s topological facets.
  • points numpy.ndarray — The point (node) locations of a mesh.
Returns numpy.ndarray

edge_lengths()

def edge_lengths(
    mesh: salvus.mesh.unstructured_mesh.UnstructuredMesh,
) -> numpy.ndarray:
    ...

Compute the edge lengths along each edge of each element.

The ordering, in the reference element, is consistent with the DMPLEX ordering

2-D: bottom, right, top, left 3-D: bottom left, bottom back, bottom right, bottom front, top front, top right, top back, top left, front right, front left, back left, back right

Parameters
  • mesh salvus.mesh.unstructured_mesh.UnstructuredMesh — The mesh to compute the edge lengths of.
Returns numpy.ndarray — The edge lengths for each edge, returned as an array with dimensions (elm_id, edge_id).

edge_lengths_projected()

def edge_lengths_projected(
    mesh: salvus.mesh.unstructured_mesh.UnstructuredMesh,
) -> numpy.ndarray:
    ...

Compute the edge lengths for each coordinate direction.

The ordering, in the reference element, is consistent with the DMPLEX ordering

2-D: bottom, right, top, left 3-D: bottom left, bottom back, bottom right, bottom front, top front, top right, top back, top left, front right, front left, back left, back right

Parameters
  • mesh salvus.mesh.unstructured_mesh.UnstructuredMesh — The mesh to compute the edge lengths of.
Returns numpy.ndarray — The edge lengths for each edge, returned as an array with dimensions (elm_id, edge_id, dim_length).

edges()

def edges(
    mesh: salvus.mesh.unstructured_mesh.UnstructuredMesh,
) -> numpy.ndarray:
    ...

Get an ordered list of the first-order edges for each element.

The ordering, in the reference element, is consistent with the DMPLEX ordering

2-D: bottom, right, top, left 3-D: bottom left, bottom back, bottom right, bottom front, top front, top right, top back, top left, front right, front left, back left, back right

Parameters
  • mesh salvus.mesh.unstructured_mesh.UnstructuredMesh — The mesh to get the ordered edges of.
Returns numpy.ndarray — The edge lengths for each edge, as ordered above, concatenated along the first axis, so that the dimensions are (elm_id, edge_id, vertex, crd).

extract_conservative_bm_file()

def extract_conservative_bm_file(
    mesh: salvus.mesh.unstructured_mesh.UnstructuredMesh,
    max_radius: float = 6371000.0,
    exclude_filter: Optional[Tuple[str, int]] = None,
) -> str:
    ...

Get a BM file containing minimum parameter values and discontinuities.

Useful to extract a bm file the preserves discontinuities, and contains the min parameter value in each layer. Can be used, along with a mesh-to-mesh interpolation routine, as a background model when a) re-meshing for a higher frequency, or b) re-meshing because material velocities have reduced below some threshold.

The successful use of this routines requires that the parameter "z_node_1D" be present as an element nodal field in the mesh, and that it represents the normalized z-coordinate. The normalized value of this parameter will be clipped to a maximum value of 1.0, in case intermediate mesh manipulations resulted in the stretching of the 1-D radial values.

Parameters
  • mesh salvus.mesh.unstructured_mesh.UnstructuredMesh — The mesh to extract the 1-D model from.
  • max_radius float — The maximum radius of the 1-D model. Defaults to 6371e3.
  • exclude_filter Optional[Tuple[str, int]] — An additional flag which can be passed to ensure that certain elements are not considered in BM file generation. In a global mesh with real oceans, a common use for this parameter might be to exclude all fluid elements in the BM file generation. This could be done, for example, by passing the tuple ("fluid", 1).
Returns str — A string which can be immediately written to a BM file and used in re-meshing.

extract_model_to_regular_grid()

def extract_model_to_regular_grid(
    mesh: salvus.mesh.unstructured_mesh.UnstructuredMesh,
    ds: xarray.core.dataset.Dataset,
    pars: Union[str, List[str]],
    max_tree_doublings: int = 4,
    verbose: bool = False,
) -> xarray.core.dataset.Dataset:
    ...

Return interpolated model values at locations defined by an xarray dataset.

It is often useful to visualize slices of a 3-D model, or to just in general have a regularly-gridded representation of a model for analysis. This function allows one to generate such a representation. As input, it takes a mesh, n xarray dataset, and a list of parameters to extract. The xarray dataset is likely the only parameter which is not self-explanatory. Here one must pass a dataset with one of the following sets of coordinate dimensions:

{"x", "y"},
{"x", "y", "z"},
{"latitude", "longitude", "radius"}, or
{"latitude", "longitude", "depth"}.

An error will be thrown if the dataset’s coordinate dimensions do not match exactly one of the above. Additionally, if the “depth” variant is chosen, a “radius_in_meters” global dataset attribute must also be present. Parameters also must, of course, exist in the mesh.

This runtime of this function will scale with both a) the number of elements in the mesh, and b) the number of point locations in the xarray dataset. Good performance on most machines is expected (for example, extracting 10,000 points from a 100k element mesh should take less than a second on most machines), but in principle the cost of this function can be as large as you like. Passing verbose = True here could give you insight on how long a longer-running call might take, as it will provide a progress bar of the algorithm’s current state.

For some troublesome points, it may be a nontrivial task to find an enclosing element in the mesh. In this case, max_tree_doublings controls the maximum amount of times that a search will be retried for a delinquent point; in each pass the number of elements searched will be doubled. If an element truly is outside of the mesh (as it may well be when interpolating from a spherical domain), extracted values at those points after max_tree_doublings tries will be marked with np.nan — no extrapolation is performed. This convention was chosen to match the standard xarray and CF convention for missing data.

The grids extracted can be visualized in a number of ways, including with xarray directly and with PyGMT. A nice example of how to visualize something with xarray using a map can be found here: http://xarray.pydata.org/en/stable/plotting.html#maps.

Parameters
  • mesh salvus.mesh.unstructured_mesh.UnstructuredMesh — The mesh to interpolate from.
  • ds xarray.core.dataset.Dataset — Xarray dataset with coordinates to interpolate to.
  • pars Union[str, List[str]] — Parameters to interpolate.
  • max_tree_doublings int — Maximum number of times the number of closest candidate elements will be doubled. Doubling only occurs for points which were not already claimed by previous passes. Defaults to 4.
  • verbose bool — Show a progress bar. Defaults to False.
Returns xarray.core.dataset.Dataset — Xarray dataset with values interpolated.

get_enclosing_elements()

def get_enclosing_elements(
    mesh: salvus.mesh.unstructured_mesh_utils._ElementCollectionProtocol,
    points: numpy.ndarray,
    max_tree_doublings: Union[str, int] = "auto",
    allow_points_outside_mesh: bool = True,
    verbose: bool = False,
    element_restrict: Optional[numpy.ndarray] = None,
    point_restrict: Optional[numpy.ndarray] = None,
) -> Tuple[numpy.ndarray, numpy.ndarray]:
    ...

Get the indices of the enclosing element given an array of points.

It is often helpful to know within which element a given spatial point lies. Given an array of points and a mesh, this function will return indices that correspond to the elements containing each point in the input array. The second element of the returned tuple contains the point’s position in reference coordinates with respect to the corresponding element ID. If an enclosing element is not found and no interrupt is passed, the returned element index will be -(closest_centroid_element_id + 1), and the reference coordinates will be outside of the canonical interval (outside [-1, +1]). This allows for extrapolation if required.

The internal algorithm will begin by trying to quickly extract the closest element to a given point. The points that remain unfound after one pass of this are re-injected into the algorithm with the search size being doubled each time. This continues recursively until max_tree_doublings is reached. For well behaved meshes, the enclosing element should just be found in at most a few passes (likely just one). If you are having issues with unclaimed points, you can try increasing the iteration count. Note: be careful to ensure that most of your points are actually in the domain! The algorithm can get slow at higher iteration counts, so it pays to match up your input point extents with the mesh extents as much as possible.

The behavior of the algorithm in the case where a point is outside all elements can be controlled with the allow_points_outside_mesh flag. If this is set to false, then the function will throw if a single point remains unclaimed after max_tree_doublings. This may suggest that either a) the point is indeed outside the mesh (in which case no extrapolation is performed), or b) more iterations are needed.

Parameters
  • mesh salvus.mesh.unstructured_mesh_utils._ElementCollectionProtocol — Mesh to query.
  • points numpy.ndarray — Array of query points, dimension [n_points, d].
  • max_tree_doublings Union[str, int] — Finding the enclosing element may be nontrivial in deformed meshes. The internal algorithm will double the number of closest candidate elements considered in each retry. Defaults to 4 doublings.
  • allow_points_outside_mesh bool — In some cases, it may be acceptable for some points to be located outside of the queried mesh. If this flag is set to true, an exception will not be thrown if this is the case. Points which are flagged as outside the mesh will have their corresponding element indices set to -(closet_centroid_element_id + 1). Defaults to True.
  • verbose bool — Show a progress bar. Also, if the query fails, setting verbose to true will print the indices of the failed points. Defaults to False.
  • element_restrict Optional[numpy.ndarray] — Only interpolate from elements with these ids.
  • point_restrict Optional[numpy.ndarray] — Only interpolate to these point indices.
Returns Tuple[numpy.ndarray, numpy.ndarray] — An tuple with 1. an array of indices with enclosing element IDs in the same order as points, and 2. the corresponding location in reference coordinates.

get_hierarchical_map()

def get_hierarchical_map(
    m_coarse: salvus.mesh.unstructured_mesh.UnstructuredMesh,
    m_fine: salvus.mesh.unstructured_mesh.UnstructuredMesh,
    nneighbour: int = 8,
    check_m_fine_is_refinement: bool = True,
) -> numpy.ndarray:
    ...

create a hierarchical map from another unstructured mesh to this one, i.e. other is a refinement of self.

Parameters
  • m_coarse salvus.mesh.unstructured_mesh.UnstructuredMesh — the coarser mesh
  • m_fine salvus.mesh.unstructured_mesh.UnstructuredMesh — the finer mesh
  • nneighbour int — number of neighbours to use in tree search
  • check_m_fine_is_refinement bool — verify that m_fine actually is a refinement of m_coarse.
Returns numpy.ndarray

get_interpolation_coefficients()

def get_interpolation_coefficients(
    mesh: salvus.mesh.unstructured_mesh_utils._ElementCollectionProtocol,
    points: numpy.ndarray,
) -> numpy.ndarray:
    ...

Get the interpolation coefficients for a series of reference coordinates.

Parameters
  • mesh salvus.mesh.unstructured_mesh_utils._ElementCollectionProtocol — The mesh object to query.
  • points numpy.ndarray — The points to get the interpolation coordinates for.
Returns numpy.ndarray — The interpolation coefficients for each point.

get_side_set_elevations()

def get_side_set_elevations(
    mesh: salvus.mesh.unstructured_mesh.UnstructuredMesh,
    side_set: str,
    points: numpy.ndarray,
) -> numpy.ndarray:
    ...

Get the elevation values on a side set.

This routine:

- Finds the elements that enclose a set of points
- Interpolates the vertical coordinate value from the nodes of element
  to those points.

This is done using the Lagrange basis of the element itself, so the elevation values returned are an accurate representation of the side set’s elevation as discretized by a given mesh.

Parameters
  • mesh salvus.mesh.unstructured_mesh.UnstructuredMesh — The mesh to extract a side set from.
  • side_set str — The side set to extract.
  • points numpy.ndarray — The points to extract to. Should be an array of shape [n_pnt, n_dim_mesh - 1], i.e. only horizontal coordinates should be passed.
Returns numpy.ndarray — A 1-D coordiante array of the elevations evaluated at each horizontal point location.

interpolate_from_element_nodes()

def interpolate_from_element_nodes(
    ref: numpy.ndarray,
    values: numpy.ndarray,
    n_dim: int,
    num_threads: int = 32,
) -> Tuple[numpy.ndarray, numpy.ndarray]:
    ...

Interpolate values from element nodes to reference coordiantes.

This function also returns polynomials evaluated at each point in reference coordinates as these are useful for further calculations.

Parameters
  • ref numpy.ndarray — An array of shape [n_pnt, n_dim] reference coordinates.
  • values numpy.ndarray — An array of shape [n_pnt, n_ctrl], or [n_pnt, n_ctrl, n_par], containing the values of the field to interpolate.
  • n_dim int — The number of dimensions.
  • num_threads int — The number of threads to use in parallel execution.
Returns Tuple[numpy.ndarray, numpy.ndarray] — A tuple consisting of the transformed coordiantes and the evaluated lagrange polynomials.

inverse_coordinate_transform()

def inverse_coordinate_transform(
    control_nodes: numpy.ndarray,
    points: numpy.ndarray,
    max_iter: int = 100,
    rtol: float = 1e-08,
    atol: float = 1e-11,
    atol_ref: float = 0.001,
    num_threads: int = 32,
) -> Tuple[numpy.ndarray, numpy.ndarray]:
    ...

Find the reference coordinates of a point w.r.t. a given element geometry.

Parameters
  • control_nodes numpy.ndarray — The tensorized control nodes defining the element’s (or it’s facet’s, or ridge’s) geometry. Should be of dimension [n_trial_points, n_ctrl_nodes, n_dim].
  • points numpy.ndarray — The point to locate within the element. Should be of dimension [n_trial_pnts, d_dim].
  • max_iter int — The maximum number of iterations to attempt.
  • rtol float — The relative tolerance that determines whether a point is considered as inside an element.
  • atol float — The absolute tolerance that determines whether a point is considered as inside the element.
  • atol_ref float — The tolerance in reference coordinates that determines whether a point is considered inside the element.
  • num_threads int — The number of threads to use for parallel opertions.
Returns Tuple[numpy.ndarray, numpy.ndarray] — A tuple containing: - an array of each point’s reference coordinte, and - an array of the indices of the enlcosing elements, the ordering of which is determined by the leading axes of pnts and cntrl, respectively.

name_free_side_set()

def name_free_side_set(
    mesh: salvus.mesh.unstructured_mesh.UnstructuredMesh, name: str
) -> None:
    ...

Assign a side set to all facets on a mesh’s surface that aren’t in one.

Parameters
  • mesh salvus.mesh.unstructured_mesh.UnstructuredMesh — The mesh to assign the new side set to. Will be mutated in place.
  • name str — The name of the new side set.
Returns None — Nothing, mesh is mutated in place.

normalize_block_coordinates()

def normalize_block_coordinates(
    mesh: salvus.mesh.unstructured_mesh.UnstructuredMesh,
    block: Union[int, List[int]],
    top_side_set: str,
    bot_side_set: str,
) -> numpy.ndarray:
    ...

Normalize vertical coordiantes between two side sets.

It is sometimes desirable to rescale the vertical coordinates of a collection of elements to the range [0, 1] to, for instance, interpolate material parameters defined in terms of thickness or relative coordinates. This function performs that rescaling.

Parameters
  • mesh salvus.mesh.unstructured_mesh.UnstructuredMesh — The mesh to normalize coordiantes from.
  • block Union[int, List[int]] — The block ID, or a list of block IDS, of the elements to be normalized.
  • top_side_set str — The top side set of the normalized region.
  • bot_side_set str — The bottom side set of the normalized region.
Returns numpy.ndarray — The coordinates with the vertical values normalized to the range [0, 1]. A vertical coordinate of 0.0 indicates that the point is coincident with the bottom side set, while 1.0 marks the top side set.

read_model_from_h5()

def read_model_from_h5(
    filename: Union[str, pathlib.Path], fields: Optional[Sequence[str]] = None
) -> Dict[str, numpy.ndarray]:
    ...

Read a model from a mesh file and return it as a dictionary. The function supports reading only a subset of fields using the optional argument fields.

Parameters
  • filename Union[str, pathlib.Path] — Mesh file.
  • fields Optional[Sequence[str]] — Optional field names to read.
Returns Dict[str, numpy.ndarray]