qbhf2's picture
added NvidiaWarp and GarmentCode repos
66c9c8a
from typing import Any
from enum import Enum
import math
import warp as wp
import warp.types
vec6 = wp.types.vector(length=6, dtype=wp.float32)
_SQRT_2 = wp.constant(math.sqrt(2.0))
_SQRT_3 = wp.constant(math.sqrt(3.0))
_SQRT_1_2 = wp.constant(math.sqrt(1.0 / 2.0))
_SQRT_1_3 = wp.constant(math.sqrt(1.0 / 3.0))
class DofMapper:
"""Base class from mapping node degrees of freedom to function values"""
value_dtype: type
dof_dtype: type
DOF_SIZE: int
@wp.func
def dof_to_value(dof: Any):
raise NotImplementedError
@wp.func
def value_to_dof(val: Any):
raise NotImplementedError
def __str__(self):
return f"{self.value_dtype.__name__}_{self.DOF_SIZE}"
class IdentityMapper(DofMapper):
"""Identity mapper"""
def __init__(self, dtype: type):
if dtype == float:
dtype = wp.float32
self.value_dtype = dtype
self.dof_dtype = dtype
size = warp.types.type_length(dtype)
self.DOF_SIZE = wp.constant(size)
@wp.func
def dof_to_value(dof: Any):
return dof
@wp.func
def value_to_dof(val: Any):
return val
class SymmetricTensorMapper(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.
"""
class Mapping(Enum):
VOIGT = 0
"""Voigt ordering of vector coefficients:
first the three diagonal terms, then off-diagonal coefficients"""
DB16 = 1
"""Ordering that also separates normal from tangential coefficients:
first trace, then other diagonal terms, then off-diagonal coefficients.
See [Daviet and Bertails-Descoubes 2016]"""
def __init__(self, dtype: type, mapping: Mapping = Mapping.VOIGT):
self.value_dtype = dtype
self.mapping = mapping
if dtype == wp.mat22:
self.dof_dtype = wp.vec3
self.DOF_SIZE = wp.constant(3)
if mapping == SymmetricTensorMapper.Mapping.VOIGT:
self.dof_to_value = SymmetricTensorMapper.dof_to_value_2d_voigt
self.value_to_dof = SymmetricTensorMapper.value_to_dof_2d_voigt
else:
self.dof_to_value = SymmetricTensorMapper.dof_to_value_2d
self.value_to_dof = SymmetricTensorMapper.value_to_dof_2d
elif dtype == wp.mat33:
self.dof_dtype = vec6
self.DOF_SIZE = wp.constant(6)
if mapping == SymmetricTensorMapper.Mapping.VOIGT:
self.dof_to_value = SymmetricTensorMapper.dof_to_value_3d_voigt
self.value_to_dof = SymmetricTensorMapper.value_to_dof_3d_voigt
else:
self.dof_to_value = SymmetricTensorMapper.dof_to_value_3d
self.value_to_dof = SymmetricTensorMapper.value_to_dof_3d
else:
raise ValueError("Unsupported value dtype: ", dtype)
def __str__(self):
return f"{self.mapping}_{self.DOF_SIZE}"
@wp.func
def dof_to_value_2d(dof: wp.vec3):
a = dof[0]
b = dof[1]
c = dof[2]
return wp.mat22(a + b, c, c, a - b)
@wp.func
def value_to_dof_2d(val: wp.mat22):
a = 0.5 * (val[0, 0] + val[1, 1])
b = 0.5 * (val[0, 0] - val[1, 1])
c = 0.5 * (val[0, 1] + val[1, 0])
return wp.vec3(a, b, c)
@wp.func
def dof_to_value_2d_voigt(dof: wp.vec3):
a = _SQRT_2 * dof[0]
b = _SQRT_2 * dof[1]
c = dof[2]
return wp.mat22(a, c, c, b)
@wp.func
def value_to_dof_2d_voigt(val: wp.mat22):
a = _SQRT_1_2 * val[0, 0]
b = _SQRT_1_2 * val[1, 1]
c = 0.5 * (val[0, 1] + val[1, 0])
return wp.vec3(a, b, c)
@wp.func
def dof_to_value_3d(dof: vec6):
a = dof[0] * _SQRT_2 * _SQRT_1_3
b = dof[1]
c = dof[2] * _SQRT_1_3
d = dof[3]
e = dof[4]
f = dof[5]
return wp.mat33(
a + b - c,
f,
e,
f,
a - b - c,
d,
e,
d,
a + 2.0 * c,
)
@wp.func
def value_to_dof_3d(val: wp.mat33):
a = (val[0, 0] + val[1, 1] + val[2, 2]) * _SQRT_1_3 * _SQRT_1_2
b = 0.5 * (val[0, 0] - val[1, 1])
c = 0.5 * (val[2, 2] - (val[0, 0] + val[1, 1] + val[2, 2]) / 3.0) * _SQRT_3
d = 0.5 * (val[2, 1] + val[1, 2])
e = 0.5 * (val[0, 2] + val[2, 0])
f = 0.5 * (val[1, 0] + val[0, 1])
return vec6(a, b, c, d, e, f)
@wp.func
def dof_to_value_3d_voigt(dof: vec6):
a = _SQRT_2 * dof[0]
b = _SQRT_2 * dof[1]
c = _SQRT_2 * dof[2]
d = dof[3]
e = dof[4]
f = dof[5]
return wp.mat33(
a,
f,
e,
f,
b,
d,
e,
d,
c,
)
@wp.func
def value_to_dof_3d_voigt(val: wp.mat33):
a = _SQRT_1_2 * val[0, 0]
b = _SQRT_1_2 * val[1, 1]
c = _SQRT_1_2 * val[2, 2]
d = 0.5 * (val[2, 1] + val[1, 2])
e = 0.5 * (val[0, 2] + val[2, 0])
f = 0.5 * (val[1, 0] + val[0, 1])
return vec6(a, b, c, d, e, f)
class SkewSymmetricTensorMapper(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.
"""
def __init__(self, dtype: type):
self.value_dtype = dtype
if dtype == wp.mat22:
self.dof_dtype = float
self.DOF_SIZE = wp.constant(1)
self.dof_to_value = SkewSymmetricTensorMapper.dof_to_value_2d
self.value_to_dof = SkewSymmetricTensorMapper.value_to_dof_2d
elif dtype == wp.mat33:
self.dof_dtype = wp.vec3
self.DOF_SIZE = wp.constant(3)
self.dof_to_value = SkewSymmetricTensorMapper.dof_to_value_3d
self.value_to_dof = SkewSymmetricTensorMapper.value_to_dof_3d
else:
raise ValueError("Unsupported value dtype: ", dtype)
def __str__(self):
return f"{self.__class__.__name__}_{self.DOF_SIZE}"
@wp.func
def dof_to_value_2d(dof: float):
return wp.mat22(0.0, -dof, dof, 0.0)
@wp.func
def value_to_dof_2d(val: wp.mat22):
return 0.5 * (val[1, 0] - val[0, 1])
@wp.func
def dof_to_value_3d(dof: wp.vec3):
a = dof[0]
b = dof[1]
c = dof[2]
return wp.mat33(0.0, -c, b, c, 0.0, -a, -b, a, 0.0)
@wp.func
def value_to_dof_3d(val: wp.mat33):
a = 0.5 * (val[2, 1] - val[1, 2])
b = 0.5 * (val[0, 2] - val[2, 0])
c = 0.5 * (val[1, 0] - val[0, 1])
return wp.vec3(a, b, c)