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