warp.fem#

The warp.fem module is designed to facilitate solving physical systems described as differential equations. For example, it can solve PDEs for diffusion, convection, fluid flow, and elasticity problems using finite-element-based (FEM) Galerkin methods and allows users to quickly experiment with various FEM formulations and discretization schemes.

Integrands#

The core functionality of the FEM toolkit is the ability to integrate constant, linear, and bilinear forms over various domains and using arbitrary interpolation basis.

The main mechanism is the integrand() decorator, for instance:

@integrand
def linear_form(
    s: Sample,
    domain: Domain,
    v: Field,
):
    x = domain(s)
    return v(s) * wp.max(0.0, 1.0 - wp.length(x))


@integrand
def diffusion_form(s: Sample, u: Field, v: Field, nu: float):
    return nu * wp.dot(
        grad(u, s),
        grad(v, s),
    )

Integrands are normal Warp kernels, meaning that they may contain arbitrary Warp functions. However, they accept a few special parameters:

  • Sample contains information about the current integration sample point, such as the element index and coordinates in element.

  • Field designates an abstract field, which will be replaced at call time by the actual field type such as a discrete field, field.TestField or field.TrialField defined over some FunctionSpace, an ImplicitField wrapping an arbitrary function, or any other of the available Fields. A field u can then be evaluated at a given sample s using the usual call operator as u(s). Several other operators are available, such as the gradient grad(); see the Operators section.

  • Domain designates an abstract integration domain. Evaluating a domain at a sample s as domain(s) yields the corresponding world position, and several operators are also provided domains, for example evaluating the normal at a given sample:

    @integrand
    def boundary_form(
        s: Sample,
        domain: Domain,
        u: Field,
    ):
        nor = normal(domain, s)
        return wp.dot(u(s), nor)
    

Integrands cannot be used directly with warp.launch(), but must be called through integrate() or interpolate() instead. The Sample and Domain arguments of the root integrand (integrand parameter passed to integrate() or interpolate() call) will get automatically populated. Field arguments must be passed as a dictionary in the fields parameter of the launcher function, and all other standard Warp types arguments must be passed as a dictionary in the values parameter of the launcher function, for instance:

integrate(diffusion_form, fields={"u": trial, "v": test}, values={"nu": viscosity})

Basic Workflow#

The typical steps for solving a linearized PDE with warp.fem are as follow:

  • Define a Geometry (grid, mesh, etc). At the moment, 2D and 3D regular grids, NanoVDB volumes, and triangle, quadrilateral, tetrahedron and hexahedron unstructured meshes are supported.

  • Define one or more FunctionSpace, by equipping the geometry elements with shape functions. See make_polynomial_space(). At the moment, continuous/discontinuous Lagrange (\(P_{k[d]}, Q_{k[d]}\)) and Serendipity (\(S_k\)) shape functions of order \(k \leq 3\) are supported, as well as linear Nédélec (first kind) and Raviart-Thomas vector-valued shape functions.

  • Define an integration domain, for instance the geometry’s cells (Cells) or boundary sides (BoundarySides).

  • Integrate linear forms to build the system’s right-hand-side. Define a test function over the function space using make_test(), a Quadrature formula (or let the module choose one based on the function space degree), and call integrate() with the linear form integrand. The result is a warp.array containing the integration result for each of the function space degrees of freedom.

  • Integrate bilinear forms to build the system’s left-hand-side. Define a trial function over the function space using make_trial(), then call integrate() with the bilinear form integrand. The result is a warp.sparse.BsrMatrix containing the integration result for each pair of test and trial function space degrees of freedom. Note that the trial and test functions do not have to be defined over the same function space, so that Mixed FEM is supported.

  • Solve the resulting linear system using the solver of your choice, for instance one of the built-in Iterative Linear Solvers.

The following excerpt from the introductory example warp/examples/fem/example_diffusion.py outlines this procedure:

# Grid geometry
geo = Grid2D(n=50, cell_size=2)

# Domain and function spaces
domain = Cells(geometry=geo)
scalar_space = make_polynomial_space(geo, degree=3)

# Right-hand-side (forcing term)
test = make_test(space=scalar_space, domain=domain)
rhs = integrate(linear_form, fields={"v": test})

# Weakly-imposed boundary conditions on Y sides
boundary = BoundarySides(geo)
bd_test = make_test(space=scalar_space, domain=boundary)
bd_trial = make_trial(space=scalar_space, domain=boundary)
bd_matrix = integrate(y_mass_form, fields={"u": bd_trial, "v": bd_test})

# Diffusion form
trial = make_trial(space=scalar_space, domain=domain)
matrix = integrate(diffusion_form, fields={"u": trial, "v": test}, values={"nu": viscosity})

# Assemble linear system (add diffusion and boundary condition matrices)
matrix += bd_matrix * boundary_strength

# Solve linear system using Conjugate Gradient
x = wp.zeros_like(rhs)
bsr_cg(matrix, b=rhs, x=x)

Note

The integrate() function does not check that the passed integrands are actually linear or bilinear forms; it is up to the user to ensure that they are. To solve non-linear PDEs, one can use an iterative procedure and pass the current value of the studied function DiscreteField argument to the integrand, in which arbitrary operations are permitted. However, the result of the form must remain linear in the test and trial fields. This strategy is demonstrated in the example_mixed_elasticity.py example.

Introductory Examples#

warp.fem ships with a list of examples in the warp/examples/fem directory demonstrating how to solve classical model problems.

  • example_diffusion.py: 2D diffusion with homogeneous Neumann and Dirichlet boundary conditions
    • example_diffusion_3d.py: 3D variant of the diffusion problem

  • example_convection_diffusion.py: 2D convection-diffusion using semi-Lagrangian advection
    • example_convection_diffusion_dg.py: 2D convection-diffusion using Discontinuous Galerkin with upwind transport and Symmetric Interior Penalty

  • example_burgers.py: 2D inviscid Burgers using Discontinuous Galerkin with upwind transport and slope limiter

  • example_stokes.py: 2D incompressible Stokes flow using mixed \(P_k/P_{k-1}\) or \(Q_k/P_{(k-1)d}\) elements

  • example_navier_stokes.py: 2D Navier-Stokes flow using mixed \(P_k/P_{k-1}\) elements

  • example_mixed_elasticity.py: 2D nonlinear elasticity using mixed continuous/discontinuous \(S_k/P_{(k-1)d}\) elements

  • example_distortion_energy.py: Parameterization of a 3D surface minimizing a 2D nonlinear distortion energy

  • example_magnetostatics.py: 2D magnetostatics using a curl-curl formulation

Advanced Usages#

High-order (curved) geometries#

It is possible to convert any Geometry (grids and explicit meshes) into a curved, high-order variant by deforming them with an arbitrary-order displacement field using the make_deformed_geometry() method. The process looks as follows:

# Define a base geometry
base_geo = fem.Grid3D(res=resolution)

# Define a displacement field on the base geometry
deformation_space = fem.make_polynomial_space(base_geo, degree=deformation_degree, dtype=wp.vec3)
deformation_field = deformation_space.make_field()

# Populate the field value by interpolating an expression
fem.interpolate(deformation_field_expr, dest=deformation_field)

# Construct the deformed geometry from the displacement field
deform_geo = deformation_field.make_deformed_geometry()

# Define new function spaces on the deformed geometry
scalar_space = fem.make_polynomial_space(deformed_geo, degree=scalar_space_degree)

See example_deformed_geometry.py for a complete example. It is also possible to define the deformation field from an ImplicitField, as done in example_magnetostatics.py.

Particle-based quadrature and position lookups#

The global lookup() operator allows generating a Sample from an arbitrary position; this is illustrated in the example_streamlines.py example for generating 3D streamlines by tracing through a velocity field.

This operator is also leveraged by the PicQuadrature to provide a way to define Particle-In-Cell quadratures from a set or arbitrary particles, making it possible to implement MPM-type methods. The particles are automatically bucketed to the geometry cells when the quadrature is initialized. This is illustrated by the example_stokes_transfer.py and example_apic_fluid.py examples.

Note

The global lookup() operator is not currently supported for Quadmesh2D, Hexmesh and deformed geometries.

Nonconforming fields#

Fields defined on a given Geometry cannot be directly used for integrating over a distinct geometry; however, they may be wrapped in a NonconformingField for this purpose. This is leveraged by the example_nonconforming_contact.py to simulate contacting bodies that are discretized separately.

Note

Currently NonconformingField does not support wrapping a trial field, so it is not yet possible to define bilinear forms over different geometries.

Note

The mapping between the different geometries is position based, so a NonconformingField is not able to accurately capture discontinuous function spaces. Moreover, the integration domain must support the lookup() operator.

Partitioning#

The FEM toolkit makes it possible to perform integration on a subset of the domain elements, possibly re-indexing degrees of freedom so that the linear system contains the local ones only. This is useful for distributed computation (see warp/examples/fem/example_diffusion_mgpu.py), or simply to limit the simulation domain to a subset of active cells (see warp/examples/fem/example_stokes_transfer.py).

A partition of the simulation geometry can be defined using subclasses of GeometryPartition such as LinearGeometryPartition or ExplicitGeometryPartition.

Function spaces can then be partitioned according to the geometry partition using make_space_partition(). The resulting SpacePartition object allows translating between space-wide and partition-wide node indices, and differentiating interior, frontier and exterior nodes.

The Subdomain class can be used to integrate over a subset of elements while keeping the full set of degrees of freedom, i.e, without reindexing; this is illustrated in the example_streamlines.py example to define inflow and outflow boundaries.

Adaptivity#

While unstructured mesh refinement is currently out of scope, warp.fem provides an adaptive version of the sparse grid geometry, AdaptiveNanogrid, with power-of-two voxel scales. Helpers for building such geometries from hierarchy of grids or a refinement oracle are also provided, see adaptive_nanogrid_from_field() and adaptive_nanogrid_from_hierarchy(). An example is provided in warp/examples/fem/example_adaptive_grid.py.

Note

The existence of “T-junctions” at resolution boundaries mean that usual tri-polynomial shape functions will no longer be globally continuous. Discontinuous–Galerkin or similar techniques may be used to take into account the “jump” at multi-resolution faces.

Memory management#

Several warp.fem functions require allocating temporary buffers to perform their computations. If such functions are called many times in a tight loop, those many allocations and de-allocations may degrade performance, though this is a lot less significant when Stream-Ordered Memory Pool Allocators are in use. To overcome this issue, a cache.TemporaryStore object may be created to persist and reuse temporary allocations across calls, either globally using set_default_temporary_store() or at a per-function granularity using the corresponding argument.

Visualization#

Most functions spaces define a FunctionSpace.cells_to_vtk() method that returns a list of VTK-compatible cell types and node indices. This can be used to visualize discrete fields in VTK-aware viewers such as pyvista, for instance:

import numpy as np
import pyvista

import warp as wp
import warp.fem as fem


@fem.integrand
def ackley(s: fem.Sample, domain: fem.Domain):
   x = domain(s)
   return (
      -20.0 * wp.exp(-0.2 * wp.sqrt(0.5 * wp.length_sq(x)))
      - wp.exp(0.5 * (wp.cos(2.0 * wp.pi * x[0]) + wp.cos(2.0 * wp.pi * x[1])))
      + wp.e
      + 20.0
   )


# Define field
geo = fem.Grid2D(res=wp.vec2i(64, 64), bounds_lo=wp.vec2(-4.0, -4.0), bounds_hi=wp.vec2(4.0, 4.0))
space = fem.make_polynomial_space(geo, degree=3)
field = space.make_field()
fem.interpolate(ackley, dest=field)

# Extract cells, nodes and values
cells, types = field.space.vtk_cells()
nodes = field.space.node_positions().numpy()
values = field.dof_values.numpy()
positions = np.hstack((nodes, values[:, np.newaxis]))

# Visualize with pyvista
grid = pyvista.UnstructuredGrid(cells, types, positions)
grid.point_data["scalars"] = values
plotter = pyvista.Plotter()
plotter.add_mesh(grid)
plotter.show()

Operators#

Domain operators#

warp.fem.position(domain: Domain, s: Sample)#

Evaluates the world position of the sample point s

warp.fem.normal(domain: Domain, s: Sample)#

Evaluates the element normal at the sample point s. Non zero if the element is a side or the geometry is embedded in a higher-dimensional space (e.g. Trimesh3D)

warp.fem.lookup(domain: Domain, x)#

Looks-up the sample point corresponding to a world position x, projecting to the closest point on the domain.

Parameters:
  • x – world position of the point to look-up in the geometry

  • guess – (optional) Sample initial guess, may help perform the query

Note

Currently this operator is unsupported for Hexmesh, Quadmesh2D, Quadmesh3D and deformed geometries.

warp.fem.measure(domain: Domain, s: Sample)#

Returns the measure (volume, area, or length) determinant of an element at a sample point s

warp.fem.measure_ratio(domain: Domain, s: Sample)#

Returns the maximum ratio between the measure of this element and that of higher-dimensional neighbors.

warp.fem.deformation_gradient(domain: Domain, s: Sample)#

Evaluates the gradient of the domain position with respect to the element reference space at the sample point s

warp.fem.cells(domain: Domain)#

Converts a domain defined on geometry sides to a domain defined of cells.

warp.fem.to_inner_cell(domain: Domain, s: Sample)#

Converts a Sample defined on a side to a sample defined on the side’s inner cell

warp.fem.to_outer_cell(domain: Domain, s: Sample)#

Converts a Sample defined on a side to a sample defined on the side’s outer cell

warp.fem.to_cell_side(domain: Domain, s: Sample, side_index: ElementIndex)#

Converts a Sample defined on a cell to a sample defined on one of its side. If the result does not lie on the side side_index, the resulting coordinates will be set to OUTSIDE.

Field operators#

warp.fem.degree(f: Field)#

Polynomial degree of a field

warp.fem.inner(f: Field, s: Sample)#

Evaluates the field at a sample point s. On oriented sides, uses the inner element

warp.fem.outer(f: Field, s: Sample)#

Evaluates the field at a sample point s. On oriented sides, uses the outer element. On interior points and on domain boundaries, this is equivalent to inner().

warp.fem.grad(f: Field, s: Sample)#

Evaluates the field gradient at a sample point s. On oriented sides, uses the inner element

warp.fem.grad_outer(f: Field, s: Sample)#

Evaluates the field gradient at a sample point s. On oriented sides, uses the outer element. On interior points and on domain boundaries, this is equivalent to grad().

warp.fem.div(f: Field, s: Sample)#

Evaluates the field divergence at a sample point s. On oriented sides, uses the inner element

warp.fem.div_outer(f: Field, s: Sample)#

Evaluates the field divergence at a sample point s. On oriented sides, uses the outer element. On interior points and on domain boundaries, this is equivalent to div().

warp.fem.at_node(f: Field, s: Sample)#

For a Test or Trial field f, returns a copy of the Sample s moved to the coordinates of the node being evaluated

warp.fem.D(f: Field, s: Sample)#

Symmetric part of the (inner) gradient of the field at s

warp.fem.curl(f: Field, s: Sample)#

Skew part of the (inner) gradient of the field at s, as a vector such that wp.cross(curl(u), v) = skew(grad(u)) v

warp.fem.jump(f: Field, s: Sample)#

Jump between inner and outer element values on an interior side. Zero for interior points or domain boundaries

warp.fem.average(f: Field, s: Sample)#

Average between inner and outer element values

warp.fem.grad_jump(f: Field, s: Sample)#

Jump between inner and outer element gradients on an interior side. Zero for interior points or domain boundaries

warp.fem.grad_average(f: Field, s: Sample)#

Average between inner and outer element gradients

Integration#

warp.fem.integrate(
integrand,
domain=None,
quadrature=None,
nodal=False,
fields=None,
values=None,
accumulate_dtype=wp.float64,
output_dtype=None,
output=None,
device=None,
temporary_store=None,
kernel_options=None,
assembly=None,
add=False,
)[source]#

Integrates a constant, linear or bilinear form, and returns a scalar, array, or sparse matrix, respectively.

Parameters:
  • integrand (Integrand) – Form to be integrated, must have integrand() decorator

  • domain (GeometryDomain | None) – Integration domain. If None, deduced from fields

  • quadrature (Quadrature | None) – Quadrature formula. If None, deduced from domain and fields degree.

  • nodal (bool) – Deprecated. Use the equivalent assembly=”nodal” instead.

  • fields (Dict[str, FieldLike] | None) – Discrete, test, and trial fields to be passed to the integrand. Keys in the dictionary must match integrand parameter names.

  • values (Dict[str, Any] | None) – Additional variable values to be passed to the integrand, can be of any type accepted by warp kernel launches. Keys in the dictionary must match integrand parameter names.

  • temporary_store (TemporaryStore | None) – shared pool from which to allocate temporary arrays

  • accumulate_dtype (type) – Scalar type to be used for accumulating integration samples

  • output (array | BsrMatrix | None) – Sparse matrix or warp array into which to store the result of the integration

  • output_dtype (type | None) – Scalar type for returned results in output is not provided. If None, defaults to accumulate_dtype

  • device – Device on which to perform the integration

  • kernel_options (Dict[str, Any] | None) – Overloaded options to be passed to the kernel builder (e.g, {"enable_backward": True})

  • assembly (str | None) – Specifies the strategy for assembling the integrated vector or matrix: - “nodal”: For linear or bilinear forms, use the test function nodes as the quadrature points. Assumes Lagrange interpolation functions are used, and no differential or DG operator is evaluated on the test or trial functions. - “generic”: Single-pass integration and shape-function evaluation. Makes no assumption about the integrand’s content, but may lead to many redundant computations. - “dispatch”: For linear or bilinear forms, first evaluate the form at quadrature points then dispatch to nodes in a second pass. More efficient for integrands that are expensive to evaluate. Incompatible with at_node operator on test or trial functions. - None (default): Automatically picks a suitable assembly strategy (either “generic” or “dispatch”)

  • add (bool) – If True and output is provided, add the integration result to output instead of replacing its content

warp.fem.interpolate(
integrand,
dest=None,
quadrature=None,
dim=0,
domain=None,
fields=None,
values=None,
device=None,
kernel_options=None,
)[source]#

Interpolates a function at a finite set of sample points and optionally assigns the result to a discrete field or a raw warp array.

Parameters:
  • integrand (Integrand | FieldLike) – Function to be interpolated: either a function with warp.fem.integrand() decorator or a field

  • dest (DiscreteField | FieldRestriction | array | None) –

    Where to store the interpolation result. Can be either

    • a DiscreteField, or restriction of a discrete field to a domain (from make_restriction()). In this case, interpolation will be performed at each node.

    • a normal warp array, or None. In this case, the interpolation samples will determined by the quadrature or dim arguments, in that order.

  • quadrature (Quadrature | None) – Quadrature formula defining the interpolation samples if dest is not a discrete field or field restriction.

  • dim (int) – Number of interpolation samples if dest is not a discrete field or restriction and quadrature is None. In this case, the Sample passed to the integrand will be invalid, but the sample point index s.qp_index can be used to define custom interpolation logic.

  • domain (Domain | None) – Interpolation domain, only used if dest is not a field restriction and quadrature is None

  • fields (Dict[str, FieldLike] | None) – Discrete fields to be passed to the integrand. Keys in the dictionary must match integrand parameters names.

  • values (Dict[str, Any] | None) – Additional variable values to be passed to the integrand, can be of any type accepted by warp kernel launches. Keys in the dictionary must match integrand parameter names.

  • device – Device on which to perform the interpolation

  • kernel_options (Dict[str, Any] | None) – Overloaded options to be passed to the kernel builder (e.g, {"enable_backward": True})

warp.fem.integrand(func=None, kernel_options=None)[source]#

Decorator for functions to be integrated (or interpolated) using warp.fem

Parameters:
  • func (Callable | None) – Decorated function

  • kernel_options (Dict[str, Any] | None) – Supplemental code-generation options to be passed to the generated kernel.

class warp.fem.Sample#

Per-sample point context for evaluating fields and related operators in integrands.

class warp.fem.Field[source]#

Tag for field-like integrand arguments

call_operator: warp.fem.operator.Operator = <warp.fem.operator.Operator object>#
class warp.fem.Domain[source]#

Tag for domain-like integrand arguments

call_operator: warp.fem.operator.Operator = <warp.fem.operator.Operator object>#

Geometry#

class warp.fem.Grid2D(res, bounds_lo=None, bounds_hi=None)[source]#

Bases: Geometry

Two-dimensional regular grid geometry

Parameters:
  • res (vec2i)

  • bounds_lo (vec2f | None)

  • bounds_hi (vec2f | None)

__init__(res, bounds_lo=None, bounds_hi=None)[source]#

Constructs a dense 2D grid

Parameters:
  • res (vec2i) – Resolution of the grid along each dimension

  • bounds_lo (vec2f | None) – Position of the lower bound of the axis-aligned grid

  • bounds_hi (vec2f | None) – Position of the upper bound of the axis-aligned grid

class warp.fem.Trimesh2D(
tri_vertex_indices,
positions,
build_bvh=False,
temporary_store=None,
)[source]#

Bases: Trimesh

2D Triangular mesh geometry

Parameters:
__init__(
tri_vertex_indices,
positions,
build_bvh=False,
temporary_store=None,
)[source]#

Constructs a D-dimensional triangular mesh.

Parameters:
  • tri_vertex_indices (array) – warp array of shape (num_tris, 3) containing vertex indices for each tri

  • positions (array) – warp array of shape (num_vertices, D) containing the position of each vertex

  • temporary_store (TemporaryStore | None) – shared pool from which to allocate temporary arrays

  • build_bvh (bool) – Whether to also build the triangle BVH, which is necessary for the global fem.lookup operator to function without initial guess

class warp.fem.Trimesh3D(
tri_vertex_indices,
positions,
build_bvh=False,
temporary_store=None,
)[source]#

Bases: Trimesh

3D Triangular mesh geometry

Parameters:
__init__(
tri_vertex_indices,
positions,
build_bvh=False,
temporary_store=None,
)[source]#

Constructs a D-dimensional triangular mesh.

Parameters:
  • tri_vertex_indices (array) – warp array of shape (num_tris, 3) containing vertex indices for each tri

  • positions (array) – warp array of shape (num_vertices, D) containing the position of each vertex

  • temporary_store (TemporaryStore | None) – shared pool from which to allocate temporary arrays

  • build_bvh (bool) – Whether to also build the triangle BVH, which is necessary for the global fem.lookup operator to function without initial guess

class warp.fem.Quadmesh2D(quad_vertex_indices, positions, temporary_store=None)[source]#

Bases: Quadmesh

Two-dimensional quadrilateral mesh

Parameters:
__init__(
quad_vertex_indices,
positions,
temporary_store=None,
)[source]#

Constructs a D-dimensional quadrilateral mesh.

Parameters:
  • quad_vertex_indices (array) – warp array of shape (num_tris, 4) containing vertex indices for each quad, in counter-clockwise order

  • positions (array) – warp array of shape (num_vertices, D) containing the position of each vertex

  • temporary_store (TemporaryStore | None) – shared pool from which to allocate temporary arrays

class warp.fem.Quadmesh3D(quad_vertex_indices, positions, temporary_store=None)[source]#

Bases: Quadmesh

Three-dimensional quadrilateral mesh

Parameters:
__init__(
quad_vertex_indices,
positions,
temporary_store=None,
)[source]#

Constructs a D-dimensional quadrilateral mesh.

Parameters:
  • quad_vertex_indices (array) – warp array of shape (num_tris, 4) containing vertex indices for each quad, in counter-clockwise order

  • positions (array) – warp array of shape (num_vertices, D) containing the position of each vertex

  • temporary_store (TemporaryStore | None) – shared pool from which to allocate temporary arrays

class warp.fem.Grid3D(res, bounds_lo=None, bounds_hi=None)[source]#

Bases: Geometry

Three-dimensional regular grid geometry

Parameters:
  • res (vec3i)

  • bounds_lo (vec3f | None)

  • bounds_hi (vec3f | None)

__init__(res, bounds_lo=None, bounds_hi=None)[source]#

Constructs a dense 3D grid

Parameters:
  • res (vec3i) – Resolution of the grid along each dimension

  • bounds_lo (vec3f | None) – Position of the lower bound of the axis-aligned grid

  • bounds_hi (vec3f | None) – Position of the upper bound of the axis-aligned grid

class warp.fem.Tetmesh(
tet_vertex_indices,
positions,
build_bvh=False,
temporary_store=None,
)[source]#

Bases: Geometry

Tetrahedral mesh geometry

Parameters:
__init__(
tet_vertex_indices,
positions,
build_bvh=False,
temporary_store=None,
)[source]#

Constructs a tetrahedral mesh.

Parameters:
  • tet_vertex_indices (array) – warp array of shape (num_tets, 4) containing vertex indices for each tet

  • positions (array) – warp array of shape (num_vertices, 3) containing 3d position for each vertex

  • temporary_store (TemporaryStore | None) – shared pool from which to allocate temporary arrays

  • build_bvh (bool) – Whether to also build the tet BVH, which is necessary for the global fem.lookup operator to function without initial guess

class warp.fem.Hexmesh(hex_vertex_indices, positions, temporary_store=None)[source]#

Bases: Geometry

Hexahedral mesh geometry

Parameters:
__init__(hex_vertex_indices, positions, temporary_store=None)[source]#

Constructs a tetrahedral mesh.

Parameters:
  • hex_vertex_indices (array) – warp array of shape (num_hexes, 8) containing vertex indices for each hex following standard ordering (bottom face vertices in counter-clockwise order, then similarly for upper face)

  • positions (array) – warp array of shape (num_vertices, 3) containing 3d position for each vertex

  • temporary_store (TemporaryStore | None) – shared pool from which to allocate temporary arrays

class warp.fem.Nanogrid(grid, temporary_store=None)[source]#

Bases: Geometry

Sparse grid geometry

Parameters:
__init__(grid, temporary_store=None)[source]#

Constructs a sparse grid geometry from an in-memory NanoVDB volume.

Parameters:
  • grid (Volume) – The NanoVDB volume. Any type is accepted, but for indexing efficiency an index grid is recommended. If grid is an ‘on’ index grid, cells will be created for active voxels only, otherwise cells will be created for all leaf voxels.

  • temporary_store (TemporaryStore | None) – shared pool from which to allocate temporary arrays

class warp.fem.AdaptiveNanogrid(cell_grid, cell_level, level_count, temporary_store)[source]#

Bases: Geometry

Adaptive sparse grid

Parameters:
__init__(
cell_grid,
cell_level,
level_count,
temporary_store,
)[source]#

Constructs an adaptive sparse grid geometry from an in-memory NanoVDB volume and a list of levels.

It is not recommended to use this constructor directly; see the helper functions warp.fem.adaptive_nanogrid_from_field() and warp.fem.adaptive_nanogrid_from_hierarchy()

Parameters:
  • cell_grid (Volume) – A warp volume (ideally backed by an index grid) whose voxels coordinates correspond to the lowest fine-resolution voxel of each cell. The cell’s extent is then given by the cell_level array. For instance, a voxel at coordinates ijk and level 0 corresponds to a fine cell at the same coordinates, a voxel at coordinates 2*ijk and level 1 corresponds to a cell spanning 2^3 voxels from 2*ijk to 2*ijk + (1,1,1), etc.

  • cell_level (array) – Refinement level for each voxel of the volume. Level 0 is the finest, level level_count-1 is the coarsest.

  • level_count (int) – Number of levels in the grid

  • temporary_store (TemporaryStore)

class warp.fem.LinearGeometryPartition(
geometry,
partition_rank,
partition_count,
device=None,
temporary_store=None,
)[source]#
Parameters:
__init__(
geometry,
partition_rank,
partition_count,
device=None,
temporary_store=None,
)[source]#

Creates a geometry partition by uniformly partionning cell indices

Parameters:
  • geometry (Geometry) – the geometry to partition

  • partition_rank (int) – the index of the partition being created

  • partition_count (int) – the number of partitions that will be created over the geometry

  • device – Warp device on which to perform and store computations

  • temporary_store (TemporaryStore | None)

class warp.fem.ExplicitGeometryPartition(geometry, cell_mask, temporary_store=None)[source]#
Parameters:
__init__(
geometry,
cell_mask,
temporary_store=None,
)[source]#

Creates a geometry partition by uniformly partionning cell indices

Parameters:
  • geometry (Geometry) – the geometry to partition

  • cell_mask (wp.array(dtype=int)) – warp array of length geometry.cell_count() indicating which cells are selected. Array values must be either 1 (selected) or 0 (not selected).

  • temporary_store (TemporaryStore)

class warp.fem.Cells(geometry)[source]#

Bases: GeometryDomain

A Domain containing all cells of the geometry or geometry partition

Parameters:

geometry (Geometry | GeometryPartition)

__init__(geometry)[source]#
Parameters:

geometry (Geometry | GeometryPartition)

class warp.fem.Sides(geometry)[source]#

Bases: GeometryDomain

A Domain containing all (interior and boundary) sides of the geometry or geometry partition

Parameters:

geometry (Geometry | GeometryPartition)

__init__(geometry)[source]#
Parameters:

geometry (Geometry | GeometryPartition)

class warp.fem.BoundarySides(geometry)[source]#

Bases: Sides

A Domain containing boundary sides of the geometry or geometry partition

Parameters:

geometry (Geometry | GeometryPartition)

__init__(geometry)[source]#
Parameters:

geometry (Geometry | GeometryPartition)

class warp.fem.FrontierSides(geometry)[source]#

Bases: Sides

A Domain containing frontier sides of the geometry partition (sides shared with at least another partition)

Parameters:

geometry (Geometry | GeometryPartition)

__init__(geometry)[source]#
Parameters:

geometry (Geometry | GeometryPartition)

class warp.fem.Subdomain(
domain,
element_mask=None,
element_indices=None,
temporary_store=None,
)[source]#

Bases: GeometryDomain

Subdomain – restriction of domain to a subset of its elements

Parameters:
__init__(
domain,
element_mask=None,
element_indices=None,
temporary_store=None,
)[source]#

Create a subdomain from a subset of elements.

Exactly one of element_mask and element_indices should be provided.

Parameters:
  • domain (GeometryDomain) – the containing domain

  • element_mask (array | None) – Array of length domain.element_count() indicating which elements should be included. Array values must be either 1 (selected) or 0 (not selected).

  • element_indices (array | None) – Explicit array of element indices to include

  • temporary_store (TemporaryStore | None)

class warp.fem.Polynomial(value)[source]#

Polynomial family defining interpolation nodes over an interval

GAUSS_LEGENDRE = 'GL'#

Gauss–Legendre 1D polynomial family (does not include endpoints)

LOBATTO_GAUSS_LEGENDRE = 'LGL'#

Lobatto–Gauss–Legendre 1D polynomial family (includes endpoints)

EQUISPACED_CLOSED = 'closed'#

Closed 1D polynomial family with uniformly distributed nodes (includes endpoints)

EQUISPACED_OPEN = 'open'#

Open 1D polynomial family with uniformly distributed nodes (does not include endpoints)

class warp.fem.RegularQuadrature(domain, order, family=None)[source]#

Bases: Quadrature

Regular quadrature formula, using a constant set of quadrature points per element

Parameters:
__init__(domain, order, family=None)[source]#
Parameters:
class warp.fem.NodalQuadrature(domain, space)[source]#

Bases: Quadrature

Quadrature using space node points as quadrature points

Note that in contrast to the nodal=True flag for integrate(), using this quadrature does not imply any assumption about orthogonality of shape functions, and is thus safe to use for arbitrary integrands.

Parameters:
__init__(domain, space)[source]#
Parameters:
class warp.fem.ExplicitQuadrature(domain, points, weights)[source]#

Bases: Quadrature

Quadrature using explicit per-cell points and weights.

The number of quadrature points per cell is assumed to be constant and deduced from the shape of the points and weights arrays. Quadrature points may be provided for either the whole geometry or just the domain’s elements.

Parameters:
  • domain (GeometryDomain) – Domain of definition of the quadrature formula

  • points (wp.array2d(dtype=Coords)) – 2d array of shape (domain.element_count(), points_per_cell) or (domain.geometry_element_count(), points_per_cell) containing the coordinates of each quadrature point.

  • weights (wp.array2d(dtype=float)) – 2d array of shape (domain.element_count(), points_per_cell) or (domain.geometry_element_count(), points_per_cell) containing the weight for each quadrature point.

See also: PicQuadrature

__init__(domain, points, weights)[source]#
Parameters:
  • domain (GeometryDomain)

  • points (wp.array2d(dtype=Coords))

  • weights (wp.array2d(dtype=float))

class warp.fem.PicQuadrature(
domain,
positions,
measures=None,
requires_grad=False,
temporary_store=None,
)[source]#

Bases: Quadrature

Particle-based quadrature formula, using a global set of points unevenly spread out over geometry elements.

Useful for Particle-In-Cell and derived methods.

Parameters:
  • domain (GeometryDomain) – Underlying domain for the quadrature

  • positions (wp.array(dtype=wp.vecXd) | Tuple[wp.array(dtype=ElementIndex), wp.array(dtype=Coords)]) – Either an array containing the world positions of all particles, or a tuple of arrays containing the cell indices and coordinates for each particle. Note that the former requires the underlying geometry to define a global Geometry.cell_lookup() method; currently this is only available for Grid2D and Grid3D.

  • measures (wp.array(dtype=float) | None) – Array containing the measure (area/volume) of each particle, used to defined the integration weights. If None, defaults to the cell measure divided by the number of particles in the cell.

  • requires_grad (bool) – Whether gradients should be allocated for the computed quantities

  • temporary_store (TemporaryStore) – shared pool from which to allocate temporary arrays

__init__(
domain,
positions,
measures=None,
requires_grad=False,
temporary_store=None,
)[source]#
Parameters:
  • domain (GeometryDomain)

  • positions (wp.array(dtype=wp.vecXd) | Tuple[wp.array(dtype=ElementIndex), wp.array(dtype=Coords)])

  • measures (wp.array(dtype=float) | None)

  • requires_grad (bool)

  • temporary_store (TemporaryStore)

Function Spaces#

warp.fem.make_polynomial_space(
geo,
dtype=float,
dof_mapper=None,
degree=1,
element_basis=None,
discontinuous=False,
family=None,
)[source]#

Equips a geometry with a collocated, polynomial function space. Equivalent to successive calls to make_polynomial_basis_space() then make_collocated_function_space, make_covariant_function_space or make_contravariant_function_space.

Parameters:
  • geo (Geometry) – the Geometry on which to build the space

  • dtype (type) – value type the function space. If dof_mapper is provided, the value type from the DofMapper will be used instead.

  • dof_mapper (DofMapper | None) – mapping from node degrees of freedom to function values, defaults to Identity. Useful for reduced coordinates, e.g. SymmetricTensorMapper maps 2x2 (resp 3x3) symmetric tensors to 3 (resp 6) degrees of freedom.

  • degree (int) – polynomial degree of the per-element shape functions

  • discontinuous (bool) – if True, use Discontinuous Galerkin shape functions. Discontinuous is implied if degree is 0, i.e, piecewise-constant shape functions.

  • element_basis (ElementBasis | None) – type of basis function for the individual elements

  • family (Polynomial | None) – Polynomial family used to generate the shape function basis. If not provided, a reasonable basis is chosen.

Returns:

the constructed function space

Return type:

CollocatedFunctionSpace

warp.fem.make_polynomial_basis_space(
geo,
degree=1,
element_basis=None,
discontinuous=False,
family=None,
)[source]#

Equips a geometry with a polynomial basis.

Parameters:
  • geo (Geometry) – the Geometry on which to build the space

  • degree (int) – polynomial degree of the per-element shape functions

  • discontinuous (bool) – if True, use Discontinuous Galerkin shape functions. Discontinuous is implied if degree is 0, i.e, piecewise-constant shape functions.

  • element_basis (ElementBasis | None) – type of basis function for the individual elements

  • family (Polynomial | None) – Polynomial family used to generate the shape function basis. If not provided, a reasonable basis is chosen.

Returns:

the constructed basis space

Return type:

BasisSpace

warp.fem.make_collocated_function_space(
basis_space,
dtype=float,
dof_mapper=None,
)[source]#

Constructs a function space from a scalar-valued basis space and a value type, such that all degrees of freedom of the value type are stored at each of the basis nodes.

Parameters:
  • geo – the Geometry on which to build the space

  • dtype (type) – value type the function space. If dof_mapper is provided, the value type from the DofMapper will be used instead.

  • dof_mapper (DofMapper | None) – mapping from node degrees of freedom to function values, defaults to Identity. Useful for reduced coordinates, e.g. SymmetricTensorMapper maps 2x2 (resp 3x3) symmetric tensors to 3 (resp 6) degrees of freedom.

  • basis_space (BasisSpace)

Returns:

the constructed function space

Return type:

CollocatedFunctionSpace

warp.fem.make_covariant_function_space(basis_space)[source]#

Constructs a covariant function space from a vector-valued basis space

Parameters:

basis_space (BasisSpace)

Return type:

CovariantFunctionSpace

warp.fem.make_contravariant_function_space(basis_space)[source]#

Constructs a contravariant function space from a vector-valued basis space

Parameters:

basis_space (BasisSpace)

Return type:

ContravariantFunctionSpace

warp.fem.make_space_partition(
space=None,
geometry_partition=None,
space_topology=None,
with_halo=True,
device=None,
temporary_store=None,
)[source]#

Computes the subset of nodes from a function space topology that touch a geometry partition

Either space_topology or space must be provided (and will be considered in that order).

Parameters:
  • space (FunctionSpace | None) – (deprecated) the function space defining the topology if space_topology is None.

  • geometry_partition (GeometryPartition | None) – The subset of the space geometry. If not provided, use the whole geometry.

  • space_topology (SpaceTopology | None) – the topology of the function space to consider. If None, deduced from space.

  • with_halo (bool) – if True, include the halo nodes (nodes from exterior frontier cells to the partition)

  • device – Warp device on which to perform and store computations

  • temporary_store (TemporaryStore | None)

Returns:

the resulting space partition

Return type:

SpacePartition

warp.fem.make_space_restriction(
space=None,
space_partition=None,
domain=None,
space_topology=None,
device=None,
temporary_store=None,
)[source]#

Restricts a function space partition to a Domain, i.e. a subset of its elements.

One of space_partition, space_topology, or space must be provided (and will be considered in that order).

Parameters:
  • space (FunctionSpace | None) – (deprecated) if neither space_partition nor space_topology are provided, the space defining the topology to restrict

  • space_partition (SpacePartition | None) – the subset of nodes from the space topology to consider

  • domain (GeometryDomain | None) – the domain to restrict the space to, defaults to all cells of the space geometry or partition.

  • space_topology (SpaceTopology | None) – the space topology to be restricted, if space_partition is None.

  • device – device on which to perform and store computations

  • temporary_store (Optional[warp.fem.cache.TemporaryStore]) – shared pool from which to allocate temporary arrays

Return type:

SpaceRestriction

class warp.fem.ElementBasis(value)[source]#

Choice of basis function to equip individual elements

LAGRANGE = 'P'#

Lagrange basis functions \(P_k\) for simplices, tensor products \(Q_k\) for squares and cubes

SERENDIPITY = 'S'#

Serendipity elements \(S_k\), corresponding to Lagrange nodes with interior points removed (for degree <= 3)

NONCONFORMING_POLYNOMIAL = 'dP'#

Simplex Lagrange basis functions \(P_{kd}\) embedded into non conforming reference elements (e.g. squares or cubes). Discontinuous only.

NEDELEC_FIRST_KIND = 'N1'#

Nédélec (first kind) H(curl) shape functions. Should be used with covariant function space.

RAVIART_THOMAS = 'RT'#

Raviart-Thomas H(div) shape functions. Should be used with contravariant function space.

class warp.fem.SymmetricTensorMapper(dtype, mapping=Mapping.VOIGT)[source]#

Bases: DofMapper

Orthonormal isomorphism from R^{n (n+1)} to nxn symmetric tensors, using usual L2 norm for vectors and half Frobenius norm, (tau : tau)/2 for tensors.

Parameters:
  • dtype (type)

  • mapping (Mapping)

__init__(dtype, mapping=Mapping.VOIGT)[source]#
Parameters:
  • dtype (type)

  • mapping (Mapping)

class warp.fem.SkewSymmetricTensorMapper(dtype)[source]#

Bases: DofMapper

Orthonormal isomorphism from R^{n (n-1)} to nxn skew-symmetric tensors, using usual L2 norm for vectors and half Frobenius norm, (tau : tau)/2 for tensors.

Parameters:

dtype (type)

__init__(dtype)[source]#
Parameters:

dtype (type)

class warp.fem.PointBasisSpace(quadrature)[source]#

Bases: BasisSpace

An unstructured BasisSpace that is non-zero at a finite set of points only.

The node locations and nodal quadrature weights are defined by a Quadrature formula.

Parameters:

quadrature (Quadrature)

__init__(quadrature)[source]#
Parameters:

quadrature (Quadrature)

Fields#

warp.fem.make_test(
space,
space_restriction=None,
space_partition=None,
domain=None,
device=None,
)[source]#

Constructs a test field over a function space or its restriction

Parameters:
  • space (FunctionSpace) – the function space

  • space_restriction (SpaceRestriction | None) – restriction of the space topology to a domain

  • space_partition (SpacePartition | None) – if space_restriction is None, the optional subset of node indices to consider

  • domain (GeometryDomain | None) – if space_restriction is None, optional subset of elements to consider

  • device – Warp device on which to perform and store computations

Returns:

the test field

Return type:

TestField

warp.fem.make_trial(
space,
space_restriction=None,
space_partition=None,
domain=None,
)[source]#

Constructs a trial field over a function space or partition

Parameters:
  • space (FunctionSpace) – the function space or function space restriction

  • space_restriction (SpaceRestriction | None) – restriction of the space topology to a domain

  • space_partition (SpacePartition | None) – if space_restriction is None, the optional subset of node indices to consider

  • domain (GeometryDomain | None) – if space_restriction is None, optional subset of elements to consider

  • device – Warp device on which to perform and store computations

Returns:

the trial field

Return type:

TrialField

warp.fem.make_discrete_field(space, space_partition=None)[source]#

Constructs a zero-initialized discrete field over a function space or partition

See also: warp.fem.FunctionSpace.make_field()

Parameters:
Return type:

DiscreteField

class warp.fem.ImplicitField(
domain,
func,
values=None,
grad_func=None,
div_func=None,
degree=0,
)[source]#

Bases: GeometryField

Field defined from an arbitrary function over a domain. Does not support autodiff yet, so if gradient/divergence evaluation is required corresponding functions must be provided.

Parameters:
  • domain (GeometryDomain) – Domain over which the field is defined

  • func (Function) – Warp function evaluating the field at a given position. Must accept at least one argument, with the first argument being the evaluation position (wp.vec2 or wp.vec3).

  • values (Dict[str, Any] | None) – Optional dictionary of additional argument values to be passed to the evaluation function.

  • grad_func (Function | None) – Optional gradient evaluation function; must take same arguments as func

  • div_func (Function | None) – Optional divergence evaluation function; must take same arguments as func

  • degree – Optional hint for automatic determination of quadrature orders when integrating this field

__init__(
domain,
func,
values=None,
grad_func=None,
div_func=None,
degree=0,
)[source]#
Parameters:
  • domain (GeometryDomain)

  • func (Function)

  • values (Dict[str, Any] | None)

  • grad_func (Function | None)

  • div_func (Function | None)

property values[source]#
class warp.fem.UniformField(domain, value)[source]#

Bases: GeometryField

Field defined as a constant value over a domain.

Parameters:
  • domain (GeometryDomain) – Domain over which the field is defined

  • value (Any) – Uniform value over the domain

__init__(domain, value)[source]#
Parameters:
property value[source]#
class warp.fem.NonconformingField(domain, field, background=0.0)[source]#

Bases: GeometryField

Field defined as the map of a DiscreteField over a non-conforming geometry.

Parameters:
  • domain (GeometryDomain) – The new domain over which the nonconforming field will be evaluated

  • field (DiscreteField) – Nonconforming discrete field

  • background (Any) – Uniform value or domain-conforming field determining the value outside of the geometry of definition of field

__init__(domain, field, background=0.0)[source]#
Parameters:
warp.fem.make_restriction(
field,
space_restriction=None,
domain=None,
device=None,
)[source]#

Restricts a discrete field to a subset of elements.

Parameters:
  • field (DiscreteField) – the discrete field to restrict

  • space_restriction (SpaceRestriction | None) – the function space restriction defining the subset of elements to consider

  • domain (GeometryDomain | None) – if space_restriction is not provided, the Domain defining the subset of elements to consider

  • device – Warp device on which to perform and store computations

Returns:

the field restriction

Return type:

FieldRestriction

Boundary Conditions#

warp.fem.normalize_dirichlet_projector(projector_matrix, fixed_value=None)[source]#

Scale projector so that it becomes idempotent, and apply the same scaling to fixed_value if provided

Parameters:
warp.fem.project_linear_system(
system_matrix,
system_rhs,
projector_matrix,
fixed_value=None,
normalize_projector=True,
)[source]#

Projects both the left-hand-side and right-hand-side of a linear system to enforce Dirichlet boundary conditions

If normalize_projector is True, first apply scaling so that the projector_matrix is idempotent

Parameters:

Adaptivity#

warp.fem.adaptive_nanogrid_from_hierarchy(
grids,
grading=None,
temporary_store=None,
)[source]#

Constructs a warp.fem.AdaptiveNanogrid from a non-overlapping grid hierarchy.

Warning: The result is undefined if there are partial overlaps between levels, that is if a cell at level l is only partially covered by cells at levels l-1 or lower.

Parameters:
  • grids (List[Volume]) – List of sparse Volumes, from finest to coarsest

  • grading (str | None) – Supplementary grading condition, may be None, “face” or “vertex”; see enforce_nanogrid_grading()

  • temporary_store (TemporaryStore | None) – Storage for temporary allocations

Return type:

AdaptiveNanogrid

warp.fem.adaptive_nanogrid_from_field(
coarse_grid,
level_count,
refinement_field,
samples_per_voxel=64,
grading=None,
temporary_store=None,
)[source]#

Constructs a warp.fem.AdaptiveNanogrid from a coarse grid and a refinement field.

Parameters:
  • coarse_grid (Volume) – Base grid from which to start refining. No voxels will be added outside of the base grid.

  • level_count (int) – Maximum number of refinement levels

  • refinement_field (GeometryField) – Scalar field used as a refinement oracle. If the returned value is negative, the corresponding voxel will be carved out. Positive values indicate the desired refinement with 0.0 corresponding to the finest level and 1.0 to the coarsest level.

  • samples_per_voxel (int) – How many samples to use for evaluating the refinement field within each voxel

  • grading (str | None) – Supplementary grading condition, may be None, “face” or “vertex”; see enforce_nanogrid_grading()

  • temporary_store (TemporaryStore | None) – Storage for temporary allocations

Return type:

AdaptiveNanogrid

Memory Management#

warp.fem.set_default_temporary_store(temporary_store)[source]#

Globally sets the default TemporaryStore instance to use for temporary allocations in warp.fem functions.

If the default temporary store is set to None, temporary allocations are not persisted unless a TemporaryStore is provided at a per-function granularity.

Parameters:

temporary_store (TemporaryStore | None)

warp.fem.borrow_temporary(
temporary_store,
shape,
dtype,
pinned=False,
requires_grad=False,
device=None,
)[source]#

Borrows and returns a temporary array with specified attributes from a shared pool.

If an array with sufficient capacity and matching desired attributes is already available in the pool, it will be returned. Otherwise, a new allocation will be performed.

Parameters:
  • temporary_store (TemporaryStore | None) – the shared pool to borrow the temporary from. If temporary_store is None, the global default temporary store, if set, will be used.

  • shape (int | Tuple[int]) – desired dimensions for the temporary array

  • dtype (type) – desired data type for the temporary array

  • pinned (bool) – whether a pinned allocation is desired

  • device – device on which the memory should be allocated; if None, the current device will be used.

  • requires_grad (bool)

Return type:

Temporary

warp.fem.borrow_temporary_like(array, temporary_store)[source]#

Borrows and returns a temporary array with the same attributes as another array or temporary.

Parameters:
  • array (array | Temporary) – Warp or temporary array to read the desired attributes from

  • temporary_store (TemporaryStore | None) – the shared pool to borrow the temporary from. If temporary_store is None, the global default temporary store, if set, will be used.

Return type:

Temporary

Interfaces#

Interface classes are not meant to be constructed directly, but can be derived from extend the built-in functionality.

class warp.fem.Geometry[source]#

Interface class for discrete geometries

A geometry is composed of cells and sides. Sides may be boundary or interior (between cells).

cell_count()[source]#

Number of cells in the geometry

side_count()[source]#

Number of sides in the geometry

boundary_side_count()[source]#

Number of boundary sides (sides with a single neighbour cell) in the geometry

__init__()#
class warp.fem.GeometryPartition(geometry)[source]#

Base class for geometry partitions, i.e. subset of cells and sides

Parameters:

geometry (Geometry)

__init__(geometry)[source]#
Parameters:

geometry (Geometry)

cell_count()[source]#

Number of cells that are ‘owned’ by this partition

Return type:

int

side_count()[source]#

Number of sides that are ‘owned’ by this partition

Return type:

int

boundary_side_count()[source]#

Number of geo-boundary sides that are ‘owned’ by this partition

Return type:

int

frontier_side_count()[source]#

Number of sides with neighbors owned by this and another partition

Return type:

int

class warp.fem.GeometryDomain(geometry)[source]#

Interface class for domains, i.e. (partial) views of elements in a Geometry

Parameters:

geometry (Geometry | GeometryPartition)

__init__(geometry)[source]#
Parameters:

geometry (Geometry | GeometryPartition)

property element_kind: ElementKind[source]#

Kind of elements that this domain contains (cells or sides)

property dimension: int[source]#

Dimension of the elements of the domain

element_count()[source]#

Number of elements in the domain

Return type:

int

class warp.fem.Quadrature(domain)[source]#

Interface class for quadrature rules

Parameters:

domain (GeometryDomain)

__init__(domain)[source]#
Parameters:

domain (GeometryDomain)

property domain[source]#

Domain over which this quadrature is defined

total_point_count()[source]#

Total number of quadrature points over the domain

class warp.fem.FunctionSpace(topology)[source]#

Interface class for function spaces, i.e. geometry + interpolation basis

The value of a function f at a position x is generally computed as

f(x) = L(x)[sum_i f_i N_i(x)]

with:
  • f_i the value of the ith node’s degrees-of-freedom (dof)

  • N_i(x) the weight associated to the node at x

  • L(x) local linear transformation from node-space to world-space

Parameters:

topology (SpaceTopology)

dtype: type#

Value type of the interpolation functions

__init__(topology)[source]#
Parameters:

topology (SpaceTopology)

property topology: SpaceTopology[source]#

Underlying geometry

property geometry: Geometry[source]#

Underlying geometry

property dimension: int[source]#

Function space embedding dimension

property degree: int[source]#

Maximum polynomial degree of the underlying basis

trace()[source]#

Trace of the function space over lower-dimensional elements of the geometry

Return type:

FunctionSpace

make_field(space_partition=None)[source]#

Creates a zero-initialized discrete field over the function space holding values for all degrees of freedom of nodes in a space partition

Parameters:

space_partition – If provided, the subset of nodes to consider

See also: make_space_partition()

class warp.fem.SpaceTopology(geometry, max_nodes_per_element)[source]#

Interface class for defining the topology of a function space.

The topology only considers the indices of the nodes in each element, and as such, the connectivity pattern of the function space. It does not specify the actual location of the nodes within the elements, or the valuation function.

Parameters:
__init__(geometry, max_nodes_per_element)[source]#
Parameters:
dimension: int#

Embedding dimension of the function space

property geometry: Geometry[source]#

Underlying geometry

node_count()[source]#

Number of nodes in the interpolation basis

Return type:

int

element_node_indices(out=None)[source]#

Returns a temporary array containing the global index for each node of each element

Parameters:

out (array | None)

Return type:

array

trace()[source]#

Trace of the function space over lower-dimensional elements of the geometry

Return type:

TraceSpaceTopology

class warp.fem.BasisSpace(topology)[source]#

Interface class for defining a shape function space over a geometry.

A basis space makes it easy to define multiple function spaces sharing the same basis (and thus nodes) but with different valuation functions; however, it is not a required component of a function space.

See also: make_polynomial_basis_space(), make_collocated_function_space()

Parameters:

topology (SpaceTopology)

__init__(topology)[source]#
Parameters:

topology (SpaceTopology)

property topology: SpaceTopology[source]#

Underlying topology of the basis space

property geometry: Geometry[source]#

Underlying geometry of the basis space

node_positions(out=None)[source]#

Returns a temporary array containing the world position for each node

Parameters:

out (array | None)

Return type:

array

class warp.fem.space.shape.ShapeFunction[source]#

Interface class for defining scalar-valued shape functions over a single element

__init__()#
class warp.fem.SpacePartition(space_topology, geo_partition)[source]#
Parameters:
__init__(space_topology, geo_partition)[source]#
Parameters:
node_count()[source]#

Returns number of nodes in this partition

owned_node_count()[source]#

Returns number of nodes in this partition, excluding exterior halo

Return type:

int

interior_node_count()[source]#

Returns number of interior nodes in this partition

Return type:

int

space_node_indices()[source]#

Return the global function space indices for nodes in this partition

Return type:

array

class warp.fem.SpaceRestriction(
space_partition,
domain,
device=None,
temporary_store=None,
)[source]#

Restriction of a space partition to a given GeometryDomain

Parameters:
__init__(
space_partition,
domain,
device=None,
temporary_store=None,
)[source]#
Parameters:
node_count()[source]#
class warp.fem.DofMapper[source]#

Base class from mapping node degrees of freedom to function values

__init__()#
class warp.fem.FieldLike[source]#

Base class for integrable fields

__init__()#
class warp.fem.DiscreteField(space, space_partition)[source]#

Bases: SpaceField

Explicitly-valued field defined over a partition of a discrete function space

Parameters:
property dof_values: array[source]#

Array of degrees of freedom values

__init__(space, space_partition)[source]#
Parameters:
class warp.fem.field.FieldRestriction(space_restriction, field)[source]#

Restriction of a discrete field to a given GeometryDomain

Parameters:
__init__(space_restriction, field)[source]#
Parameters:
class warp.fem.field.GeometryField[source]#

Bases: FieldLike

Base class for fields defined over a geometry

trace()[source]#

Trace of this field over lower-dimensional elements

Return type:

FieldLike

make_deformed_geometry(relative=True)[source]#

Returns a deformed version of the underlying geometry, with positions displaced according to this field’s values.

Parameters:

relative – If True, the field is interpreted as a relative displacement over the original geometry. If False, the field values are interpreted as absolute positions.

Return type:

Geometry

__init__()#
class warp.fem.field.SpaceField(space, space_partition)[source]#

Bases: GeometryField

Base class for fields defined over a function space

Parameters:
__init__(space, space_partition)[source]#
Parameters:
class warp.fem.field.TestField(space_restriction, space)[source]#

Bases: AdjointField

Field defined over a space restriction that can be used as a test function.

In order to reuse computations, it is possible to define the test field using a SpaceRestriction defined for a different value type than the test function value type, as long as the node topology is similar.

Parameters:
__init__(space_restriction, space)[source]#
Parameters:
class warp.fem.field.TrialField(space, space_partition, domain)[source]#

Bases: AdjointField

Field defined over a domain that can be used as a trial function

Parameters:
__init__(space, space_partition, domain)[source]#
Parameters:
class warp.fem.TemporaryStore[source]#

Shared pool of temporary arrays that will be persisted and reused across invocations of warp.fem functions.

A TemporaryStore instance may either be passed explicitly to warp.fem functions that accept such an argument, for instance integrate.integrate(), or can be set globally as the default store using set_default_temporary_store().

By default, there is no default temporary store, so that temporary allocations are not persisted.

__init__()[source]#
clear()[source]#
class warp.fem.cache.Temporary(*args, **kwargs)[source]#

Handle over a temporary array from a TemporaryStore.

The array will be automatically returned to the temporary pool for reuse upon destruction of this object, unless the temporary is explicitly detached from the pool using detach(). The temporary may also be explicitly returned to the pool before destruction using release().

__init__(array, pool=None, shape=None, dtype=None)[source]#
Parameters:
  • array (array)

  • pool (Pool | None)

detach()[source]#

Detaches the temporary so it is never returned to the pool

Return type:

array

release()[source]#

Returns the temporary array to the pool

property array: array[source]#

View of the array with desired shape and data type.