qbhf2's picture
added NvidiaWarp and GarmentCode repos
66c9c8a
from typing import Optional
from enum import Enum
import warp.fem.domain as _domain
import warp.fem.geometry as _geometry
import warp.fem.polynomial as _polynomial
from .function_space import FunctionSpace
from .topology import SpaceTopology
from .basis_space import BasisSpace, PointBasisSpace
from .collocated_function_space import CollocatedFunctionSpace
from .grid_2d_function_space import (
GridPiecewiseConstantBasis,
GridBipolynomialBasisSpace,
GridDGBipolynomialBasisSpace,
GridSerendipityBasisSpace,
GridDGSerendipityBasisSpace,
GridDGPolynomialBasisSpace,
)
from .grid_3d_function_space import (
GridTripolynomialBasisSpace,
GridDGTripolynomialBasisSpace,
Grid3DPiecewiseConstantBasis,
Grid3DSerendipityBasisSpace,
Grid3DDGSerendipityBasisSpace,
Grid3DDGPolynomialBasisSpace,
)
from .trimesh_2d_function_space import (
Trimesh2DPiecewiseConstantBasis,
Trimesh2DPolynomialBasisSpace,
Trimesh2DDGPolynomialBasisSpace,
Trimesh2DNonConformingPolynomialBasisSpace,
)
from .tetmesh_function_space import (
TetmeshPiecewiseConstantBasis,
TetmeshPolynomialBasisSpace,
TetmeshDGPolynomialBasisSpace,
TetmeshNonConformingPolynomialBasisSpace,
)
from .quadmesh_2d_function_space import (
Quadmesh2DPiecewiseConstantBasis,
Quadmesh2DBipolynomialBasisSpace,
Quadmesh2DDGBipolynomialBasisSpace,
Quadmesh2DSerendipityBasisSpace,
Quadmesh2DDGSerendipityBasisSpace,
Quadmesh2DPolynomialBasisSpace,
)
from .hexmesh_function_space import (
HexmeshPiecewiseConstantBasis,
HexmeshTripolynomialBasisSpace,
HexmeshDGTripolynomialBasisSpace,
HexmeshSerendipityBasisSpace,
HexmeshDGSerendipityBasisSpace,
HexmeshPolynomialBasisSpace,
)
from .partition import SpacePartition, make_space_partition
from .restriction import SpaceRestriction
from .dof_mapper import DofMapper, IdentityMapper, SymmetricTensorMapper, SkewSymmetricTensorMapper
def make_space_restriction(
space: Optional[FunctionSpace] = None,
space_partition: Optional[SpacePartition] = None,
domain: Optional[_domain.GeometryDomain] = None,
space_topology: Optional[SpaceTopology] = None,
device=None,
temporary_store: "Optional[warp.fem.cache.TemporaryStore]" = None,
) -> SpaceRestriction:
"""
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).
Args:
space: (deprecated) if neither `space_partition` nor `space_topology` are provided, the space defining the topology to restrict
space_partition: the subset of nodes from the space topology to consider
domain: the domain to restrict the space to, defaults to all cells of the space geometry or partition.
space_topology: the space topology to be restricted, if `space_partition` is ``None``.
device: device on which to perform and store computations
temporary_store: shared pool from which to allocate temporary arrays
"""
if space_partition is None:
if space_topology is None:
assert space is not None
space_topology = space.topology
if domain is None:
domain = _domain.Cells(geometry=space_topology.geometry)
space_partition = make_space_partition(
space_topology=space_topology, geometry_partition=domain.geometry_partition
)
elif domain is None:
domain = _domain.Cells(geometry=space_partition.geo_partition)
return SpaceRestriction(
space_partition=space_partition, domain=domain, device=device, temporary_store=temporary_store
)
class ElementBasis(Enum):
"""Choice of basis function to equip individual elements"""
LAGRANGE = 0
"""Lagrange basis functions :math:`P_k` for simplices, tensor products :math:`Q_k` for squares and cubes"""
SERENDIPITY = 1
"""Serendipity elements :math:`S_k`, corresponding to Lagrange nodes with interior points removed (for degree <= 3)"""
NONCONFORMING_POLYNOMIAL = 2
"""Simplex Lagrange basis functions :math:`P_{kd}` embedded into non conforming reference elements (e.g. squares or cubes). Discontinuous only."""
def make_polynomial_basis_space(
geo: _geometry.Geometry,
degree: int = 1,
element_basis: Optional[ElementBasis] = None,
discontinuous: bool = False,
family: Optional[_polynomial.Polynomial] = None,
) -> BasisSpace:
"""
Equips a geometry with a polynomial basis.
Args:
geo: the Geometry on which to build the space
degree: polynomial degree of the per-element shape functions
discontinuous: if True, use Discontinuous Galerkin shape functions. Discontinuous is implied if degree is 0, i.e, piecewise-constant shape functions.
element_basis: type of basis function for the individual elements
family: Polynomial family used to generate the shape function basis. If not provided, a reasonable basis is chosen.
Returns:
the constructed basis space
"""
base_geo = geo.base if isinstance(geo, _geometry.DeformedGeometry) else geo
if element_basis is None:
element_basis = ElementBasis.LAGRANGE
if isinstance(base_geo, _geometry.Grid2D):
if degree == 0:
return GridPiecewiseConstantBasis(geo)
if element_basis == ElementBasis.SERENDIPITY and degree > 1:
if discontinuous:
return GridDGSerendipityBasisSpace(geo, degree=degree, family=family)
else:
return GridSerendipityBasisSpace(geo, degree=degree, family=family)
if element_basis == ElementBasis.NONCONFORMING_POLYNOMIAL:
return GridDGPolynomialBasisSpace(geo, degree=degree)
if discontinuous:
return GridDGBipolynomialBasisSpace(geo, degree=degree, family=family)
else:
return GridBipolynomialBasisSpace(geo, degree=degree, family=family)
if isinstance(base_geo, _geometry.Grid3D):
if degree == 0:
return Grid3DPiecewiseConstantBasis(geo)
if element_basis == ElementBasis.SERENDIPITY and degree > 1:
if discontinuous:
return Grid3DDGSerendipityBasisSpace(geo, degree=degree, family=family)
else:
return Grid3DSerendipityBasisSpace(geo, degree=degree, family=family)
if element_basis == ElementBasis.NONCONFORMING_POLYNOMIAL:
return Grid3DDGPolynomialBasisSpace(geo, degree=degree)
if discontinuous:
return GridDGTripolynomialBasisSpace(geo, degree=degree, family=family)
else:
return GridTripolynomialBasisSpace(geo, degree=degree, family=family)
if isinstance(base_geo, _geometry.Trimesh2D):
if degree == 0:
return Trimesh2DPiecewiseConstantBasis(geo)
if element_basis == ElementBasis.SERENDIPITY and degree > 2:
raise NotImplementedError("Serendipity variant not implemented yet")
if element_basis == ElementBasis.NONCONFORMING_POLYNOMIAL:
return Trimesh2DNonConformingPolynomialBasisSpace(geo, degree=degree)
if discontinuous:
return Trimesh2DDGPolynomialBasisSpace(geo, degree=degree)
else:
return Trimesh2DPolynomialBasisSpace(geo, degree=degree)
if isinstance(base_geo, _geometry.Tetmesh):
if degree == 0:
return TetmeshPiecewiseConstantBasis(geo)
if element_basis == ElementBasis.SERENDIPITY and degree > 2:
raise NotImplementedError("Serendipity variant not implemented yet")
if element_basis == ElementBasis.NONCONFORMING_POLYNOMIAL:
return TetmeshNonConformingPolynomialBasisSpace(geo, degree=degree)
if discontinuous:
return TetmeshDGPolynomialBasisSpace(geo, degree=degree)
else:
return TetmeshPolynomialBasisSpace(geo, degree=degree)
if isinstance(base_geo, _geometry.Quadmesh2D):
if degree == 0:
return Quadmesh2DPiecewiseConstantBasis(geo)
if element_basis == ElementBasis.SERENDIPITY and degree > 1:
if discontinuous:
return Quadmesh2DDGSerendipityBasisSpace(geo, degree=degree, family=family)
else:
return Quadmesh2DSerendipityBasisSpace(geo, degree=degree, family=family)
if element_basis == ElementBasis.NONCONFORMING_POLYNOMIAL:
return Quadmesh2DPolynomialBasisSpace(geo, degree=degree)
if discontinuous:
return Quadmesh2DDGBipolynomialBasisSpace(geo, degree=degree, family=family)
else:
return Quadmesh2DBipolynomialBasisSpace(geo, degree=degree, family=family)
if isinstance(base_geo, _geometry.Hexmesh):
if degree == 0:
return HexmeshPiecewiseConstantBasis(geo)
if element_basis == ElementBasis.SERENDIPITY and degree > 1:
if discontinuous:
return HexmeshDGSerendipityBasisSpace(geo, degree=degree, family=family)
else:
return HexmeshSerendipityBasisSpace(geo, degree=degree, family=family)
if element_basis == ElementBasis.NONCONFORMING_POLYNOMIAL:
return HexmeshPolynomialBasisSpace(geo, degree=degree)
if discontinuous:
return HexmeshDGTripolynomialBasisSpace(geo, degree=degree, family=family)
else:
return HexmeshTripolynomialBasisSpace(geo, degree=degree, family=family)
raise NotImplementedError()
def make_collocated_function_space(
basis_space: BasisSpace, dtype: type = float, dof_mapper: Optional[DofMapper] = None
) -> CollocatedFunctionSpace:
"""
Constructs a function space from a basis space and a value type, such that all degrees of freedom of the value type are stored at each of the basis nodes.
Args:
geo: the Geometry on which to build the space
dtype: value type the function space. If ``dof_mapper`` is provided, the value type from the DofMapper will be used instead.
dof_mapper: mapping from node degrees of freedom to function values, defaults to Identity. Useful for reduced coordinates, e.g. :py:class:`SymmetricTensorMapper` maps 2x2 (resp 3x3) symmetric tensors to 3 (resp 6) degrees of freedom.
Returns:
the constructed function space
"""
return CollocatedFunctionSpace(basis_space, dtype=dtype, dof_mapper=dof_mapper)
def make_polynomial_space(
geo: _geometry.Geometry,
dtype: type = float,
dof_mapper: Optional[DofMapper] = None,
degree: int = 1,
element_basis: Optional[ElementBasis] = None,
discontinuous: bool = False,
family: Optional[_polynomial.Polynomial] = None,
) -> CollocatedFunctionSpace:
"""
Equips a geometry with a collocated, polynomial function space.
Equivalent to successive calls to :func:`make_polynomial_basis_space` and `make_collocated_function_space`.
Args:
geo: the Geometry on which to build the space
dtype: value type the function space. If ``dof_mapper`` is provided, the value type from the DofMapper will be used instead.
dof_mapper: mapping from node degrees of freedom to function values, defaults to Identity. Useful for reduced coordinates, e.g. :py:class:`SymmetricTensorMapper` maps 2x2 (resp 3x3) symmetric tensors to 3 (resp 6) degrees of freedom.
degree: polynomial degree of the per-element shape functions
discontinuous: if True, use Discontinuous Galerkin shape functions. Discontinuous is implied if degree is 0, i.e, piecewise-constant shape functions.
element_basis: type of basis function for the individual elements
family: Polynomial family used to generate the shape function basis. If not provided, a reasonable basis is chosen.
Returns:
the constructed function space
"""
basis_space = make_polynomial_basis_space(geo, degree, element_basis, discontinuous, family)
return CollocatedFunctionSpace(basis_space, dtype=dtype, dof_mapper=dof_mapper)