diff --git a/src/fesa/elements/hex8_element.cpp b/src/fesa/elements/hex8_element.cpp index cc3eb6a..26a9b78 100644 --- a/src/fesa/elements/hex8_element.cpp +++ b/src/fesa/elements/hex8_element.cpp @@ -5,6 +5,7 @@ #include #include +#include "../math/dense_blas_internal.h" #include "hex8_geometry.h" namespace fesa { @@ -38,24 +39,39 @@ Matrix Outer(const std::array& values, double coefficient) { } return left.Multiply(right); } -/// @brief Forms node-gradient Gram and stress congruence through dense MKL. +/// @brief Uses MKL entry products and the original ordered Gram/stress sums. Matrix GradientProduct(const std::array& gradients, const Tensor* stress = nullptr) { - Matrix left{8U, 3U}; - Matrix transpose{3U, 8U}; + const std::size_t terms = stress == nullptr ? 3U : 9U; + Vector left{64U * terms}; + Vector right{64U * terms}; + Vector final_factor{64U * terms}; for (std::size_t a = 0; a < 8; ++a) - for (std::size_t i = 0; i < 3; ++i) { - left(a, i) = gradients[a][i]; - transpose(i, a) = gradients[a][i]; - } - if (stress != nullptr) { - Matrix stress_transpose{3U, 3U}; - for (std::size_t i = 0; i < 3; ++i) + for (std::size_t b = 0; b < 8; ++b) for (std::size_t j = 0; j < 3; ++j) - stress_transpose(i, j) = (*stress)[j][i]; - left = left.Multiply(stress_transpose); - } - return left.Multiply(transpose); + for (std::size_t l = 0; l < (stress == nullptr ? 1U : 3U); ++l) { + const auto entry = (8U * a + b) * terms + + (stress == nullptr ? j : 3U * j + l); + left[entry] = gradients[a][j]; + right[entry] = stress == nullptr ? gradients[b][j] : (*stress)[l][j]; + final_factor[entry] = gradients[b][l]; + } + auto products = dense_blas_internal::MultiplyDiagonal(left, right); + if (stress != nullptr) + products = dense_blas_internal::MultiplyDiagonal(products, final_factor); + Matrix result{8U, 8U}; + for (std::size_t a = 0; a < 8; ++a) + for (std::size_t b = 0; b < 8; ++b) { + const auto first = (8U * a + b) * terms; + if (stress == nullptr) { + result(a, b) = (products[first] + products[first + 1U]) + + products[first + 2U]; + } else { + for (std::size_t term = 0; term < terms; ++term) + result(a, b) += products[first + term]; + } + } + return result; } /// @brief Retains product and cancellation errors in fixed-order contractions. void AccumulateProduct(double left, double right, double& sum,