#ifndef MEDUSA_BITS_OPERATORS_EXPLICITVECTOROPERATORS_HPP_ #define MEDUSA_BITS_OPERATORS_EXPLICITVECTOROPERATORS_HPP_ /** * @file * Explicit vector operators implementation. */ #include "ExplicitVectorOperators_fwd.hpp" #include #include #include "ShapeStorage_fwd.hpp" namespace mm { /** * Performs all asserts for a given node: asserts that node index is valid and that shape functions * were initialized for a given node. * @param node Node index to consider. */ #define NODE_ASSERTS(node) \ assert_msg(0 <= (node) && (node) < ss->size(), "Node index %d must be in range " \ "[0, num_nodes = %d).", ss->size()); /// @cond template template Eigen::Matrix< typename vector_type::type::scalar_t, vector_type::type::dim, ExplicitVectorOperators::dim> ExplicitVectorOperators::grad(const vector_field_t& u, int node) const { NODE_ASSERTS(node); constexpr int vector_dim = vector_type::type::dim; constexpr int domain_dim = ExplicitVectorOperators::dim; Eigen::Matrix::type::scalar_t, vector_dim, domain_dim> ret; for (int d = 0; d < vector_dim; ++d) { for (int var = 0; var < domain_dim; ++var) { ret(d, var) = ss->d1(var, node, 0) * u[ss->support(node, 0)][d]; for (int i = 1; i < ss->supportSize(node); ++i) { ret(d, var) += ss->d1(var, node, i) * u[ss->support(node, i)][d]; } } } return ret; } template template typename vector_type::type ExplicitVectorOperators::apply(const vector_field_t& u, int node, typename op_family_t::operator_t o) const { constexpr int u_dim = vector_type::type::dim; typename vector_type::type res; res.setZero(); int idx = op_family_t::index(o); for (int i = 0; i < ss->supportSize(node); ++i) { for (int d = 0; d < u_dim; ++d) { res[d] += ss->template get(idx, node, i) * u[ss->support(node, i)][d]; } } return res; } template template typename vector_type::type::scalar_t ExplicitVectorOperators::div(const vector_field_t& u, int node) const { NODE_ASSERTS(node); static_assert(static_cast(dim) == static_cast(vector_type::type::dim), "Domain and filed dimensions must match."); typename vector_type::type::scalar_t ret = ss->d1(0, node, 0) * u[ss->support(node, 0)][0]; for (int i = 1; i < ss->supportSize(node); ++i) ret += ss->d1(0, node, i) * u[ss->support(node, i)][0]; for (int var = 1; var < dim; ++var) for (int i = 0; i < ss->supportSize(node); ++i) ret += ss->d1(var, node, i) * u[ss->support(node, i)][var]; return ret; } template template typename vector_type::type ExplicitVectorOperators::curl(const vector_field_t& u, int node) const { NODE_ASSERTS(node); static_assert(static_cast(vector_type::type::dim) == 3, "The field must be three dimensional."); typename vector_type::type ret; ret.setZero(); for (int i = 0; i < ss->supportSize(node); ++i) { ret[0] += ss->d1(1, node, i) * u[ss->support(node, i)][2] - ss->d1(2, node, i) * u[ss->support(node, i)][1]; ret[1] += ss->d1(2, node, i) * u[ss->support(node, i)][0] - ss->d1(0, node, i) * u[ss->support(node, i)][2]; ret[2] += ss->d1(0, node, i) * u[ss->support(node, i)][1] - ss->d1(1, node, i) * u[ss->support(node, i)][0]; } return ret; } template template typename vector_type::type ExplicitVectorOperators::graddiv(const vector_field_t& u, int node) const { NODE_ASSERTS(node); static_assert(static_cast(dim) == static_cast(vector_type::type::dim), "Domain and filed dimensions must match."); typename vector_type::type ret; ret.setZero(); for (int d1 = 0; d1 < dim; ++d1) { for (int d2 = 0; d2 < dim; ++d2) { // loop over dimensions int dmin = std::min(d1, d2); int dmax = std::max(d1, d2); for (int i = 0; i < ss->supportSize(node); ++i) { ret[d1] += ss->d2(dmin, dmax, node, i) * u[ss->support(node, i)][d2]; } } } return ret; } template template typename vector_type::type ExplicitVectorOperators::neumann( const vector_field_t& u, int node, const vector_t& normal, typename vector_type::type val) const { NODE_ASSERTS(node); static_assert(static_cast(dim) == static_cast(vector_type::type::dim), "Domain and filed dimensions must match."); assert_msg(ss->support(node, 0) == node, "First support node should be the node itself."); scalar_t denominator = 0; for (int d = 0; d < dim; ++d) { for (int i = 1; i < ss->supportSize(node); ++i) { val -= normal[d] * ss->d1(d, node, i) * u[ss->support(node, i)]; } // i = 0 denominator += normal[d] * ss->d1(d, node, 0); } assert_msg(std::abs(denominator) >= 1e-14, "Node %d has no effect on the flux in direction %s. The cause of this might be wrong" " normal direction, bad neighbourhood choice or bad nodal positions.", node, normal); return val / denominator; } /// @endcond /// Output basic info about given operators. template std::ostream& operator<<(std::ostream& os, const ExplicitVectorOperators& op) { if (!op.hasShapes()) { return os << "Explicit vector operators without any linked storage."; } return os << "Explicit vector operators over storage: " << *op.ss; } template ExplicitVectorOperators ShapeStorage::explicitVectorOperators() const { return ExplicitVectorOperators(*static_cast(this)); } } // namespace mm #endif // MEDUSA_BITS_OPERATORS_EXPLICITVECTOROPERATORS_HPP_