Spaces:
Sleeping
Sleeping
| import inspect | |
| from typing import Callable, Any | |
| import warp as wp | |
| from warp.fem.types import Domain, Field, Sample | |
| from warp.fem import utils | |
| class Integrand: | |
| """An integrand is a device function containing arbitrary expressions over Field and Domain variables. | |
| It will get transformed to a proper warp.Function by resolving concrete Field types at call time. | |
| """ | |
| def __init__(self, func: Callable): | |
| self.func = func | |
| self.name = wp.codegen.make_full_qualified_name(self.func) | |
| self.module = wp.get_module(self.func.__module__) | |
| self.argspec = inspect.getfullargspec(self.func) | |
| class Operator: | |
| """ | |
| Operators provide syntaxic sugar over Field and Domain evaluation functions and arguments | |
| """ | |
| def __init__(self, func: Callable, resolver: Callable): | |
| self.func = func | |
| self.resolver = resolver | |
| def integrand(func: Callable): | |
| """Decorator for functions to be integrated (or interpolated) using warp.fem""" | |
| itg = Integrand(func) | |
| itg.__doc__ = func.__doc__ | |
| return itg | |
| def operator(resolver: Callable): | |
| """Decorator for functions operating on Field-like or Domain-like data inside warp.fem integrands""" | |
| def wrap_operator(func: Callable): | |
| op = Operator(func, resolver) | |
| op.__doc__ = func.__doc__ | |
| return op | |
| return wrap_operator | |
| # Domain operators | |
| def position(domain: Domain, s: Sample): | |
| """Evaluates the world position of the sample point `s`""" | |
| pass | |
| def normal(domain: Domain, s: Sample): | |
| """Evaluates the element normal at the sample point `s`. Null for interior points.""" | |
| pass | |
| def 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`""" | |
| pass | |
| def lookup(domain: Domain, x: Any) -> Sample: | |
| """Looks-up the sample point corresponding to a world position `x`, projecting to the closest point on the domain. | |
| Arg: | |
| x: world position of the point to look-up in the geometry | |
| guess: (optional) :class:`Sample` initial guess, may help perform the query | |
| Notes: | |
| Currently this operator is only fully supported for :class:`Grid2D` and :class:`Grid3D` geometries. | |
| For :class:`TriangleMesh2D` and :class:`Tetmesh` geometries, the operator requires providing `guess`. | |
| """ | |
| pass | |
| def measure(domain: Domain, s: Sample) -> float: | |
| """Returns the measure (volume, area, or length) determinant of an element at a sample point `s`""" | |
| pass | |
| def measure_ratio(domain: Domain, s: Sample) -> float: | |
| """Returns the maximum ratio between the measure of this element and that of higher-dimensional neighbours.""" | |
| pass | |
| # Field operators | |
| # On a side, inner and outer are such that normal goes from inner to outer | |
| def inner(f: Field, s: Sample): | |
| """Evaluates the field at a sample point `s`. On oriented sides, uses the inner element""" | |
| pass | |
| def grad(f: Field, s: Sample): | |
| """Evaluates the field gradient at a sample point `s`. On oriented sides, uses the inner element""" | |
| pass | |
| def div(f: Field, s: Sample): | |
| """Evaluates the field divergence at a sample point `s`. On oriented sides, uses the inner element""" | |
| pass | |
| def 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 :func:`inner`.""" | |
| pass | |
| def 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 :func:`grad`.""" | |
| pass | |
| def 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 :func:`div`.""" | |
| pass | |
| def degree(f: Field): | |
| """Polynomial degree of a field""" | |
| pass | |
| def at_node(f: Field, s: Sample): | |
| """For a Test or Trial field, returns a copy of the Sample `s` moved to the coordinates of the node being evaluated""" | |
| pass | |
| # Common derived operators, for convenience | |
| def D(f: Field, s: Sample): | |
| """Symmetric part of the (inner) gradient of the field at `s`""" | |
| return utils.symmetric_part(grad(f, s)) | |
| def 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``""" | |
| return utils.skew_part(grad(f, s)) | |
| def jump(f: Field, s: Sample): | |
| """Jump between inner and outer element values on an interior side. Zero for interior points or domain boundaries""" | |
| return inner(f, s) - outer(f, s) | |
| def average(f: Field, s: Sample): | |
| """Average between inner and outer element values""" | |
| return 0.5 * (inner(f, s) + outer(f, s)) | |
| def grad_jump(f: Field, s: Sample): | |
| """Jump between inner and outer element gradients on an interior side. Zero for interior points or domain boundaries""" | |
| return grad(f, s) - grad_outer(f, s) | |
| def grad_average(f: Field, s: Sample): | |
| """Average between inner and outer element gradients""" | |
| return 0.5 * (grad(f, s) + grad_outer(f, s)) | |
| # Set default call operators for argument types, so that field(s) = inner(field, s) and domain(s) = position(domain, s) | |
| Field.call_operator = inner | |
| Domain.call_operator = position | |