reduce_on_subface#
- iskra.topology.reduce_on_subface(data: Tensor, faces: Tensor, n_subfaces: int, reduce: Literal['sum', 'prod', 'mean', 'amax', 'amin'], data_ndim: int | None = None, batch_ndim: int = 0) Tensor[SOURCE]#
Scatter-reduce data from faces onto constitutive subfaces.
This function distributes, i.e., scatters, data (scalar, vector, tensor, etc.) defined on faces to each face’s subfaces. A naive scatter would result in each subface receiving multiple competing values, one for each face that contains it. Therefore, each operation is actually a scatter-reduce (see
reduceargument). So, e.g., a triangle face can scatter its value to its 3 edges. That value is then, e.g., averaged onto each edge with the values of the other triangles that share that same edge.The function slices up the data tensor into three parts: [Bs, Fs, Ds], where Bs is the batch shape, Ds are the data payload dimensions; Fs represents the “domain” of the data. Most commonly Fs is either [F] or [F, FS]. For example, on a triangle mesh, Fs = [F] implies one data payload per triangle, whereas Fs = [F, 3] implies one data payload per triangle-corner or triangle-side.
Data dimensions are greedy when
data_ndimisNone: we assume Fs = [F] and that everything to the right of Fs is the data payload. E.g., if data.shape = [B, F, 3, 3] and Fs = [F], we have one data payload per face, whereas if Fs = [F, 3], we have one data payload per triangle-corner.Caution
The function should generalize to nested subfaces indices, i.e., Fs=[F, FSs]. For example, it should handle data defined on a tetrahedron’s side-triangles’ corners (Fs=[Tets, 3, 3]), but this is untested! If you have a real-world example of data stored on subfaces of subfaces, let me know and I can look into it!
Tip
This function is one of the three building blocks of
iskra’s scatter-gather framework, together withiskra.topology.get_subfaces()which constructs the face hierarchy andiskra.topology.face_index(), which performs the gather operation.This function moves data down the face hierarchy.
See Scatter-Gather Dataflow in iskra ✨ for an explanation of
iskra’s tensor-based scatter-gather framework.- Parameters:
data (
Tensor[DType, [Bs, Fs, Ds]]) – Data defined on mesh faces (Fs=[F]) or face-subfaces (Fs=[F, FS]).faces (
Tensor[Int64, [Bs, F, FS]]) – Face-subface indices.n_subfaces (int) – Total number of subfaces in the mesh (e.g., total number of vertices or edges in a triangle mesh).
reduce (Literal["sum", "prod", "mean", "amax", "amin"]) – Reduction operation, see
torch.scatter_reduce()for more details.data_ndim (int | None) – Num. dimensions of the per-face (or per-face-subface) payload. See above for more details on default behavior.
batch_ndim (int) – Num. batch dimensions.
- Returns:
(
Tensor[DType, [Bs, S, Ds]]) – Data reduced onto the S subfaces, (where
:abbr:`S (Number of subfaces in the mesh. Usually S is documented together with some F as point of reference. E.g., if F is the number of triangles, S could be the number of edges or vertices in the mesh.)`equals the value of the argumentn_subfaces.)
Example
data.shapefaces.shapedata_ndimresult.shapeExample: from → to
[B, F]
[B, F, 3]
0[B, V]
face scalars → vertices
[B, F, 3]
[B, F, 3]
0[B, V]
corner scalars → vertices
[B, F, 2]
[B, F, 3]
1|None[B, V, 2]
face 2-vectors → vertices
[B, F, 3, 2]
[B, F, 3]
1[B, V, 2]
corner 2-vectors → vertices
[B, F, 3]
[B, F, 3]
1|None[B, V, 3]
face normals → vertices
[B, F, 3, 3]
[B, F, 3]
1[B, V, 3]
corner normals → vertices
[B, F, 3, 3]
[B, F, 3]
2|None[B, V, 3, 3]
face covariances → vertices