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

salvus.mesh.algorithms.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: typing.List[UnstructuredMesh],
) -> 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 typing.List[UnstructuredMesh] — List of UnstructuredMesh objects to add together.
Returns UnstructuredMesh — A new UnstructuredMesh with the same elemental fields in each summed.

compute_topological_facet_normals()

def compute_topological_facet_normals(
    topological_facets: np.ndarray, points: np.ndarray
) -> np.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 np.ndarray — An array of a mesh’s topological facets.
  • points np.ndarray — The point (node) locations of a mesh.
Returns np.ndarray

create_rotation_matrices()

def create_rotation_matrices(
    vectors_from: npt.NDArray, vectors_to: npt.NDArray
) -> npt.NDArray: ...

Create the rotation matrices for rotating vectors_from onto vectors_to. Will always create 3D rotation matrices. If either vectors_from or vectors_to is passed in shape (…, 2), zeros are appended to create 3D vectors in the last index. Follows general broadcasting rules, output shape will be np.broadcast(vectors_A, vectors_B).shape[:-1] + (3, 3). If drop_dimension is True, and one of the original input shapes was 2 dimensional, the returned rotation matrices will be 2D. This might be incorrect, if rotation in 3D is required to fully make the rotation.

Parameters
  • vectors_from npt.NDArray — Vectors to rotate from. Length of last dimensions should be 2 or 3.
  • vectors_to npt.NDArray — Vectors to rotate to. Length of last dimensions should be 2 or 3, matching vectors_from.
Returns npt.NDArray — ND Array of rotation matrices in 2 or 3 dimensions, depending on size of last dimension of both inputs — the last 2 dimensions are of shape (3, 3) or (2, 2).

disconnect_along_side_set()

def disconnect_along_side_set(
    mesh: UnstructuredMesh,
    side_set: str,
    disconnection_decider: typing.Callable[
        [UnstructuredMesh, npt.NDArray, npt.NDArray, npt.NDArray, npt.NDArray],
        typing.Iterable[bool],
    ],
) -> UnstructuredMesh: ...

Disconnect mesh along internal side set, turning it into two free surfaces.

The disconnection is made by using a callback able to tell for any element if it is on side A or side B of the disconnection, in relation to a point.

Parameters
  • mesh UnstructuredMesh — The mesh to disconnect.
  • side_set str — The internal sideset to disconnect.
  • disconnection_decider typing.Callable[[UnstructuredMesh, npt.NDArray, npt.NDArray, npt.NDArray, npt.NDArray], typing.Iterable[bool]] — A function that takes in a mesh, an array containing element and local point indices to candidates to disconnect, an array of sorted overlapping points global ids, an array of their multiplicity, and an array of offsets that indexes into the first two arrays to get the start of grouped elements.
Returns UnstructuredMesh — A new mesh with duplicated points and broken up connectivity along the desired side set.

edge_lengths()

def edge_lengths(mesh: UnstructuredMesh) -> np.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 UnstructuredMesh — The mesh to compute the edge lengths of.
Returns np.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: UnstructuredMesh) -> np.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 UnstructuredMesh — The mesh to compute the edge lengths of.
Returns np.ndarray — The edge lengths for each edge, returned as an array with dimensions (elm_id, edge_id, dim_length).

edges()

def edges(mesh: UnstructuredMesh) -> np.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 UnstructuredMesh — The mesh to get the ordered edges of.
Returns np.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: UnstructuredMesh,
    max_radius: float = 6371000.0,
    exclude_filter: typing.Optional[typing.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 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 typing.Optional[typing.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: UnstructuredMesh,
    ds: xr.Dataset,
    pars: typing.Union[str, typing.List[str]],
    max_tree_doublings: int = 4,
    verbose: bool = False,
) -> xr.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 UnstructuredMesh — The mesh to interpolate from.
  • ds xr.Dataset — Xarray dataset with coordinates to interpolate to.
  • pars typing.Union[str, typing.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 xr.Dataset — Xarray dataset with values interpolated.

get_enclosing_elements()

def get_enclosing_elements(
    mesh: _ElementCollectionProtocol,
    points: np.ndarray,
    max_tree_doublings: typing.Union[str, int] = "auto",
    allow_points_outside_mesh: bool = True,
    verbose: bool = False,
    element_restrict: typing.Optional[np.ndarray] = None,
    point_restrict: typing.Optional[np.ndarray] = None,
) -> typing.Tuple[np.ndarray, np.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 _ElementCollectionProtocol — Mesh to query.
  • points np.ndarray — Array of query points, dimension [n_points, d].
  • max_tree_doublings typing.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 typing.Optional[np.ndarray] — Only interpolate from elements with these ids.
  • point_restrict typing.Optional[np.ndarray] — Only interpolate to these point indices.
Returns typing.Tuple[np.ndarray, np.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: UnstructuredMesh,
    m_fine: UnstructuredMesh,
    number_of_neighbours: int = 8,
    verify: bool = True,
) -> np.ndarray: ...

Find the hierarchical map between two meshes.

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

get_internal_side_set_facets()

def get_internal_side_set_facets(
    mesh: UnstructuredMesh, side_set: str
) -> typing.Tuple[npt.NDArray, npt.NDArray]: ...

Get the internal facets of a sideset, i.e. those that have two surrounding elements, and the respective elements.

Parameters
  • mesh UnstructuredMesh — The mesh.
  • side_set str — The sideset.
Returns typing.Tuple[npt.NDArray, npt.NDArray] — A tuple of 2d arrays with facet pair ids and element pair ids respectively.

get_interpolation_coefficients()

def get_interpolation_coefficients(
    mesh: _ElementCollectionProtocol, points: np.ndarray
) -> npt.NDArray: ...

Get the interpolation coefficients for a series of reference coordinates.

Parameters
  • mesh _ElementCollectionProtocol — The mesh object to query.
  • points np.ndarray — The points to get the interpolation coordinates for.
Returns npt.NDArray — The interpolation coefficients for each point.

get_side_set_elevations()

def get_side_set_elevations(
    mesh: UnstructuredMesh, side_set: str, points: npt.NDArray
) -> npt.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.

For Cartesian and 2-D spherical domains 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. For 3-D spherical domains the result is an approximation built by projecting the points to a set of triangles that span each element.

Parameters
  • mesh UnstructuredMesh — The mesh to extract a side set from.
  • side_set str — The side set to extract.
  • points npt.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 npt.NDArray — A 1-D coordiante array of the elevations evaluated at each horizontal point location.

get_surface_unit_vectors()

def get_surface_unit_vectors(
    points: npt.NDArray, mesh: UnstructuredMesh, side_set: str
) -> npt.NDArray: ...

Get the surface unit vectors of a mesh relative to a side set, for specific points.

Parameters
  • points npt.NDArray — Points to return surface vectors on. Need to lie on the sideset. Should be of shape (N, mesh.ndim).
  • mesh UnstructuredMesh — Mesh to calculate surface vectors on.
  • side_set str — Side set to calculate surface vectors relative to.
Returns npt.NDArray — Surface vectors.

get_topological_facets()

def get_topological_facets(mesh: UnstructuredMesh) -> npt.NDArray: ...

Get an array of node ids corresponding to each facet in the mesh.

The facets returned here are “topological” in that they only consider the mesh’s first-order connectivity. Returns an array of shape (n_elem, n_facet_per_elem, n_nodes_per_facet). Facet ordering is as followings:

2D Quad: bottom, top, right, left. 3D Hex: Left, right, bottom, top, back, front.

Parameters
  • mesh UnstructuredMesh — The mesh.
Returns npt.NDArray

interpolate_from_element_nodes()

def interpolate_from_element_nodes(
    ref: npt.NDArray, values: npt.NDArray, n_dim: int, num_threads: int = 16
) -> typing.Tuple[npt.NDArray, npt.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 npt.NDArray — An array of shape [n_pnt, n_dim] reference coordinates.
  • values npt.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 typing.Tuple[npt.NDArray, npt.NDArray] — A tuple consisting of the transformed coordiantes and the evaluated lagrange polynomials.

inverse_coordinate_transform()

def inverse_coordinate_transform(
    control_nodes: npt.NDArray,
    points: npt.NDArray,
    max_iter: int = 100,
    rtol: float = 1e-08,
    atol: float = 1e-11,
    atol_ref: float = 0.001,
    num_threads: int = 16,
) -> typing.Tuple[npt.NDArray[np.float_], npt.NDArray[np.int_]]: ...

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

Parameters
  • control_nodes npt.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 npt.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 typing.Tuple[npt.NDArray[np.float_], npt.NDArray[np.int_]] — 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: UnstructuredMesh, name: str) -> None: ...

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

Parameters
  • 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: UnstructuredMesh,
    block: typing.Union[int, typing.List[int]],
    top_side_set: str,
    bot_side_set: str,
) -> typing.Tuple[npt.NDArray, npt.NDArray, npt.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 UnstructuredMesh — The mesh to normalize coordiantes from.
  • block typing.Union[int, typing.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 typing.Tuple[npt.NDArray, npt.NDArray, npt.NDArray] — A tuple containing: 1. 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. 2. The elevation of the top side set. 3. The elevation of the bottom side set.

read_model_from_h5()

def read_model_from_h5(
    filename: typing.Union[str, pathlib.Path],
    fields: typing.Optional[typing.Sequence[str]] = None,
) -> typing.Dict[str, np.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 typing.Union[str, pathlib.Path] — Mesh file.
  • fields typing.Optional[typing.Sequence[str]] — Optional field names to read.
Returns typing.Dict[str, np.ndarray]

remove_from_side_set()

def remove_from_side_set(
    mesh: UnstructuredMesh,
    side_set: str,
    indices_to_remove: typing.Optional[npt.NDArray] = None,
    indices_to_retain: typing.Optional[npt.NDArray] = None,
) -> None: ...

Remove or retain facets from side set by index, operating on the passed mesh. Facets are indexed according to their order of appearance in mesh.side_sets[side_set].

Parameters
  • mesh UnstructuredMesh — The mesh to modify.
  • side_set str — The side set to modify.
  • indices_to_remove typing.Optional[npt.NDArray] — Facets to be removed. Must be None if indices_to_retain is not.
  • indices_to_retain typing.Optional[npt.NDArray] — Facets to be retained. Must be None if indices_to_remove is not.
Returns None

retain_unique_facets()

def retain_unique_facets(
    mesh: UnstructuredMesh, side_set: str, verbosity: int = 0
) -> None: ...

Retain only facets in side set that don’t appear in other sidesets, deleting the side set if it becomes empty.

Parameters
  • mesh UnstructuredMesh — Mesh.
  • side_set str — Sideset to reduce to uniquely appearing facets.
  • verbosity int — Verbosity of the operation, informing how side-set is altered.
Returns None

uniquefy_side_sets()

def uniquefy_side_sets(
    mesh: UnstructuredMesh,
    order: typing.Optional[typing.Iterable[str]] = None,
    verbosity: int = 0,
) -> None: ...

Retain only unique facets in side sets, deleting empty side sets.

The order influences what elements are retained. The algorithm will remove facets from sidesets in this order, i.e. the first side set has all facets subtracted that occur in other side sets. Side sets appearing earlier will have more facets removed. Empty side sets will not be retained.

Parameters
  • mesh UnstructuredMesh — Mesh.
  • order typing.Optional[typing.Iterable[str]] — Order in which the sidesets are parsed.
  • verbosity int — Verbosity of the operation, informing how side-sets are altered.
Returns None