qbhf2's picture
added NvidiaWarp and GarmentCode repos
66c9c8a
from typing import Union
from enum import Enum
import warp as wp
import warp.codegen
import warp.context
from warp.fem.geometry import (
Element,
Geometry,
GeometryPartition,
WholeGeometryPartition,
)
GeometryOrPartition = Union[Geometry, GeometryPartition]
class GeometryDomain:
"""Interface class for domains, i.e. (partial) views of elements in a Geometry"""
class ElementKind(Enum):
"""Possible kinds of elements contained in a domain"""
CELL = 0
SIDE = 1
def __init__(self, geometry: GeometryOrPartition):
if isinstance(geometry, GeometryPartition):
self.geometry_partition = geometry
else:
self.geometry_partition = WholeGeometryPartition(geometry)
self.geometry = self.geometry_partition.geometry
@property
def name(self) -> str:
return f"{self.geometry_partition.name}_{self.__class__.__name__}"
def __str__(self) -> str:
return self.name
def __eq__(self, other) -> bool:
return self.__class__ == other.__class__ and self.geometry_partition == other.geometry_partition
@property
def element_kind(self) -> ElementKind:
"""Kind of elements that this domain contains (cells or sides)"""
raise NotImplementedError
@property
def dimension(self) -> int:
"""Dimension of the elements of the domain"""
raise NotImplementedError
def element_count(self) -> int:
"""Number of elements in the domain"""
raise NotImplementedError
def geometry_element_count(self) -> int:
"""Number of elements in the underlying geometry"""
return self.geometry.cell_count()
def reference_element(self) -> Element:
"""Protypical element"""
raise NotImplementedError
def element_index_arg_value(self, device: warp.context.Devicelike) -> warp.codegen.StructInstance:
"""Value of the argument to be passed to device functions"""
raise NotImplementedError
def element_arg_value(self, device: warp.context.Devicelike) -> warp.codegen.StructInstance:
"""Value of the argument to be passed to device functions"""
raise NotImplementedError
ElementIndexArg: warp.codegen.Struct
"""Structure containing arguments to be passed to device functions computing element indices"""
element_index: wp.Function
"""Device function for retrieving an ElementIndex from a linearized index"""
ElementArg: warp.codegen.Struct
"""Structure containing arguments to be passed to device functions computing element geometry"""
element_measure: wp.Function
"""Device function returning the measure determinant (e.g. volume, area) at a given point"""
element_measure_ratio: wp.Function
"""Device function returning the ratio of the measure of a side to that of its neighbour cells"""
element_position: wp.Function
"""Device function returning the element position at a sample point"""
element_deformation_gradient: wp.Function
"""Device function returning the gradient of the position with respect to the element's reference space"""
element_normal: wp.Function
"""Device function returning the element normal at a sample point"""
element_lookup: wp.Function
"""Device function returning the sample point corresponding to a world position"""
class Cells(GeometryDomain):
"""A Domain containing all cells of the geometry or geometry partition"""
def __init__(self, geometry: GeometryOrPartition):
super().__init__(geometry)
@property
def element_kind(self) -> GeometryDomain.ElementKind:
return GeometryDomain.ElementKind.CELL
@property
def dimension(self) -> int:
return self.geometry.dimension
def reference_element(self) -> Element:
return self.geometry.reference_cell()
def element_count(self) -> int:
return self.geometry_partition.cell_count()
def geometry_element_count(self) -> int:
return self.geometry.cell_count()
@property
def ElementIndexArg(self) -> warp.codegen.Struct:
return self.geometry_partition.CellArg
def element_index_arg_value(self, device: warp.context.Devicelike) -> warp.codegen.StructInstance:
return self.geometry_partition.cell_arg_value(device)
@property
def element_index(self) -> wp.Function:
return self.geometry_partition.cell_index
def element_arg_value(self, device: warp.context.Devicelike) -> warp.codegen.StructInstance:
return self.geometry.cell_arg_value(device)
@property
def ElementArg(self) -> warp.codegen.Struct:
return self.geometry.CellArg
@property
def element_position(self) -> wp.Function:
return self.geometry.cell_position
@property
def element_deformation_gradient(self) -> wp.Function:
return self.geometry.cell_deformation_gradient
@property
def element_measure(self) -> wp.Function:
return self.geometry.cell_measure
@property
def element_measure_ratio(self) -> wp.Function:
return self.geometry.cell_measure_ratio
@property
def eval_normal(self) -> wp.Function:
return self.geometry.cell_normal
@property
def element_lookup(self) -> wp.Function:
return self.geometry.cell_lookup
class Sides(GeometryDomain):
"""A Domain containing all (interior and boundary) sides of the geometry or geometry partition"""
def __init__(self, geometry: GeometryOrPartition):
self.geometry = geometry
super().__init__(geometry)
@property
def element_kind(self) -> GeometryDomain.ElementKind:
return GeometryDomain.ElementKind.SIDE
@property
def dimension(self) -> int:
return self.geometry.dimension - 1
def reference_element(self) -> Element:
return self.geometry.reference_side()
def element_count(self) -> int:
return self.geometry_partition.side_count()
def geometry_element_count(self) -> int:
return self.geometry.side_count()
@property
def ElementIndexArg(self) -> warp.codegen.Struct:
return self.geometry_partition.SideArg
def element_index_arg_value(self, device: warp.context.Devicelike) -> warp.codegen.StructInstance:
return self.geometry_partition.side_arg_value(device)
@property
def element_index(self) -> wp.Function:
return self.geometry_partition.side_index
@property
def ElementArg(self) -> warp.codegen.Struct:
return self.geometry.SideArg
def element_arg_value(self, device: warp.context.Devicelike) -> warp.codegen.StructInstance:
return self.geometry.side_arg_value(device)
@property
def element_position(self) -> wp.Function:
return self.geometry.side_position
@property
def element_deformation_gradient(self) -> wp.Function:
return self.geometry.side_deformation_gradient
@property
def element_measure(self) -> wp.Function:
return self.geometry.side_measure
@property
def element_measure_ratio(self) -> wp.Function:
return self.geometry.side_measure_ratio
@property
def eval_normal(self) -> wp.Function:
return self.geometry.side_normal
class BoundarySides(Sides):
"""A Domain containing boundary sides of the geometry or geometry partition"""
def __init__(self, geometry: GeometryOrPartition):
super().__init__(geometry)
def element_count(self) -> int:
return self.geometry_partition.boundary_side_count()
def geometry_element_count(self) -> int:
return self.geometry.boundary_side_count()
@property
def element_index(self) -> wp.Function:
return self.geometry_partition.boundary_side_index
class FrontierSides(Sides):
"""A Domain containing frontier sides of the geometry partition (sides shared with at least another partition)"""
def __init__(self, geometry: GeometryOrPartition):
super().__init__(geometry)
def element_count(self) -> int:
return self.geometry_partition.frontier_side_count()
def geometry_element_count(self) -> int:
raise RuntimeError("Frontier sides not defined at the geometry level")
@property
def element_index(self) -> wp.Function:
return self.geometry_partition.frontier_side_index