diff --git a/src/core/static_types.hh b/src/core/static_types.hh
index e4a2ff8..b53d0a7 100644
--- a/src/core/static_types.hh
+++ b/src/core/static_types.hh
@@ -1,810 +1,810 @@
/*
* SPDX-License-Indentifier: AGPL-3.0-or-later
*
* Copyright (©) 2016-2024 EPFL (École Polytechnique Fédérale de Lausanne),
* Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
* Copyright (©) 2020-2024 Lucas Frérot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*
*/
/* -------------------------------------------------------------------------- */
#ifndef STATIC_TYPES_HH
#define STATIC_TYPES_HH
/* -------------------------------------------------------------------------- */
#include "tamaas.hh"
-#include
+#include
#include
#include
namespace tamaas {
/* -------------------------------------------------------------------------- */
namespace detail {
/// \cond HIDDEN_SYMBOLS
template
struct product_tail_rec : product_tail_rec {};
/// \endcond
template
struct product_tail_rec : std::integral_constant {};
/// \cond HIDDEN_SYMBOLS
template
struct get_rec : get_rec {};
/// \endcond
template
struct get_rec<0, n, ns...> : std::integral_constant {};
} // namespace detail
template
struct product : detail::product_tail_rec<1, ns...> {};
template
struct get : detail::get_rec {};
template
struct is_arithmetic : std::is_arithmetic {};
template
struct is_arithmetic> : std::true_type {};
template
struct voigt_size;
template <>
struct voigt_size<3> : std::integral_constant {};
template <>
struct voigt_size<2> : std::integral_constant {};
template <>
struct voigt_size<1> : std::integral_constant {};
/* -------------------------------------------------------------------------- */
/**
* @brief Static Array
*
* This class is meant to be a small and fast object for intermediate
* calculations, possibly on wrapped memory belonging to a grid. Support type
* show be either a pointer or a C array. It should not contain any virtual
* method.
*/
template
class StaticArray {
static_assert(std::is_array::value or
std::is_pointer::value,
"the support type of StaticArray should be either a pointer or "
"a C-array");
using T = DataType;
using T_bare = typename std::remove_cv_t;
public:
using value_type = T;
static constexpr UInt size = _size;
public:
StaticArray() = default;
~StaticArray() = default;
StaticArray(const StaticArray&) = delete;
StaticArray(StaticArray&&) = delete;
StaticArray& operator=(StaticArray&&) = delete;
public:
/// Access operator
__device__ __host__ auto operator()(UInt i) -> T& { return _mem[i]; }
/// Access operator
__device__ __host__ auto operator()(UInt i) const -> const T& {
return _mem[i];
}
/// Scalar product
template
__device__ __host__ auto dot(const StaticArray& o) const
-> T_bare {
decltype(T_bare(0) * DT(0)) res = 0;
for (UInt i = 0; i < size; ++i)
res += (*this)(i)*o(i);
return res;
}
/// L2 norm squared
__device__ __host__ T_bare l2squared() const { return this->dot(*this); }
/// L2 norm
__device__ __host__ T_bare l2norm() const { return std::sqrt(l2squared()); }
/// Sum of all elements
__device__ __host__ T_bare sum() const {
T_bare res = 0;
for (UInt i = 0; i < size; ++i)
res += (*this)(i);
return res;
}
#define VECTOR_OP(op) \
template \
__device__ __host__ void operator op(const StaticArray& o) { \
for (UInt i = 0; i < size; ++i) \
(*this)(i) op o(i); \
}
VECTOR_OP(+=)
VECTOR_OP(-=)
VECTOR_OP(*=)
VECTOR_OP(/=)
#undef VECTOR_OP
#define SCALAR_OP(op) \
template \
__device__ __host__ std::enable_if_t::value, StaticArray&> \
operator op(const T1& x) { \
for (UInt i = 0; i < size; ++i) \
(*this)(i) op x; \
return *this; \
}
SCALAR_OP(+=)
SCALAR_OP(-=)
SCALAR_OP(*=)
SCALAR_OP(/=)
SCALAR_OP(=)
#undef SCALAR_OP
/// Overriding the implicit copy operator
__device__ __host__ StaticArray& operator=(const StaticArray& o) {
copy(o);
return *this;
}
template
__device__ __host__ void operator=(const StaticArray& o) {
copy(o);
}
template
__device__ __host__ StaticArray& copy(const StaticArray& o) {
for (UInt i = 0; i < size; ++i)
(*this)(i) = o(i);
return *this;
}
T* begin() { return _mem; }
const T* begin() const { return _mem; }
T* end() { return _mem + size; }
const T* end() const { return _mem + size; }
private:
template
using valid_size_t = std::enable_if_t<(size > 0), U>;
public:
__host__ __device__ valid_size_t front() { return *_mem; }
__host__ __device__ valid_size_t front() const { return *_mem; }
__host__ __device__ valid_size_t back() { return _mem[size - 1]; }
__host__ __device__ valid_size_t back() const {
return _mem[size - 1];
}
protected:
SupportType _mem;
};
/**
* @brief Static Tensor
*
* This class implements a multi-dimensional tensor behavior.
*/
template
class StaticTensor
: public StaticArray::value> {
using parent = StaticArray::value>;
using T = DataType;
public:
static constexpr UInt dim = sizeof...(dims);
using parent::operator=;
private:
template
__device__ __host__ static UInt unpackOffset(UInt offset, UInt index,
Idx... rest) {
constexpr UInt size = sizeof...(rest);
offset += index;
offset *= get::value;
return unpackOffset(offset, rest...);
}
template
__device__ __host__ static UInt unpackOffset(UInt offset, UInt index) {
return offset + index;
}
public:
template
__device__ __host__ const T& operator()(Idx... idx) const {
return parent::operator()(unpackOffset(0, idx...));
}
template
__device__ __host__ T& operator()(Idx... idx) {
return parent::operator()(unpackOffset(0, idx...));
}
};
/* -------------------------------------------------------------------------- */
/* Common Static Types */
/* -------------------------------------------------------------------------- */
// Forward declaration
template
class StaticVector;
template
class StaticSymMatrix;
/* -------------------------------------------------------------------------- */
template
class StaticMatrix : public StaticTensor {
using T = DataType;
using T_bare = typename std::remove_cv_t;
public:
using StaticTensor::operator=;
// /// Initialize from a symmetric matrix
template
__device__ __host__ std::enable_if_t
fromSymmetric(const StaticSymMatrix& o);
/// Outer product of two vectors
template
__device__ __host__ void outer(const StaticVector& a,
const StaticVector& b);
template
__device__ __host__ void mul(const StaticMatrix& a,
const StaticMatrix& b) {
(*this) = T(0);
for (UInt i = 0; i < n; ++i)
for (UInt j = 0; j < m; ++j)
for (UInt k = 0; k < l; ++k)
(*this)(i, j) += a(i, k) * b(k, j);
}
__device__ __host__ std::enable_if_t trace() const {
T_bare res{0};
for (UInt i = 0; i < n; ++i)
res += (*this)(i, i);
return res;
}
template
__device__ __host__ std::enable_if_t
deviatoric(const StaticMatrix& mat, Real factor = n) {
auto norm_trace = mat.trace() / factor;
for (UInt i = 0; i < n; ++i)
for (UInt j = 0; j < m; ++j)
(*this)(i, j) = mat(i, j) - (i == j) * norm_trace;
}
};
/* -------------------------------------------------------------------------- */
/// Vector class with size determined at compile-time
template
class StaticVector : public StaticTensor {
using T = std::remove_cv_t;
public:
using StaticTensor::operator=;
/// Matrix-vector product
template
__device__ __host__ void mul(const StaticMatrix& mat,
const StaticVector& vec) {
*this = T(0);
for (UInt i = 0; i < n; ++i)
for (UInt j = 0; j < m; ++j)
(*this)(i) +=
((transpose) ? mat(j, i) : mat(i, j)) * vec(j); // can be optimized
}
};
/* -------------------------------------------------------------------------- */
/// Symmetric matrix in Voigt notation
template
class StaticSymMatrix
: public StaticVector::value> {
using parent = StaticVector::value>;
using T = std::remove_cv_t;
private:
template
__device__ __host__ void sym_binary(const StaticMatrix& m,
BinOp&& op) {
for (UInt i = 0; i < n; ++i)
op((*this)(i), m(i, i));
const auto a = 0.5 * std::sqrt(2);
for (UInt i = 0, b = n; i < n; ++i)
for (UInt j = i + 1; j < n; ++j)
op((*this)(b++), a * (m(i, j) + m(j, i)));
// Old Mendel-Voigt loops
// for (UInt j = n - 1, b = n; j > 0; --j)
// for (Int i = j - 1; i >= 0; --i)
// op((*this)(b++), a * (m(i, j) + m(j, i)));
}
public:
/// Copy values from matrix and symmetrize
template
__device__ __host__ void symmetrize(const StaticMatrix& m) {
sym_binary(m, [](auto&& v, auto&& w) { v = w; });
}
/// Add values from symmetrized matrix
template
__device__ __host__ void operator+=(const StaticMatrix& m) {
sym_binary(m, [](auto&& v, auto&& w) { v += w; });
}
__device__ __host__ auto trace() const {
std::remove_cv_t res = 0;
for (UInt i = 0; i < n; ++i)
res += (*this)(i);
return res;
}
template
__device__ __host__ void deviatoric(const StaticSymMatrix& m,
Real factor = n) {
auto tr = m.trace() / factor;
for (UInt i = 0; i < n; ++i)
(*this)(i) = m(i) - tr;
for (UInt i = n; i < voigt_size::value; ++i)
(*this)(i) = m(i);
}
using parent::operator+=;
using parent::operator=;
};
/* -------------------------------------------------------------------------- */
// Implementation of constructor from symmetric matrix
template
template
__device__ __host__ std::enable_if_t
StaticMatrix::fromSymmetric(
const StaticSymMatrix& o) {
for (UInt i = 0; i < n; ++i)
(*this)(i, i) = o(i);
// We use Mendel-Voigt notation for the vector representation
// Specifically from
// https://thelfer.github.io/tfel/web/tensors.html#vector-notations-for-symmetric-tensors
const auto a = 1. / std::sqrt(2);
for (UInt i = 0, b = n; i < n; ++i)
for (UInt j = i + 1; j < n; ++j)
(*this)(i, j) = (*this)(j, i) = a * o(b++);
// Old Mendel-Voigt
// for (UInt j = n - 1, b = n; j > 0; --j)
// for (Int i = j - 1; i >= 0; --i)
// (*this)(i, j) = (*this)(j, i) = a * o(b++);
}
// Implementation of outer product
template
template
__device__ __host__ void StaticMatrix::outer(
const StaticVector& a, const StaticVector& b) {
for (UInt i = 0; i < n; ++i)
for (UInt j = 0; j < m; ++j)
(*this)(i, j) = a(i) * b(j);
}
/* -------------------------------------------------------------------------- */
/* On the stack static types */
/* -------------------------------------------------------------------------- */
template class StaticParent,
UInt... dims>
struct static_size_helper : product {};
template
struct static_size_helper : voigt_size {};
template class StaticParent, typename T,
UInt... dims>
class Tensor
: public StaticParent<
T, T[static_size_helper::value], dims...> {
static constexpr UInt size = static_size_helper::value;
using parent = StaticParent;
public:
using parent::operator=;
using parent::copy;
/// Default constructor
Tensor() = default;
/// Construct with default value
__device__ __host__ Tensor(T val) { *this = val; }
/// Construct from array
__device__ __host__ Tensor(const std::array& arr) {
// we use size to ensure static loop unrolling
for (UInt i = 0; i < size; ++i)
this->_mem[i] = arr[i];
}
/// Copy from array
__device__ __host__ Tensor& operator=(const std::array& arr) {
// we use size to ensure static loop unrolling
for (UInt i = 0; i < size; ++i)
(*this)(i) = arr[i];
}
/// Construct by copy from static tensor
template
__device__ __host__ Tensor(const StaticParent& o) {
copy(o);
}
__device__ __host__ Tensor(const Tensor& o) : parent() { copy(o); }
__device__ __host__ Tensor& operator=(const Tensor& o) {
copy(o);
return *this;
}
__device__ __host__ Tensor(Tensor&& o) noexcept { copy(o); }
};
template
using Matrix = Tensor;
template
using SymMatrix = Tensor;
template
using Vector = Tensor;
/* -------------------------------------------------------------------------- */
/* Proxy Static Types */
/* -------------------------------------------------------------------------- */
/// Proxy type for tensor
template class StaticParent, typename T,
UInt... dims>
class TensorProxy : public StaticParent {
using parent = StaticParent;
public:
/// Explicit construction from data location
__device__ __host__ explicit TensorProxy(T* spot) { this->_mem = spot; }
/// Explicit construction from lvalue-reference
__device__ __host__ explicit TensorProxy(T& spot) : TensorProxy(&spot) {}
/// Construction from static tensor
template
__device__ __host__
TensorProxy(StaticParent& o)
: TensorProxy(o.begin()) {}
using parent::operator=;
__device__ __host__ TensorProxy(const TensorProxy& o) { this->_mem = o._mem; }
__device__ __host__ TensorProxy& operator=(const TensorProxy& o) {
this->copy(o);
return *this;
}
__device__ __host__ TensorProxy(TensorProxy&& o) noexcept
: TensorProxy(exchange(o._mem, nullptr)) {}
public:
using stack_type = Tensor;
};
template
using MatrixProxy = TensorProxy;
template
using SymMatrixProxy = TensorProxy;
template
using VectorProxy = TensorProxy;
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
/* Arithmetic operators creating temporaries */
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
/* Simple operators */
/* -------------------------------------------------------------------------- */
template
__device__ __host__ Vector
operator+(const StaticVector& a,
const StaticVector& b) {
Vector res(a);
res += b;
return res;
}
template
__device__ __host__ Vector
operator-(const StaticVector& a,
const StaticVector& b) {
Vector res(a);
res -= b;
return res;
}
template
__device__ __host__ Vector
operator-(const StaticVector& a) {
Vector res(a);
res *= -1;
return res;
}
template
__device__ __host__ Matrix
operator+(const StaticMatrix& a,
const StaticMatrix& b) {
Matrix res(a);
res += b;
return res;
}
template
__device__ __host__ Matrix
operator-(const StaticMatrix& a,
const StaticMatrix& b) {
Matrix res(a);
res -= b;
return res;
}
template
__device__ __host__ Matrix
operator-(const StaticMatrix& a) {
Matrix res(a);
res *= -1;
return res;
}
template
__device__ __host__ SymMatrix
operator+(const StaticSymMatrix& a,
const StaticSymMatrix& b) {
SymMatrix res(a);
res += b;
return res;
}
template
__device__ __host__ SymMatrix
operator-(const StaticSymMatrix& a,
const StaticSymMatrix& b) {
SymMatrix res(a);
res -= b;
return res;
}
template
__device__ __host__ SymMatrix
operator-(const StaticSymMatrix& a) {
SymMatrix res(a);
res *= -1;
return res;
}
template ::value>>
__device__ __host__ Vector
operator*(const StaticVector& a, const T& b) {
Vector res{a};
res *= b;
return res;
}
// symmetry
template ::value>>
__device__ __host__ Vector
operator*(const T& b, const StaticVector& a) {
return a * b;
}
template ::value>>
__device__ __host__ Matrix
operator*(const StaticMatrix& a, const T& b) {
Matrix res{a};
res *= b;
return res;
}
// symmetry
template ::value, void>>
__device__ __host__ Matrix
operator*(const T& b, const StaticMatrix& a) {
return a * b;
}
template ::value>>
__device__ __host__ SymMatrix
operator*(const StaticSymMatrix& a, const T& b) {
SymMatrix res{a};
res *= b;
return res;
}
// symmetry
template ::value>>
__device__ __host__ SymMatrix
operator*(const T& b, const StaticSymMatrix& a) {
return a * b;
}
/* -------------------------------------------------------------------------- */
/* Linear algebra operators */
/* -------------------------------------------------------------------------- */
/// Matrix-vector multiplication
template
__device__ __host__ Vector
operator*(const StaticMatrix& a,
const StaticVector& b) {
Vector res;
res.template mul(a, b);
return res;
}
/// Matrix-matrix multiplication
template
__device__ __host__ Matrix
operator*(const StaticMatrix& a,
const StaticMatrix& b) {
Matrix res;
res.mul(a, b);
return res;
}
template
__device__ __host__ Matrix
outer(const StaticVector& a, const StaticVector& b) {
Matrix res;
res.outer(a, b);
return res;
}
/* -------------------------------------------------------------------------- */
/* Dense/Sparse */
/* -------------------------------------------------------------------------- */
template
__device__ __host__ Matrix, n, n>
dense(const StaticSymMatrix& m) {
Matrix, n, n> res;
res.fromSymmetric(m);
return res;
}
template
__device__ __host__ auto dense(const StaticVector& v)
-> Vector {
return v;
}
template
__device__ __host__ SymMatrix, n>
symmetrize(const StaticMatrix& m) {
SymMatrix, n> res;
res.symmetrize(m);
return res;
}
/* -------------------------------------------------------------------------- */
template
__device__ __host__ Vector, 3>
invariants(const StaticSymMatrix& m) {
return {
{// I1 = tr(A)
m.trace(),
// I2 = 1/2 * (tr(A)^2 - tr(A^2))
m(0) * m(1) + m(1) * m(2) + m(0) * m(2) -
(m(3) * m(3) + m(4) * m(4) + m(5) * m(5)) / 2,
// I3 = det(A)
m(0) * m(1) * m(2) + m(5) * m(3) * m(4) / std::sqrt(Real(2)) -
(m(4) * m(4) * m(1) + m(5) * m(5) * m(0) + m(3) * m(3) * m(2)) / 2}};
}
template
__device__ __host__ Vector, 3>
eigenvalues(const StaticSymMatrix& m) {
constexpr UInt n = 3;
Vector, n> eigenv;
auto inv = invariants(m);
Real a = 1, b = -inv(0), c = inv(1), d = -inv(2);
auto p = (3 * a * c - b * b) / (3 * a * a);
auto q = (2 * b * b * b - 9 * a * b * c + 27 * a * a * d) / (27 * a * a * a);
for (UInt k = 0; k < n; ++k)
eigenv(k) =
2. * std::sqrt(-p / 3.) *
std::cos(1. / 3. *
std::acos(3. * q / (2. * p) * std::sqrt(-3. / p)) -
2. * M_PI * k / 3.) -
b / (3. * a);
// Sorting eigenvalues
std::remove_cv_t max = eigenv(0);
UInt max_k = 0;
for (UInt k = 1; k < n; ++k) {
if (eigenv(k) > max) {
max = eigenv(k);
max_k = k;
}
}
thrust::swap(eigenv.back(), eigenv(max_k));
if (eigenv(0) > eigenv(1))
thrust::swap(eigenv(0), eigenv(1));
return eigenv;
}
/* -------------------------------------------------------------------------- */
/* Type traits */
/* -------------------------------------------------------------------------- */
template
struct is_proxy : std::false_type {};
template class StaticParent, typename T,
UInt... dims>
struct is_proxy> : std::true_type {};
template
struct is_proxy> : std::true_type {};
template
struct is_proxy> : std::true_type {};
template
struct is_proxy> : std::true_type {};
} // namespace tamaas
#endif // STATIC_TYPES_HH