diff --git a/include/GooseFEM/Element.h b/include/GooseFEM/Element.h index 0c18b56..4cc823b 100644 --- a/include/GooseFEM/Element.h +++ b/include/GooseFEM/Element.h @@ -1,35 +1,35 @@ /* (c - GPLv3) T.W.J. de Geus (Tom) | tom@geus.me | www.geus.me | github.com/tdegeus/GooseFEM */ #ifndef GOOSEFEM_ELEMENT_H #define GOOSEFEM_ELEMENT_H #include "config.h" namespace GooseFEM { namespace Element { // Convert nodal vector [nnode, ndim] to nodal vector stored per element [nelem, nne, ndim] -inline xt::xtensor asElementVector( - const xt::xtensor& conn, const xt::xtensor& nodevec); +inline xt::xtensor asElementVector( + const xt::xtensor& conn, const xt::xtensor& nodevec); // Assemble nodal vector stored per element [nelem, nne, ndim] to nodal vector [nnode, ndim] -inline xt::xtensor assembleNodeVector( - const xt::xtensor& conn, const xt::xtensor& elemvec); +inline xt::xtensor assembleNodeVector( + const xt::xtensor& conn, const xt::xtensor& elemvec); // Check that DOFs leave no holes template inline bool isSequential(const E& dofs); // Check structure of the matrices stored per element [nelem, nne*ndim, nne*ndim] -bool isDiagonal(const xt::xtensor& elemmat); +bool isDiagonal(const xt::xtensor& elemmat); } // namespace Element } // namespace GooseFEM #include "Element.hpp" #endif diff --git a/include/GooseFEM/Element.hpp b/include/GooseFEM/Element.hpp index 1c68cbb..fe4a63c 100644 --- a/include/GooseFEM/Element.hpp +++ b/include/GooseFEM/Element.hpp @@ -1,108 +1,108 @@ /* (c - GPLv3) T.W.J. de Geus (Tom) | tom@geus.me | www.geus.me | github.com/tdegeus/GooseFEM */ #ifndef GOOSEFEM_ELEMENT_HPP #define GOOSEFEM_ELEMENT_HPP #include "Element.h" namespace GooseFEM { namespace Element { -inline xt::xtensor -asElementVector(const xt::xtensor& conn, const xt::xtensor& nodevec) +inline xt::xtensor asElementVector( + const xt::xtensor& conn, const xt::xtensor& nodevec) { size_t nelem = conn.shape(0); size_t nne = conn.shape(1); size_t ndim = nodevec.shape(1); - xt::xtensor elemvec = xt::empty({nelem, nne, ndim}); + xt::xtensor elemvec = xt::empty({nelem, nne, ndim}); #pragma omp parallel for for (size_t e = 0; e < nelem; ++e) { for (size_t m = 0; m < nne; ++m) { for (size_t i = 0; i < ndim; ++i) { elemvec(e, m, i) = nodevec(conn(e, m), i); } } } return elemvec; } -inline xt::xtensor -assembleNodeVector(const xt::xtensor& conn, const xt::xtensor& elemvec) +inline xt::xtensor assembleNodeVector( + const xt::xtensor& conn, const xt::xtensor& elemvec) { size_t nelem = conn.shape(0); size_t nne = conn.shape(1); size_t ndim = elemvec.shape(2); size_t nnode = xt::amax(conn)[0] + 1; GOOSEFEM_ASSERT(elemvec.shape(0) == nelem); GOOSEFEM_ASSERT(elemvec.shape(1) == nne); - xt::xtensor nodevec = xt::zeros({nnode, ndim}); + xt::xtensor nodevec = xt::zeros({nnode, ndim}); for (size_t e = 0; e < nelem; ++e) { for (size_t m = 0; m < nne; ++m) { for (size_t i = 0; i < ndim; ++i) { nodevec(conn(e, m), i) += elemvec(e, m, i); } } } return nodevec; } template inline bool isSequential(const E& dofs) { size_t ndof = xt::amax(dofs)[0] + 1; - xt::xtensor exists = xt::zeros({ndof}); + xt::xtensor exists = xt::zeros({ndof}); for (auto& i : dofs) { exists[i]++; } for (auto& i : dofs) { if (exists[i] == 0) { return false; } } return true; } -inline bool isDiagonal(const xt::xtensor& elemmat) +inline bool isDiagonal(const xt::xtensor& elemmat) { GOOSEFEM_ASSERT(elemmat.shape(1) == elemmat.shape(2)); size_t nelem = elemmat.shape(0); size_t N = elemmat.shape(1); double eps = std::numeric_limits::epsilon(); #pragma omp parallel for for (size_t e = 0; e < nelem; ++e) { for (size_t i = 0; i < N; ++i) { for (size_t j = 0; j < N; ++j) { if (i != j) { if (std::abs(elemmat(e, i, j)) > eps) { return false; } } } } } return true; } } // namespace Element } // namespace GooseFEM #endif diff --git a/include/GooseFEM/ElementHex8.h b/include/GooseFEM/ElementHex8.h index 4d1d9d4..ea4132e 100644 --- a/include/GooseFEM/ElementHex8.h +++ b/include/GooseFEM/ElementHex8.h @@ -1,142 +1,131 @@ /* (c - GPLv3) T.W.J. de Geus (Tom) | tom@geus.me | www.geus.me | github.com/tdegeus/GooseFEM */ #ifndef GOOSEFEM_ELEMENTHEX8_H #define GOOSEFEM_ELEMENTHEX8_H #include "config.h" namespace GooseFEM { namespace Element { namespace Hex8 { -inline double inv(const xt::xtensor_fixed>& A, - xt::xtensor_fixed>& Ainv); +template +inline double inv(const T& A, T& Ainv); namespace Gauss { -inline size_t nip(); // number of integration points -inline xt::xtensor xi(); // integration point coordinates (local coordinates) -inline xt::xtensor w(); // integration point weights -} +inline size_t nip(); // number of integration points +inline xt::xtensor xi(); // integration point coordinates (local coordinates) +inline xt::xtensor w(); // integration point weights +} // namespace Gauss namespace Nodal { -inline size_t nip(); // number of integration points -inline xt::xtensor xi(); // integration point coordinates (local coordinates) -inline xt::xtensor w(); // integration point weights -} +inline size_t nip(); // number of integration points +inline xt::xtensor xi(); // integration point coordinates (local coordinates) +inline xt::xtensor w(); // integration point weights +} // namespace Nodal class Quadrature { public: // Fixed dimensions: // ndim = 3 - number of dimensions // nne = 8 - number of nodes per element // // Naming convention: // "elemmat" - matrices stored per element - [nelem, nne*ndim, nne*ndim] // "elemvec" - nodal vectors stored per element - [nelem, nne, ndim] // "qtensor" - integration point tensor - [nelem, nip, ndim, ndim] // "qscalar" - integration point scalar - [nelem, nip] // Constructor: integration point coordinates and weights are optional (default: Gauss) Quadrature() = default; - Quadrature(const xt::xtensor& x); + Quadrature(const xt::xtensor& x); Quadrature( - const xt::xtensor& x, - const xt::xtensor& xi, - const xt::xtensor& w); + const xt::xtensor& x, + const xt::xtensor& xi, + const xt::xtensor& w); // Update the nodal positions (shape of "x" should match the earlier definition) - void update_x(const xt::xtensor& x); + void update_x(const xt::xtensor& x); // Return dimensions size_t nelem() const; // number of elements size_t nne() const; // number of nodes per element size_t ndim() const; // number of dimension size_t nip() const; // number of integration points // Return shape function gradients - xt::xtensor GradN() const; + xt::xtensor GradN() const; // Return integration volume - void dV(xt::xtensor& qscalar) const; - void dV(xt::xtensor& qtensor) const; // same volume for all tensor components - void dV(xt::xarray& qtensor) const; // same volume for all tensor components + void dV(xt::xtensor& qscalar) const; + void dV(xt::xtensor& qtensor) const; // same volume for all tensor components + void dV(xt::xarray& qtensor) const; // same volume for all tensor components // Dyadic product (and its transpose and symmetric part) // qtensor(i,j) += dNdx(m,i) * elemvec(m,j) - void gradN_vector( - const xt::xtensor& elemvec, - xt::xtensor& qtensor) const; - - void gradN_vector_T( - const xt::xtensor& elemvec, - xt::xtensor& qtensor) const; - - void symGradN_vector( - const xt::xtensor& elemvec, - xt::xtensor& qtensor) const; + void gradN_vector(const xt::xtensor& elemvec, xt::xtensor& qtensor) const; + void gradN_vector_T(const xt::xtensor& elemvec, xt::xtensor& qtensor) const; + void symGradN_vector(const xt::xtensor& elemvec, xt::xtensor& qtensor) const; // Integral of the scalar product // elemmat(m*ndim+i,n*ndim+i) += N(m) * qscalar * N(n) * dV void int_N_scalar_NT_dV( - const xt::xtensor& qscalar, - xt::xtensor& elemmat) const; + const xt::xtensor& qscalar, xt::xtensor& elemmat) const; // Integral of the dot product // elemvec(m,j) += dNdx(m,i) * qtensor(i,j) * dV void int_gradN_dot_tensor2_dV( - const xt::xtensor& qtensor, - xt::xtensor& elemvec) const; + const xt::xtensor& qtensor, xt::xtensor& elemvec) const; // Integral of the dot product // elemmat(m*2+j, n*2+k) += dNdx(m,i) * qtensor(i,j,k,l) * dNdx(n,l) * dV void int_gradN_dot_tensor4_dot_gradNT_dV( - const xt::xtensor& qtensor, - xt::xtensor& elemmat) const; + const xt::xtensor& qtensor, xt::xtensor& elemmat) const; // Auto-allocation of the functions above - xt::xtensor DV() const; + xt::xtensor DV() const; xt::xarray DV(size_t rank) const; - xt::xtensor GradN_vector(const xt::xtensor& elemvec) const; - xt::xtensor GradN_vector_T(const xt::xtensor& elemvec) const; - xt::xtensor SymGradN_vector(const xt::xtensor& elemvec) const; - xt::xtensor Int_N_scalar_NT_dV(const xt::xtensor& qscalar) const; - xt::xtensor Int_gradN_dot_tensor2_dV(const xt::xtensor& qtensor) const; - xt::xtensor Int_gradN_dot_tensor4_dot_gradNT_dV( - const xt::xtensor& qtensor) const; + xt::xtensor GradN_vector(const xt::xtensor& elemvec) const; + xt::xtensor GradN_vector_T(const xt::xtensor& elemvec) const; + xt::xtensor SymGradN_vector(const xt::xtensor& elemvec) const; + xt::xtensor Int_N_scalar_NT_dV(const xt::xtensor& qscalar) const; + xt::xtensor Int_gradN_dot_tensor2_dV(const xt::xtensor& qtensor) const; + xt::xtensor Int_gradN_dot_tensor4_dot_gradNT_dV( + const xt::xtensor& qtensor) const; private: // Compute "vol" and "dNdx" based on current "x" void compute_dN(); private: // Dimensions (flexible) size_t m_nelem; // number of elements size_t m_nip; // number of integration points // Dimensions (fixed for this element type) static const size_t m_nne = 8; // number of nodes per element static const size_t m_ndim = 3; // number of dimensions // Data arrays - xt::xtensor m_x; // nodal positions stored per element [nelem, nne, ndim] - xt::xtensor m_w; // weight of each integration point [nip] - xt::xtensor m_xi; // local coordinate of each integration point [nip, ndim] - xt::xtensor m_N; // shape functions [nip, nne] - xt::xtensor m_dNxi; // shape function grad. wrt local coor. [nip, nne, ndim] - xt::xtensor m_dNx; // shape function grad. wrt global coor. [nelem, nip, nne, ndim] - xt::xtensor m_vol; // integration point volume [nelem, nip] + xt::xtensor m_x; // nodal positions stored per element [nelem, nne, ndim] + xt::xtensor m_w; // weight of each integration point [nip] + xt::xtensor m_xi; // local coordinate of each integration point [nip, ndim] + xt::xtensor m_N; // shape functions [nip, nne] + xt::xtensor m_dNxi; // shape function grad. wrt local coor. [nip, nne, ndim] + xt::xtensor m_dNx; // shape function grad. wrt global coor. [nelem, nip, nne, ndim] + xt::xtensor m_vol; // integration point volume [nelem, nip] }; } // namespace Hex8 } // namespace Element } // namespace GooseFEM #include "ElementHex8.hpp" #endif diff --git a/include/GooseFEM/ElementHex8.hpp b/include/GooseFEM/ElementHex8.hpp index d01c483..83c9240 100644 --- a/include/GooseFEM/ElementHex8.hpp +++ b/include/GooseFEM/ElementHex8.hpp @@ -1,655 +1,649 @@ /* (c - GPLv3) T.W.J. de Geus (Tom) | tom@geus.me | www.geus.me | github.com/tdegeus/GooseFEM */ #ifndef GOOSEFEM_ELEMENTHEX8_HPP #define GOOSEFEM_ELEMENTHEX8_HPP #include "ElementHex8.h" namespace GooseFEM { namespace Element { namespace Hex8 { -inline double inv(const xt::xtensor_fixed>& A, - xt::xtensor_fixed>& Ainv) +template +inline double inv(const T& A, T& Ainv) { double det = (A(0, 0) * A(1, 1) * A(2, 2) + A(0, 1) * A(1, 2) * A(2, 0) + A(0, 2) * A(1, 0) * A(2, 1)) - (A(0, 2) * A(1, 1) * A(2, 0) + A(0, 1) * A(1, 0) * A(2, 2) + A(0, 0) * A(1, 2) * A(2, 1)); Ainv(0, 0) = (A(1, 1) * A(2, 2) - A(1, 2) * A(2, 1)) / det; Ainv(0, 1) = (A(0, 2) * A(2, 1) - A(0, 1) * A(2, 2)) / det; Ainv(0, 2) = (A(0, 1) * A(1, 2) - A(0, 2) * A(1, 1)) / det; Ainv(1, 0) = (A(1, 2) * A(2, 0) - A(1, 0) * A(2, 2)) / det; Ainv(1, 1) = (A(0, 0) * A(2, 2) - A(0, 2) * A(2, 0)) / det; Ainv(1, 2) = (A(0, 2) * A(1, 0) - A(0, 0) * A(1, 2)) / det; Ainv(2, 0) = (A(1, 0) * A(2, 1) - A(1, 1) * A(2, 0)) / det; Ainv(2, 1) = (A(0, 1) * A(2, 0) - A(0, 0) * A(2, 1)) / det; Ainv(2, 2) = (A(0, 0) * A(1, 1) - A(0, 1) * A(1, 0)) / det; return det; } namespace Gauss { inline size_t nip() { return 8; } -inline xt::xtensor xi() +inline xt::xtensor xi() { size_t nip = 8; size_t ndim = 3; - xt::xtensor xi = xt::empty({nip, ndim}); + xt::xtensor xi = xt::empty({nip, ndim}); xi(0, 0) = -1.0 / std::sqrt(3.0); xi(0, 1) = -1.0 / std::sqrt(3.0); xi(0, 2) = -1.0 / std::sqrt(3.0); xi(1, 0) = +1.0 / std::sqrt(3.0); xi(1, 1) = -1.0 / std::sqrt(3.0); xi(1, 2) = -1.0 / std::sqrt(3.0); xi(2, 0) = +1.0 / std::sqrt(3.0); xi(2, 1) = +1.0 / std::sqrt(3.0); xi(2, 2) = -1.0 / std::sqrt(3.0); xi(3, 0) = -1.0 / std::sqrt(3.0); xi(3, 1) = +1.0 / std::sqrt(3.0); xi(3, 2) = -1.0 / std::sqrt(3.0); xi(4, 0) = -1.0 / std::sqrt(3.0); xi(4, 1) = -1.0 / std::sqrt(3.0); xi(4, 2) = +1.0 / std::sqrt(3.0); xi(5, 0) = +1.0 / std::sqrt(3.0); xi(5, 1) = -1.0 / std::sqrt(3.0); xi(5, 2) = +1.0 / std::sqrt(3.0); xi(6, 0) = +1.0 / std::sqrt(3.0); xi(6, 1) = +1.0 / std::sqrt(3.0); xi(6, 2) = +1.0 / std::sqrt(3.0); xi(7, 0) = -1.0 / std::sqrt(3.0); xi(7, 1) = +1.0 / std::sqrt(3.0); xi(7, 2) = +1.0 / std::sqrt(3.0); return xi; } -inline xt::xtensor w() +inline xt::xtensor w() { size_t nip = 8; - xt::xtensor w = xt::empty({nip}); + xt::xtensor w = xt::empty({nip}); w(0) = 1.0; w(1) = 1.0; w(2) = 1.0; w(3) = 1.0; w(4) = 1.0; w(5) = 1.0; w(6) = 1.0; w(7) = 1.0; return w; } } // namespace Gauss namespace Nodal { inline size_t nip() { return 8; } -inline xt::xtensor xi() +inline xt::xtensor xi() { size_t nip = 8; size_t ndim = 3; - xt::xtensor xi = xt::empty({nip, ndim}); + xt::xtensor xi = xt::empty({nip, ndim}); xi(0, 0) = -1.0; xi(0, 1) = -1.0; xi(0, 2) = -1.0; xi(1, 0) = +1.0; xi(1, 1) = -1.0; xi(1, 2) = -1.0; xi(2, 0) = +1.0; xi(2, 1) = +1.0; xi(2, 2) = -1.0; xi(3, 0) = -1.0; xi(3, 1) = +1.0; xi(3, 2) = -1.0; xi(4, 0) = -1.0; xi(4, 1) = -1.0; xi(4, 2) = +1.0; xi(5, 0) = +1.0; xi(5, 1) = -1.0; xi(5, 2) = +1.0; xi(6, 0) = +1.0; xi(6, 1) = +1.0; xi(6, 2) = +1.0; xi(7, 0) = -1.0; xi(7, 1) = +1.0; xi(7, 2) = +1.0; return xi; } -inline xt::xtensor w() +inline xt::xtensor w() { size_t nip = 8; - xt::xtensor w = xt::empty({nip}); + xt::xtensor w = xt::empty({nip}); w(0) = 1.0; w(1) = 1.0; w(2) = 1.0; w(3) = 1.0; w(4) = 1.0; w(5) = 1.0; w(6) = 1.0; w(7) = 1.0; return w; } } // namespace Nodal -inline Quadrature::Quadrature(const xt::xtensor& x) +inline Quadrature::Quadrature(const xt::xtensor& x) : Quadrature(x, Gauss::xi(), Gauss::w()) { } inline Quadrature::Quadrature( - const xt::xtensor& x, - const xt::xtensor& xi, - const xt::xtensor& w) + const xt::xtensor& x, + const xt::xtensor& xi, + const xt::xtensor& w) : m_x(x), m_w(w), m_xi(xi) { GOOSEFEM_ASSERT(m_x.shape(1) == m_nne); GOOSEFEM_ASSERT(m_x.shape(2) == m_ndim); m_nelem = m_x.shape(0); m_nip = m_w.size(); GOOSEFEM_ASSERT(m_xi.shape(0) == m_nip); GOOSEFEM_ASSERT(m_xi.shape(1) == m_ndim); GOOSEFEM_ASSERT(m_w.size() == m_nip); m_N = xt::empty({m_nip, m_nne}); m_dNxi = xt::empty({m_nip, m_nne, m_ndim}); m_dNx = xt::empty({m_nelem, m_nip, m_nne, m_ndim}); m_vol = xt::empty({m_nelem, m_nip}); // shape functions for (size_t q = 0; q < m_nip; ++q) { m_N(q, 0) = 0.125 * (1.0 - m_xi(q, 0)) * (1.0 - m_xi(q, 1)) * (1.0 - m_xi(q, 2)); m_N(q, 1) = 0.125 * (1.0 + m_xi(q, 0)) * (1.0 - m_xi(q, 1)) * (1.0 - m_xi(q, 2)); m_N(q, 2) = 0.125 * (1.0 + m_xi(q, 0)) * (1.0 + m_xi(q, 1)) * (1.0 - m_xi(q, 2)); m_N(q, 3) = 0.125 * (1.0 - m_xi(q, 0)) * (1.0 + m_xi(q, 1)) * (1.0 - m_xi(q, 2)); m_N(q, 4) = 0.125 * (1.0 - m_xi(q, 0)) * (1.0 - m_xi(q, 1)) * (1.0 + m_xi(q, 2)); m_N(q, 5) = 0.125 * (1.0 + m_xi(q, 0)) * (1.0 - m_xi(q, 1)) * (1.0 + m_xi(q, 2)); m_N(q, 6) = 0.125 * (1.0 + m_xi(q, 0)) * (1.0 + m_xi(q, 1)) * (1.0 + m_xi(q, 2)); m_N(q, 7) = 0.125 * (1.0 - m_xi(q, 0)) * (1.0 + m_xi(q, 1)) * (1.0 + m_xi(q, 2)); } // shape function gradients in local coordinates for (size_t q = 0; q < m_nip; ++q) { // - dN / dxi_0 m_dNxi(q, 0, 0) = -0.125 * (1.0 - m_xi(q, 1)) * (1.0 - m_xi(q, 2)); m_dNxi(q, 1, 0) = +0.125 * (1.0 - m_xi(q, 1)) * (1.0 - m_xi(q, 2)); m_dNxi(q, 2, 0) = +0.125 * (1.0 + m_xi(q, 1)) * (1.0 - m_xi(q, 2)); m_dNxi(q, 3, 0) = -0.125 * (1.0 + m_xi(q, 1)) * (1.0 - m_xi(q, 2)); m_dNxi(q, 4, 0) = -0.125 * (1.0 - m_xi(q, 1)) * (1.0 + m_xi(q, 2)); m_dNxi(q, 5, 0) = +0.125 * (1.0 - m_xi(q, 1)) * (1.0 + m_xi(q, 2)); m_dNxi(q, 6, 0) = +0.125 * (1.0 + m_xi(q, 1)) * (1.0 + m_xi(q, 2)); m_dNxi(q, 7, 0) = -0.125 * (1.0 + m_xi(q, 1)) * (1.0 + m_xi(q, 2)); // - dN / dxi_1 m_dNxi(q, 0, 1) = -0.125 * (1.0 - m_xi(q, 0)) * (1.0 - m_xi(q, 2)); m_dNxi(q, 1, 1) = -0.125 * (1.0 + m_xi(q, 0)) * (1.0 - m_xi(q, 2)); m_dNxi(q, 2, 1) = +0.125 * (1.0 + m_xi(q, 0)) * (1.0 - m_xi(q, 2)); m_dNxi(q, 3, 1) = +0.125 * (1.0 - m_xi(q, 0)) * (1.0 - m_xi(q, 2)); m_dNxi(q, 4, 1) = -0.125 * (1.0 - m_xi(q, 0)) * (1.0 + m_xi(q, 2)); m_dNxi(q, 5, 1) = -0.125 * (1.0 + m_xi(q, 0)) * (1.0 + m_xi(q, 2)); m_dNxi(q, 6, 1) = +0.125 * (1.0 + m_xi(q, 0)) * (1.0 + m_xi(q, 2)); m_dNxi(q, 7, 1) = +0.125 * (1.0 - m_xi(q, 0)) * (1.0 + m_xi(q, 2)); // - dN / dxi_2 m_dNxi(q, 0, 2) = -0.125 * (1.0 - m_xi(q, 0)) * (1.0 - m_xi(q, 1)); m_dNxi(q, 1, 2) = -0.125 * (1.0 + m_xi(q, 0)) * (1.0 - m_xi(q, 1)); m_dNxi(q, 2, 2) = -0.125 * (1.0 + m_xi(q, 0)) * (1.0 + m_xi(q, 1)); m_dNxi(q, 3, 2) = -0.125 * (1.0 - m_xi(q, 0)) * (1.0 + m_xi(q, 1)); m_dNxi(q, 4, 2) = +0.125 * (1.0 - m_xi(q, 0)) * (1.0 - m_xi(q, 1)); m_dNxi(q, 5, 2) = +0.125 * (1.0 + m_xi(q, 0)) * (1.0 - m_xi(q, 1)); m_dNxi(q, 6, 2) = +0.125 * (1.0 + m_xi(q, 0)) * (1.0 + m_xi(q, 1)); m_dNxi(q, 7, 2) = +0.125 * (1.0 - m_xi(q, 0)) * (1.0 + m_xi(q, 1)); } // compute the shape function gradients, based on "x" compute_dN(); } inline size_t Quadrature::nelem() const { return m_nelem; } inline size_t Quadrature::nne() const { return m_nne; } inline size_t Quadrature::ndim() const { return m_ndim; } inline size_t Quadrature::nip() const { return m_nip; } -inline xt::xtensor Quadrature::GradN() const +inline xt::xtensor Quadrature::GradN() const { return m_dNx; } -inline void Quadrature::dV(xt::xtensor& qscalar) const +inline void Quadrature::dV(xt::xtensor& qscalar) const { GOOSEFEM_ASSERT( qscalar.shape() == std::decay_t::shape_type({m_nelem, m_nip})); #pragma omp parallel for for (size_t e = 0; e < m_nelem; ++e) { for (size_t q = 0; q < m_nip; ++q) { qscalar(e, q) = m_vol(e, q); } } } -inline void Quadrature::dV(xt::xtensor& qtensor) const +inline void Quadrature::dV(xt::xtensor& qtensor) const { GOOSEFEM_ASSERT( qtensor.shape() == std::decay_t::shape_type({m_nelem, m_nip, m_ndim, m_ndim})); #pragma omp parallel for for (size_t e = 0; e < m_nelem; ++e) { for (size_t q = 0; q < m_nip; ++q) { for (size_t i = 0; i < m_ndim; ++i) { for (size_t j = 0; j < m_ndim; ++j) { qtensor(e, q, i, j) = m_vol(e, q); } } } } } inline void Quadrature::dV(xt::xarray& qtensor) const { GOOSEFEM_ASSERT(qtensor.shape(0) == m_nelem); GOOSEFEM_ASSERT(qtensor.shape(1) == m_nip); xt::dynamic_shape strides = {static_cast(m_vol.strides()[0]), static_cast(m_vol.strides()[1])}; for (size_t i = 2; i < qtensor.shape().size(); ++i) { strides.push_back(0); } qtensor = xt::strided_view(m_vol, qtensor.shape(), std::move(strides), 0ul, xt::layout_type::dynamic); } -inline void Quadrature::update_x(const xt::xtensor& x) +inline void Quadrature::update_x(const xt::xtensor& x) { GOOSEFEM_ASSERT(x.shape() == m_x.shape()); xt::noalias(m_x) = x; compute_dN(); } inline void Quadrature::compute_dN() { #pragma omp parallel { xt::xtensor_fixed> J, Jinv; #pragma omp for for (size_t e = 0; e < m_nelem; ++e) { auto x = xt::adapt(&m_x(e, 0, 0), xt::xshape()); for (size_t q = 0; q < m_nip; ++q) { auto dNxi = xt::adapt(&m_dNxi(q, 0, 0), xt::xshape()); auto dNx = xt::adapt(&m_dNx(e, q, 0, 0), xt::xshape()); J.fill(0.0); for (size_t m = 0; m < m_nne; ++m) { for (size_t i = 0; i < m_ndim; ++i) { for (size_t j = 0; j < m_ndim; ++j) { J(i, j) += dNxi(m, i) * x(m, j); } } } double Jdet = inv(J, Jinv); // dNx(m,i) += Jinv(i,j) * dNxi(m,j); for (size_t m = 0; m < m_nne; ++m) { - dNx(m, 0) - = Jinv(0, 0) * dNxi(m, 0) - + Jinv(0, 1) * dNxi(m, 1) - + Jinv(0, 2) * dNxi(m, 2); - dNx(m, 1) - = Jinv(1, 0) * dNxi(m, 0) - + Jinv(1, 1) * dNxi(m, 1) - + Jinv(1, 2) * dNxi(m, 2); - dNx(m, 2) - = Jinv(2, 0) * dNxi(m, 0) - + Jinv(2, 1) * dNxi(m, 1) - + Jinv(2, 2) * dNxi(m, 2); + dNx(m, 0) = + Jinv(0, 0) * dNxi(m, 0) + Jinv(0, 1) * dNxi(m, 1) + Jinv(0, 2) * dNxi(m, 2); + dNx(m, 1) = + Jinv(1, 0) * dNxi(m, 0) + Jinv(1, 1) * dNxi(m, 1) + Jinv(1, 2) * dNxi(m, 2); + dNx(m, 2) = + Jinv(2, 0) * dNxi(m, 0) + Jinv(2, 1) * dNxi(m, 1) + Jinv(2, 2) * dNxi(m, 2); } m_vol(e, q) = m_w(q) * Jdet; } } } } inline void Quadrature::gradN_vector( - const xt::xtensor& elemvec, xt::xtensor& qtensor) const + const xt::xtensor& elemvec, xt::xtensor& qtensor) const { GOOSEFEM_ASSERT( elemvec.shape() == std::decay_t::shape_type({m_nelem, m_nne, m_ndim})); GOOSEFEM_ASSERT( qtensor.shape() == std::decay_t::shape_type({m_nelem, m_nip, m_ndim, m_ndim})); qtensor.fill(0.0); #pragma omp parallel for for (size_t e = 0; e < m_nelem; ++e) { auto u = xt::adapt(&elemvec(e, 0, 0), xt::xshape()); for (size_t q = 0; q < m_nip; ++q) { auto dNx = xt::adapt(&m_dNx(e, q, 0, 0), xt::xshape()); auto gradu = xt::adapt(&qtensor(e, q, 0, 0), xt::xshape()); for (size_t m = 0; m < m_nne; ++m) { for (size_t i = 0; i < m_ndim; ++i) { for (size_t j = 0; j < m_ndim; ++j) { gradu(i, j) += dNx(m, i) * u(m, j); } } } } } } inline void Quadrature::gradN_vector_T( - const xt::xtensor& elemvec, xt::xtensor& qtensor) const + const xt::xtensor& elemvec, xt::xtensor& qtensor) const { GOOSEFEM_ASSERT( elemvec.shape() == std::decay_t::shape_type({m_nelem, m_nne, m_ndim})); GOOSEFEM_ASSERT( qtensor.shape() == std::decay_t::shape_type({m_nelem, m_nip, m_ndim, m_ndim})); qtensor.fill(0.0); #pragma omp parallel for for (size_t e = 0; e < m_nelem; ++e) { auto u = xt::adapt(&elemvec(e, 0, 0), xt::xshape()); for (size_t q = 0; q < m_nip; ++q) { auto dNx = xt::adapt(&m_dNx(e, q, 0, 0), xt::xshape()); auto gradu = xt::adapt(&qtensor(e, q, 0, 0), xt::xshape()); for (size_t m = 0; m < m_nne; ++m) { for (size_t i = 0; i < m_ndim; ++i) { for (size_t j = 0; j < m_ndim; ++j) { gradu(j, i) += dNx(m, i) * u(m, j); } } } } } } inline void Quadrature::symGradN_vector( - const xt::xtensor& elemvec, xt::xtensor& qtensor) const + const xt::xtensor& elemvec, xt::xtensor& qtensor) const { GOOSEFEM_ASSERT( elemvec.shape() == std::decay_t::shape_type({m_nelem, m_nne, m_ndim})); GOOSEFEM_ASSERT( qtensor.shape() == std::decay_t::shape_type({m_nelem, m_nip, m_ndim, m_ndim})); qtensor.fill(0.0); #pragma omp parallel for for (size_t e = 0; e < m_nelem; ++e) { auto u = xt::adapt(&elemvec(e, 0, 0), xt::xshape()); for (size_t q = 0; q < m_nip; ++q) { auto dNx = xt::adapt(&m_dNx(e, q, 0, 0), xt::xshape()); auto eps = xt::adapt(&qtensor(e, q, 0, 0), xt::xshape()); for (size_t m = 0; m < m_nne; ++m) { for (size_t i = 0; i < m_ndim; ++i) { for (size_t j = 0; j < m_ndim; ++j) { eps(i, j) += 0.5 * dNx(m, i) * u(m, j); eps(j, i) += 0.5 * dNx(m, i) * u(m, j); } } } } } } inline void Quadrature::int_N_scalar_NT_dV( - const xt::xtensor& qscalar, xt::xtensor& elemmat) const + const xt::xtensor& qscalar, xt::xtensor& elemmat) const { GOOSEFEM_ASSERT( qscalar.shape() == std::decay_t::shape_type({m_nelem, m_nip})); GOOSEFEM_ASSERT( elemmat.shape() == std::decay_t::shape_type({m_nelem, m_nne * m_ndim, m_nne * m_ndim})); elemmat.fill(0.0); #pragma omp parallel for for (size_t e = 0; e < m_nelem; ++e) { auto M = xt::adapt(&elemmat(e, 0, 0), xt::xshape()); for (size_t q = 0; q < m_nip; ++q) { auto N = xt::adapt(&m_N(q, 0), xt::xshape()); auto& vol = m_vol(e, q); auto& rho = qscalar(e, q); // M(m * ndim + i, n * ndim + i) += N(m) * scalar * N(n) * dV for (size_t m = 0; m < m_nne; ++m) { for (size_t n = 0; n < m_nne; ++n) { M(m * m_ndim + 0, n * m_ndim + 0) += N(m) * rho * N(n) * vol; M(m * m_ndim + 1, n * m_ndim + 1) += N(m) * rho * N(n) * vol; M(m * m_ndim + 2, n * m_ndim + 2) += N(m) * rho * N(n) * vol; } } } } } inline void Quadrature::int_gradN_dot_tensor2_dV( - const xt::xtensor& qtensor, xt::xtensor& elemvec) const + const xt::xtensor& qtensor, xt::xtensor& elemvec) const { GOOSEFEM_ASSERT( qtensor.shape() == std::decay_t::shape_type({m_nelem, m_nip, m_ndim, m_ndim})); GOOSEFEM_ASSERT( elemvec.shape() == std::decay_t::shape_type({m_nelem, m_nne, m_ndim})); elemvec.fill(0.0); #pragma omp parallel for for (size_t e = 0; e < m_nelem; ++e) { auto f = xt::adapt(&elemvec(e, 0, 0), xt::xshape()); for (size_t q = 0; q < m_nip; ++q) { auto dNx = xt::adapt(&m_dNx(e, q, 0, 0), xt::xshape()); auto sig = xt::adapt(&qtensor(e, q, 0, 0), xt::xshape()); auto& vol = m_vol(e, q); for (size_t m = 0; m < m_nne; ++m) { f(m, 0) += (dNx(m, 0) * sig(0, 0) + dNx(m, 1) * sig(1, 0) + dNx(m, 2) * sig(2, 0)) * vol; f(m, 1) += (dNx(m, 0) * sig(0, 1) + dNx(m, 1) * sig(1, 1) + dNx(m, 2) * sig(2, 1)) * vol; f(m, 2) += (dNx(m, 0) * sig(0, 2) + dNx(m, 1) * sig(1, 2) + dNx(m, 2) * sig(2, 2)) * vol; } } } } inline void Quadrature::int_gradN_dot_tensor4_dot_gradNT_dV( - const xt::xtensor& qtensor, xt::xtensor& elemmat) const + const xt::xtensor& qtensor, xt::xtensor& elemmat) const { GOOSEFEM_ASSERT( qtensor.shape() == std::decay_t::shape_type( {m_nelem, m_nip, m_ndim, m_ndim, m_ndim, m_ndim})); GOOSEFEM_ASSERT( elemmat.shape() == std::decay_t::shape_type({m_nelem, m_nne * m_ndim, m_nne * m_ndim})); elemmat.fill(0.0); #pragma omp parallel for for (size_t e = 0; e < m_nelem; ++e) { auto K = xt::adapt(&elemmat(e, 0, 0), xt::xshape()); for (size_t q = 0; q < m_nip; ++q) { - auto dNx = xt::adapt(&m_dNx(e,q,0,0), xt::xshape()); - auto C = xt::adapt(&qtensor(e,q,0,0,0,0), xt::xshape()); + auto dNx = xt::adapt(&m_dNx(e, q, 0, 0), xt::xshape()); + auto C = xt::adapt(&qtensor(e, q, 0, 0, 0, 0), xt::xshape()); auto& vol = m_vol(e, q); for (size_t m = 0; m < m_nne; ++m) { for (size_t n = 0; n < m_nne; ++n) { for (size_t i = 0; i < m_ndim; ++i) { for (size_t j = 0; j < m_ndim; ++j) { for (size_t k = 0; k < m_ndim; ++k) { for (size_t l = 0; l < m_ndim; ++l) { K(m * m_ndim + j, n * m_ndim + k) += dNx(m, i) * C(i, j, k, l) * dNx(n, l) * vol; } } } } } } } } } -inline xt::xtensor Quadrature::DV() const +inline xt::xtensor Quadrature::DV() const { - xt::xtensor out = xt::empty({m_nelem, m_nip}); + xt::xtensor out = xt::empty({m_nelem, m_nip}); this->dV(out); return out; } inline xt::xarray Quadrature::DV(size_t rank) const { std::vector shape = {m_nelem, m_nip}; for (size_t i = 0; i < rank; ++i) { shape.push_back(static_cast(m_ndim)); } xt::xarray out = xt::empty(shape); this->dV(out); return out; } -inline xt::xtensor Quadrature::GradN_vector(const xt::xtensor& elemvec) const +inline xt::xtensor Quadrature::GradN_vector(const xt::xtensor& elemvec) const { - xt::xtensor qtensor = xt::empty({m_nelem, m_nip, m_ndim, m_ndim}); + xt::xtensor qtensor = xt::empty({m_nelem, m_nip, m_ndim, m_ndim}); this->gradN_vector(elemvec, qtensor); return qtensor; } -inline xt::xtensor -Quadrature::GradN_vector_T(const xt::xtensor& elemvec) const +inline xt::xtensor +Quadrature::GradN_vector_T(const xt::xtensor& elemvec) const { - xt::xtensor qtensor = xt::empty({m_nelem, m_nip, m_ndim, m_ndim}); + xt::xtensor qtensor = xt::empty({m_nelem, m_nip, m_ndim, m_ndim}); this->gradN_vector_T(elemvec, qtensor); return qtensor; } -inline xt::xtensor -Quadrature::SymGradN_vector(const xt::xtensor& elemvec) const +inline xt::xtensor +Quadrature::SymGradN_vector(const xt::xtensor& elemvec) const { - xt::xtensor qtensor = xt::empty({m_nelem, m_nip, m_ndim, m_ndim}); + xt::xtensor qtensor = xt::empty({m_nelem, m_nip, m_ndim, m_ndim}); this->symGradN_vector(elemvec, qtensor); return qtensor; } -inline xt::xtensor -Quadrature::Int_N_scalar_NT_dV(const xt::xtensor& qscalar) const +inline xt::xtensor +Quadrature::Int_N_scalar_NT_dV(const xt::xtensor& qscalar) const { - xt::xtensor elemmat = xt::empty({m_nelem, m_nne * m_ndim, m_nne * m_ndim}); + xt::xtensor elemmat = xt::empty({m_nelem, m_nne * m_ndim, m_nne * m_ndim}); this->int_N_scalar_NT_dV(qscalar, elemmat); return elemmat; } -inline xt::xtensor -Quadrature::Int_gradN_dot_tensor2_dV(const xt::xtensor& qtensor) const +inline xt::xtensor +Quadrature::Int_gradN_dot_tensor2_dV(const xt::xtensor& qtensor) const { - xt::xtensor elemvec = xt::empty({m_nelem, m_nne, m_ndim}); + xt::xtensor elemvec = xt::empty({m_nelem, m_nne, m_ndim}); this->int_gradN_dot_tensor2_dV(qtensor, elemvec); return elemvec; } -inline xt::xtensor -Quadrature::Int_gradN_dot_tensor4_dot_gradNT_dV(const xt::xtensor& qtensor) const +inline xt::xtensor +Quadrature::Int_gradN_dot_tensor4_dot_gradNT_dV(const xt::xtensor& qtensor) const { - xt::xtensor elemmat = xt::empty({m_nelem, m_ndim * m_nne, m_ndim * m_nne}); + xt::xtensor elemmat = xt::empty({m_nelem, m_ndim * m_nne, m_ndim * m_nne}); this->int_gradN_dot_tensor4_dot_gradNT_dV(qtensor, elemmat); return elemmat; } } // namespace Hex8 } // namespace Element } // namespace GooseFEM #endif diff --git a/include/GooseFEM/ElementQuad4.h b/include/GooseFEM/ElementQuad4.h index bc7928a..3e7fe0c 100644 --- a/include/GooseFEM/ElementQuad4.h +++ b/include/GooseFEM/ElementQuad4.h @@ -1,148 +1,137 @@ /* (c - GPLv3) T.W.J. de Geus (Tom) | tom@geus.me | www.geus.me | github.com/tdegeus/GooseFEM */ #ifndef GOOSEFEM_ELEMENTQUAD4_H #define GOOSEFEM_ELEMENTQUAD4_H #include "config.h" namespace GooseFEM { namespace Element { namespace Quad4 { -inline double inv(const xt::xtensor_fixed>& A, - xt::xtensor_fixed>& Ainv); +template +inline double inv(const T& A, T& Ainv); namespace Gauss { -inline size_t nip(); // number of integration points -inline xt::xtensor xi(); // integration point coordinates (local coordinates) -inline xt::xtensor w(); // integration point weights -} +inline size_t nip(); // number of integration points +inline xt::xtensor xi(); // integration point coordinates (local coordinates) +inline xt::xtensor w(); // integration point weights +} // namespace Gauss namespace Nodal { -inline size_t nip(); // number of integration points -inline xt::xtensor xi(); // integration point coordinates (local coordinates) -inline xt::xtensor w(); // integration point weights -} +inline size_t nip(); // number of integration points +inline xt::xtensor xi(); // integration point coordinates (local coordinates) +inline xt::xtensor w(); // integration point weights +} // namespace Nodal namespace MidPoint { -inline size_t nip(); // number of integration points -inline xt::xtensor xi(); // integration point coordinates (local coordinates) -inline xt::xtensor w(); // integration point weights -} +inline size_t nip(); // number of integration points +inline xt::xtensor xi(); // integration point coordinates (local coordinates) +inline xt::xtensor w(); // integration point weights +} // namespace MidPoint class Quadrature { public: // Fixed dimensions: // ndim = 2 - number of dimensions // nne = 4 - number of nodes per element // // Naming convention: // "elemmat" - matrices stored per element - [nelem, nne*ndim, nne*ndim] // "elemvec" - nodal vectors stored per element - [nelem, nne, ndim] // "qtensor" - integration point tensor - [nelem, nip, ndim, ndim] // "qscalar" - integration point scalar - [nelem, nip] // Constructor: integration point coordinates and weights are optional (default: Gauss) Quadrature() = default; - Quadrature(const xt::xtensor& x); + Quadrature(const xt::xtensor& x); Quadrature( - const xt::xtensor& x, - const xt::xtensor& xi, - const xt::xtensor& w); + const xt::xtensor& x, + const xt::xtensor& xi, + const xt::xtensor& w); // Update the nodal positions (shape of "x" should match the earlier definition) - void update_x(const xt::xtensor& x); + void update_x(const xt::xtensor& x); // Return dimensions size_t nelem() const; // number of elements size_t nne() const; // number of nodes per element size_t ndim() const; // number of dimension size_t nip() const; // number of integration points // Return shape function gradients - xt::xtensor GradN() const; + xt::xtensor GradN() const; // Return integration volume - void dV(xt::xtensor& qscalar) const; - void dV(xt::xtensor& qtensor) const; // same volume for all tensor components - void dV(xt::xarray& qtensor) const; // same volume for all tensor components + void dV(xt::xtensor& qscalar) const; + void dV(xt::xtensor& qtensor) const; // same volume for all tensor components + void dV(xt::xarray& qtensor) const; // same volume for all tensor components // Dyadic product (and its transpose and symmetric part) // qtensor(i,j) += dNdx(m,i) * elemvec(m,j) - void gradN_vector( - const xt::xtensor& elemvec, - xt::xtensor& qtensor) const; - - void gradN_vector_T( - const xt::xtensor& elemvec, - xt::xtensor& qtensor) const; - - void symGradN_vector( - const xt::xtensor& elemvec, - xt::xtensor& qtensor) const; + void gradN_vector(const xt::xtensor& elemvec, xt::xtensor& qtensor) const; + void gradN_vector_T(const xt::xtensor& elemvec, xt::xtensor& qtensor) const; + void symGradN_vector(const xt::xtensor& elemvec, xt::xtensor& qtensor) const; // Integral of the scalar product // elemmat(m*ndim+i,n*ndim+i) += N(m) * qscalar * N(n) * dV void int_N_scalar_NT_dV( - const xt::xtensor& qscalar, - xt::xtensor& elemmat) const; + const xt::xtensor& qscalar, xt::xtensor& elemmat) const; // Integral of the dot product // elemvec(m,j) += dNdx(m,i) * qtensor(i,j) * dV void int_gradN_dot_tensor2_dV( - const xt::xtensor& qtensor, - xt::xtensor& elemvec) const; + const xt::xtensor& qtensor, xt::xtensor& elemvec) const; // Integral of the dot product // elemmat(m*2+j, n*2+k) += dNdx(m,i) * qtensor(i,j,k,l) * dNdx(n,l) * dV void int_gradN_dot_tensor4_dot_gradNT_dV( - const xt::xtensor& qtensor, - xt::xtensor& elemmat) const; + const xt::xtensor& qtensor, xt::xtensor& elemmat) const; // Auto-allocation of the functions above - xt::xtensor DV() const; + xt::xtensor DV() const; xt::xarray DV(size_t rank) const; - xt::xtensor GradN_vector(const xt::xtensor& elemvec) const; - xt::xtensor GradN_vector_T(const xt::xtensor& elemvec) const; - xt::xtensor SymGradN_vector(const xt::xtensor& elemvec) const; - xt::xtensor Int_N_scalar_NT_dV(const xt::xtensor& qscalar) const; - xt::xtensor Int_gradN_dot_tensor2_dV(const xt::xtensor& qtensor) const; - xt::xtensor Int_gradN_dot_tensor4_dot_gradNT_dV( - const xt::xtensor& qtensor) const; + xt::xtensor GradN_vector(const xt::xtensor& elemvec) const; + xt::xtensor GradN_vector_T(const xt::xtensor& elemvec) const; + xt::xtensor SymGradN_vector(const xt::xtensor& elemvec) const; + xt::xtensor Int_N_scalar_NT_dV(const xt::xtensor& qscalar) const; + xt::xtensor Int_gradN_dot_tensor2_dV(const xt::xtensor& qtensor) const; + xt::xtensor Int_gradN_dot_tensor4_dot_gradNT_dV( + const xt::xtensor& qtensor) const; private: // Compute "vol" and "dNdx" based on current "x" void compute_dN(); private: // Dimensions (flexible) size_t m_nelem; // number of elements size_t m_nip; // number of integration points // Dimensions (fixed for this element type) static const size_t m_nne = 4; // number of nodes per element static const size_t m_ndim = 2; // number of dimensions // Data arrays - xt::xtensor m_x; // nodal positions stored per element [nelem, nne, ndim] - xt::xtensor m_w; // weight of each integration point [nip] - xt::xtensor m_xi; // local coordinate of each integration point [nip, ndim] - xt::xtensor m_N; // shape functions [nip, nne] - xt::xtensor m_dNxi; // shape function grad. wrt local coor. [nip, nne, ndim] - xt::xtensor m_dNx; // shape function grad. wrt global coor. [nelem, nip, nne, ndim] - xt::xtensor m_vol; // integration point volume [nelem, nip] + xt::xtensor m_x; // nodal positions stored per element [nelem, nne, ndim] + xt::xtensor m_w; // weight of each integration point [nip] + xt::xtensor m_xi; // local coordinate of each integration point [nip, ndim] + xt::xtensor m_N; // shape functions [nip, nne] + xt::xtensor m_dNxi; // shape function grad. wrt local coor. [nip, nne, ndim] + xt::xtensor m_dNx; // shape function grad. wrt global coor. [nelem, nip, nne, ndim] + xt::xtensor m_vol; // integration point volume [nelem, nip] }; } // namespace Quad4 } // namespace Element } // namespace GooseFEM #include "ElementQuad4.hpp" #endif diff --git a/include/GooseFEM/ElementQuad4.hpp b/include/GooseFEM/ElementQuad4.hpp index c103027..9564c42 100644 --- a/include/GooseFEM/ElementQuad4.hpp +++ b/include/GooseFEM/ElementQuad4.hpp @@ -1,638 +1,591 @@ /* (c - GPLv3) T.W.J. de Geus (Tom) | tom@geus.me | www.geus.me | github.com/tdegeus/GooseFEM */ #ifndef GOOSEFEM_ELEMENTQUAD4_HPP #define GOOSEFEM_ELEMENTQUAD4_HPP #include "ElementQuad4.h" namespace GooseFEM { namespace Element { namespace Quad4 { -inline double inv(const xt::xtensor_fixed>& A, - xt::xtensor_fixed>& Ainv) +template +inline double inv(const T& A, T& Ainv) { double det = A(0, 0) * A(1, 1) - A(0, 1) * A(1, 0); - Ainv(0, 0) = A(1, 1) / det; + Ainv(0, 0) = A(1, 1) / det; Ainv(0, 1) = -1.0 * A(0, 1) / det; Ainv(1, 0) = -1.0 * A(1, 0) / det; - Ainv(1, 1) = A(0, 0) / det; + Ainv(1, 1) = A(0, 0) / det; return det; } namespace Gauss { inline size_t nip() { return 4; } -inline xt::xtensor xi() +inline xt::xtensor xi() { size_t nip = 4; size_t ndim = 2; - xt::xtensor xi = xt::empty({nip, ndim}); + xt::xtensor xi = xt::empty({nip, ndim}); xi(0, 0) = -1.0 / std::sqrt(3.0); xi(0, 1) = -1.0 / std::sqrt(3.0); xi(1, 0) = +1.0 / std::sqrt(3.0); xi(1, 1) = -1.0 / std::sqrt(3.0); xi(2, 0) = +1.0 / std::sqrt(3.0); xi(2, 1) = +1.0 / std::sqrt(3.0); xi(3, 0) = -1.0 / std::sqrt(3.0); xi(3, 1) = +1.0 / std::sqrt(3.0); return xi; } -inline xt::xtensor w() +inline xt::xtensor w() { size_t nip = 4; - xt::xtensor w = xt::empty({nip}); + xt::xtensor w = xt::empty({nip}); w(0) = 1.0; w(1) = 1.0; w(2) = 1.0; w(3) = 1.0; return w; } } // namespace Gauss namespace Nodal { inline size_t nip() { return 4; } -inline xt::xtensor xi() +inline xt::xtensor xi() { size_t nip = 4; size_t ndim = 2; - xt::xtensor xi = xt::empty({nip, ndim}); + xt::xtensor xi = xt::empty({nip, ndim}); xi(0, 0) = -1.0; xi(0, 1) = -1.0; xi(1, 0) = +1.0; xi(1, 1) = -1.0; xi(2, 0) = +1.0; xi(2, 1) = +1.0; xi(3, 0) = -1.0; xi(3, 1) = +1.0; return xi; } -inline xt::xtensor w() +inline xt::xtensor w() { size_t nip = 4; - xt::xtensor w = xt::empty({nip}); + xt::xtensor w = xt::empty({nip}); w(0) = 1.0; w(1) = 1.0; w(2) = 1.0; w(3) = 1.0; return w; } } // namespace Nodal namespace MidPoint { inline size_t nip() { return 1; } -inline xt::xtensor xi() +inline xt::xtensor xi() { size_t nip = 1; size_t ndim = 2; - xt::xtensor xi = xt::empty({nip, ndim}); + xt::xtensor xi = xt::empty({nip, ndim}); xi(0, 0) = 0.0; xi(0, 1) = 0.0; return xi; } -inline xt::xtensor w() +inline xt::xtensor w() { size_t nip = 1; - xt::xtensor w = xt::empty({nip}); + xt::xtensor w = xt::empty({nip}); w(0) = 1.0; return w; } } // namespace MidPoint -inline Quadrature::Quadrature(const xt::xtensor& x) +inline Quadrature::Quadrature(const xt::xtensor& x) : Quadrature(x, Gauss::xi(), Gauss::w()) { } inline Quadrature::Quadrature( - const xt::xtensor& x, - const xt::xtensor& xi, - const xt::xtensor& w) + const xt::xtensor& x, + const xt::xtensor& xi, + const xt::xtensor& w) : m_x(x), m_w(w), m_xi(xi) { GOOSEFEM_ASSERT(m_x.shape(1) == m_nne); GOOSEFEM_ASSERT(m_x.shape(2) == m_ndim); m_nelem = m_x.shape(0); m_nip = m_w.size(); GOOSEFEM_ASSERT(m_xi.shape(0) == m_nip); GOOSEFEM_ASSERT(m_xi.shape(1) == m_ndim); GOOSEFEM_ASSERT(m_w.size() == m_nip); m_N = xt::empty({m_nip, m_nne}); m_dNxi = xt::empty({m_nip, m_nne, m_ndim}); m_dNx = xt::empty({m_nelem, m_nip, m_nne, m_ndim}); m_vol = xt::empty({m_nelem, m_nip}); for (size_t q = 0; q < m_nip; ++q) { m_N(q, 0) = 0.25 * (1.0 - m_xi(q, 0)) * (1.0 - m_xi(q, 1)); m_N(q, 1) = 0.25 * (1.0 + m_xi(q, 0)) * (1.0 - m_xi(q, 1)); m_N(q, 2) = 0.25 * (1.0 + m_xi(q, 0)) * (1.0 + m_xi(q, 1)); m_N(q, 3) = 0.25 * (1.0 - m_xi(q, 0)) * (1.0 + m_xi(q, 1)); } for (size_t q = 0; q < m_nip; ++q) { // - dN / dxi_0 m_dNxi(q, 0, 0) = -0.25 * (1.0 - m_xi(q, 1)); m_dNxi(q, 1, 0) = +0.25 * (1.0 - m_xi(q, 1)); m_dNxi(q, 2, 0) = +0.25 * (1.0 + m_xi(q, 1)); m_dNxi(q, 3, 0) = -0.25 * (1.0 + m_xi(q, 1)); // - dN / dxi_1 m_dNxi(q, 0, 1) = -0.25 * (1.0 - m_xi(q, 0)); m_dNxi(q, 1, 1) = -0.25 * (1.0 + m_xi(q, 0)); m_dNxi(q, 2, 1) = +0.25 * (1.0 + m_xi(q, 0)); m_dNxi(q, 3, 1) = +0.25 * (1.0 - m_xi(q, 0)); } compute_dN(); } inline size_t Quadrature::nelem() const { return m_nelem; } inline size_t Quadrature::nne() const { return m_nne; } inline size_t Quadrature::ndim() const { return m_ndim; } inline size_t Quadrature::nip() const { return m_nip; } -inline xt::xtensor Quadrature::GradN() const +inline xt::xtensor Quadrature::GradN() const { return m_dNx; } -inline void Quadrature::dV(xt::xtensor& qscalar) const +inline void Quadrature::dV(xt::xtensor& qscalar) const { GOOSEFEM_ASSERT( qscalar.shape() == std::decay_t::shape_type({m_nelem, m_nip})); #pragma omp parallel for for (size_t e = 0; e < m_nelem; ++e) { for (size_t q = 0; q < m_nip; ++q) { qscalar(e, q) = m_vol(e, q); } } } -inline void Quadrature::dV(xt::xtensor& qtensor) const +inline void Quadrature::dV(xt::xtensor& qtensor) const { GOOSEFEM_ASSERT( qtensor.shape() == std::decay_t::shape_type({m_nelem, m_nip, m_ndim, m_ndim})); #pragma omp parallel for for (size_t e = 0; e < m_nelem; ++e) { for (size_t q = 0; q < m_nip; ++q) { for (size_t i = 0; i < m_ndim; ++i) { for (size_t j = 0; j < m_ndim; ++j) { qtensor(e, q, i, j) = m_vol(e, q); } } } } } inline void Quadrature::dV(xt::xarray& qtensor) const { GOOSEFEM_ASSERT(qtensor.shape(0) == m_nelem); GOOSEFEM_ASSERT(qtensor.shape(1) == m_nip); xt::dynamic_shape strides = {static_cast(m_vol.strides()[0]), static_cast(m_vol.strides()[1])}; for (size_t i = 2; i < qtensor.shape().size(); ++i) { strides.push_back(0); } qtensor = xt::strided_view(m_vol, qtensor.shape(), std::move(strides), 0ul, xt::layout_type::dynamic); } -inline void Quadrature::update_x(const xt::xtensor& x) +inline void Quadrature::update_x(const xt::xtensor& x) { GOOSEFEM_ASSERT(x.shape() == m_x.shape()); xt::noalias(m_x) = x; compute_dN(); } inline void Quadrature::compute_dN() { #pragma omp parallel { xt::xtensor_fixed> J; xt::xtensor_fixed> Jinv; #pragma omp for for (size_t e = 0; e < m_nelem; ++e) { auto x = xt::adapt(&m_x(e, 0, 0), xt::xshape()); for (size_t q = 0; q < m_nip; ++q) { auto dNxi = xt::adapt(&m_dNxi(q, 0, 0), xt::xshape()); auto dNx = xt::adapt(&m_dNx(e, q, 0, 0), xt::xshape()); // J(i,j) += dNxi(m,i) * x(m,j); - J(0, 0) - = dNxi(0, 0) * x(0, 0) - + dNxi(1, 0) * x(1, 0) - + dNxi(2, 0) * x(2, 0) - + dNxi(3, 0) * x(3, 0); - J(0, 1) - = dNxi(0, 0) * x(0, 1) - + dNxi(1, 0) * x(1, 1) - + dNxi(2, 0) * x(2, 1) - + dNxi(3, 0) * x(3, 1); - J(1, 0) - = dNxi(0, 1) * x(0, 0) - + dNxi(1, 1) * x(1, 0) - + dNxi(2, 1) * x(2, 0) - + dNxi(3, 1) * x(3, 0); - J(1, 1) - = dNxi(0, 1) * x(0, 1) - + dNxi(1, 1) * x(1, 1) - + dNxi(2, 1) * x(2, 1) - + dNxi(3, 1) * x(3, 1); + J(0, 0) = dNxi(0, 0) * x(0, 0) + dNxi(1, 0) * x(1, 0) + dNxi(2, 0) * x(2, 0) + + dNxi(3, 0) * x(3, 0); + J(0, 1) = dNxi(0, 0) * x(0, 1) + dNxi(1, 0) * x(1, 1) + dNxi(2, 0) * x(2, 1) + + dNxi(3, 0) * x(3, 1); + J(1, 0) = dNxi(0, 1) * x(0, 0) + dNxi(1, 1) * x(1, 0) + dNxi(2, 1) * x(2, 0) + + dNxi(3, 1) * x(3, 0); + J(1, 1) = dNxi(0, 1) * x(0, 1) + dNxi(1, 1) * x(1, 1) + dNxi(2, 1) * x(2, 1) + + dNxi(3, 1) * x(3, 1); double Jdet = inv(J, Jinv); // dNx(m,i) += Jinv(i,j) * dNxi(m,j); for (size_t m = 0; m < m_nne; ++m) { dNx(m, 0) = Jinv(0, 0) * dNxi(m, 0) + Jinv(0, 1) * dNxi(m, 1); dNx(m, 1) = Jinv(1, 0) * dNxi(m, 0) + Jinv(1, 1) * dNxi(m, 1); } m_vol(e, q) = m_w(q) * Jdet; } } } } inline void Quadrature::gradN_vector( - const xt::xtensor& elemvec, xt::xtensor& qtensor) const + const xt::xtensor& elemvec, xt::xtensor& qtensor) const { GOOSEFEM_ASSERT( elemvec.shape() == std::decay_t::shape_type({m_nelem, m_nne, m_ndim})); GOOSEFEM_ASSERT( qtensor.shape() == std::decay_t::shape_type({m_nelem, m_nip, m_ndim, m_ndim})); #pragma omp parallel for for (size_t e = 0; e < m_nelem; ++e) { auto u = xt::adapt(&elemvec(e, 0, 0), xt::xshape()); for (size_t q = 0; q < m_nip; ++q) { auto dNx = xt::adapt(&m_dNx(e, q, 0, 0), xt::xshape()); auto gradu = xt::adapt(&qtensor(e, q, 0, 0), xt::xshape()); // gradu(i,j) += dNx(m,i) * u(m,j) - gradu(0, 0) - = dNx(0, 0) * u(0, 0) - + dNx(1, 0) * u(1, 0) - + dNx(2, 0) * u(2, 0) - + dNx(3, 0) * u(3, 0); - gradu(0, 1) - = dNx(0, 0) * u(0, 1) - + dNx(1, 0) * u(1, 1) - + dNx(2, 0) * u(2, 1) - + dNx(3, 0) * u(3, 1); - gradu(1, 0) - = dNx(0, 1) * u(0, 0) - + dNx(1, 1) * u(1, 0) - + dNx(2, 1) * u(2, 0) - + dNx(3, 1) * u(3, 0); - gradu(1, 1) - = dNx(0, 1) * u(0, 1) - + dNx(1, 1) * u(1, 1) - + dNx(2, 1) * u(2, 1) - + dNx(3, 1) * u(3, 1); + gradu(0, 0) = dNx(0, 0) * u(0, 0) + dNx(1, 0) * u(1, 0) + dNx(2, 0) * u(2, 0) + + dNx(3, 0) * u(3, 0); + gradu(0, 1) = dNx(0, 0) * u(0, 1) + dNx(1, 0) * u(1, 1) + dNx(2, 0) * u(2, 1) + + dNx(3, 0) * u(3, 1); + gradu(1, 0) = dNx(0, 1) * u(0, 0) + dNx(1, 1) * u(1, 0) + dNx(2, 1) * u(2, 0) + + dNx(3, 1) * u(3, 0); + gradu(1, 1) = dNx(0, 1) * u(0, 1) + dNx(1, 1) * u(1, 1) + dNx(2, 1) * u(2, 1) + + dNx(3, 1) * u(3, 1); } } } inline void Quadrature::gradN_vector_T( - const xt::xtensor& elemvec, xt::xtensor& qtensor) const + const xt::xtensor& elemvec, xt::xtensor& qtensor) const { GOOSEFEM_ASSERT( elemvec.shape() == std::decay_t::shape_type({m_nelem, m_nne, m_ndim})); GOOSEFEM_ASSERT( qtensor.shape() == std::decay_t::shape_type({m_nelem, m_nip, m_ndim, m_ndim})); #pragma omp parallel for for (size_t e = 0; e < m_nelem; ++e) { auto u = xt::adapt(&elemvec(e, 0, 0), xt::xshape()); for (size_t q = 0; q < m_nip; ++q) { auto dNx = xt::adapt(&m_dNx(e, q, 0, 0), xt::xshape()); auto gradu = xt::adapt(&qtensor(e, q, 0, 0), xt::xshape()); // gradu(j,i) += dNx(m,i) * u(m,j) - gradu(0, 0) - = dNx(0, 0) * u(0, 0) - + dNx(1, 0) * u(1, 0) - + dNx(2, 0) * u(2, 0) - + dNx(3, 0) * u(3, 0); - gradu(1, 0) - = dNx(0, 0) * u(0, 1) - + dNx(1, 0) * u(1, 1) - + dNx(2, 0) * u(2, 1) - + dNx(3, 0) * u(3, 1); - gradu(0, 1) - = dNx(0, 1) * u(0, 0) - + dNx(1, 1) * u(1, 0) - + dNx(2, 1) * u(2, 0) - + dNx(3, 1) * u(3, 0); - gradu(1, 1) - = dNx(0, 1) * u(0, 1) - + dNx(1, 1) * u(1, 1) - + dNx(2, 1) * u(2, 1) - + dNx(3, 1) * u(3, 1); + gradu(0, 0) = dNx(0, 0) * u(0, 0) + dNx(1, 0) * u(1, 0) + dNx(2, 0) * u(2, 0) + + dNx(3, 0) * u(3, 0); + gradu(1, 0) = dNx(0, 0) * u(0, 1) + dNx(1, 0) * u(1, 1) + dNx(2, 0) * u(2, 1) + + dNx(3, 0) * u(3, 1); + gradu(0, 1) = dNx(0, 1) * u(0, 0) + dNx(1, 1) * u(1, 0) + dNx(2, 1) * u(2, 0) + + dNx(3, 1) * u(3, 0); + gradu(1, 1) = dNx(0, 1) * u(0, 1) + dNx(1, 1) * u(1, 1) + dNx(2, 1) * u(2, 1) + + dNx(3, 1) * u(3, 1); } } } inline void Quadrature::symGradN_vector( - const xt::xtensor& elemvec, xt::xtensor& qtensor) const + const xt::xtensor& elemvec, xt::xtensor& qtensor) const { GOOSEFEM_ASSERT( elemvec.shape() == std::decay_t::shape_type({m_nelem, m_nne, m_ndim})); GOOSEFEM_ASSERT( qtensor.shape() == std::decay_t::shape_type({m_nelem, m_nip, m_ndim, m_ndim})); #pragma omp parallel for for (size_t e = 0; e < m_nelem; ++e) { auto u = xt::adapt(&elemvec(e, 0, 0), xt::xshape()); for (size_t q = 0; q < m_nip; ++q) { auto dNx = xt::adapt(&m_dNx(e, q, 0, 0), xt::xshape()); auto eps = xt::adapt(&qtensor(e, q, 0, 0), xt::xshape()); // gradu(i,j) += dNx(m,i) * u(m,j) // eps(j,i) = 0.5 * (gradu(i,j) + gradu(j,i)) - eps(0, 0) - = dNx(0, 0) * u(0, 0) - + dNx(1, 0) * u(1, 0) - + dNx(2, 0) * u(2, 0) - + dNx(3, 0) * u(3, 0); - eps(1, 1) - = dNx(0, 1) * u(0, 1) - + dNx(1, 1) * u(1, 1) - + dNx(2, 1) * u(2, 1) - + dNx(3, 1) * u(3, 1); - eps(0, 1) = 0.5 * - ( dNx(0, 0) * u(0, 1) - + dNx(1, 0) * u(1, 1) - + dNx(2, 0) * u(2, 1) - + dNx(3, 0) * u(3, 1) - + dNx(0, 1) * u(0, 0) - + dNx(1, 1) * u(1, 0) - + dNx(2, 1) * u(2, 0) - + dNx(3, 1) * u(3, 0)); + eps(0, 0) = dNx(0, 0) * u(0, 0) + dNx(1, 0) * u(1, 0) + dNx(2, 0) * u(2, 0) + + dNx(3, 0) * u(3, 0); + eps(1, 1) = dNx(0, 1) * u(0, 1) + dNx(1, 1) * u(1, 1) + dNx(2, 1) * u(2, 1) + + dNx(3, 1) * u(3, 1); + eps(0, 1) = 0.5 * (dNx(0, 0) * u(0, 1) + dNx(1, 0) * u(1, 1) + dNx(2, 0) * u(2, 1) + + dNx(3, 0) * u(3, 1) + dNx(0, 1) * u(0, 0) + dNx(1, 1) * u(1, 0) + + dNx(2, 1) * u(2, 0) + dNx(3, 1) * u(3, 0)); eps(1, 0) = eps(0, 1); } } } inline void Quadrature::int_N_scalar_NT_dV( - const xt::xtensor& qscalar, xt::xtensor& elemmat) const + const xt::xtensor& qscalar, xt::xtensor& elemmat) const { GOOSEFEM_ASSERT( qscalar.shape() == std::decay_t::shape_type({m_nelem, m_nip})); GOOSEFEM_ASSERT( elemmat.shape() == std::decay_t::shape_type({m_nelem, m_nne * m_ndim, m_nne * m_ndim})); elemmat.fill(0.0); #pragma omp parallel for for (size_t e = 0; e < m_nelem; ++e) { auto M = xt::adapt(&elemmat(e, 0, 0), xt::xshape()); for (size_t q = 0; q < m_nip; ++q) { auto N = xt::adapt(&m_N(q, 0), xt::xshape()); auto& vol = m_vol(e, q); auto& rho = qscalar(e, q); // M(m*ndim+i,n*ndim+i) += N(m) * scalar * N(n) * dV for (size_t m = 0; m < m_nne; ++m) { for (size_t n = 0; n < m_nne; ++n) { M(m * m_ndim + 0, n * m_ndim + 0) += N(m) * rho * N(n) * vol; M(m * m_ndim + 1, n * m_ndim + 1) += N(m) * rho * N(n) * vol; } } } } } inline void Quadrature::int_gradN_dot_tensor2_dV( - const xt::xtensor& qtensor, xt::xtensor& elemvec) const + const xt::xtensor& qtensor, xt::xtensor& elemvec) const { GOOSEFEM_ASSERT( qtensor.shape() == std::decay_t::shape_type({m_nelem, m_nip, m_ndim, m_ndim})); GOOSEFEM_ASSERT( elemvec.shape() == std::decay_t::shape_type({m_nelem, m_nne, m_ndim})); elemvec.fill(0.0); #pragma omp parallel for for (size_t e = 0; e < m_nelem; ++e) { auto f = xt::adapt(&elemvec(e, 0, 0), xt::xshape()); for (size_t q = 0; q < m_nip; ++q) { auto dNx = xt::adapt(&m_dNx(e, q, 0, 0), xt::xshape()); auto sig = xt::adapt(&qtensor(e, q, 0, 0), xt::xshape()); auto& vol = m_vol(e, q); for (size_t m = 0; m < m_nne; ++m) { f(m, 0) += (dNx(m, 0) * sig(0, 0) + dNx(m, 1) * sig(1, 0)) * vol; f(m, 1) += (dNx(m, 0) * sig(0, 1) + dNx(m, 1) * sig(1, 1)) * vol; } } } } inline void Quadrature::int_gradN_dot_tensor4_dot_gradNT_dV( - const xt::xtensor& qtensor, xt::xtensor& elemmat) const + const xt::xtensor& qtensor, xt::xtensor& elemmat) const { GOOSEFEM_ASSERT( - qtensor.shape() == - std::decay_t::shape_type({m_nelem,m_nip,m_ndim,m_ndim,m_ndim,m_ndim})); + qtensor.shape() == std::decay_t::shape_type( + {m_nelem, m_nip, m_ndim, m_ndim, m_ndim, m_ndim})); GOOSEFEM_ASSERT( elemmat.shape() == std::decay_t::shape_type({m_nelem, m_nne * m_ndim, m_nne * m_ndim})); elemmat.fill(0.0); #pragma omp parallel for for (size_t e = 0; e < m_nelem; ++e) { auto K = xt::adapt(&elemmat(e, 0, 0), xt::xshape()); for (size_t q = 0; q < m_nip; ++q) { - auto dNx = xt::adapt(&m_dNx(e,q,0,0), xt::xshape()); - auto C = xt::adapt(&qtensor(e,q,0,0,0,0), xt::xshape()); + auto dNx = xt::adapt(&m_dNx(e, q, 0, 0), xt::xshape()); + auto C = + xt::adapt(&qtensor(e, q, 0, 0, 0, 0), xt::xshape()); auto& vol = m_vol(e, q); for (size_t m = 0; m < m_nne; ++m) { for (size_t n = 0; n < m_nne; ++n) { for (size_t i = 0; i < m_ndim; ++i) { for (size_t j = 0; j < m_ndim; ++j) { for (size_t k = 0; k < m_ndim; ++k) { for (size_t l = 0; l < m_ndim; ++l) { K(m * m_ndim + j, n * m_ndim + k) += dNx(m, i) * C(i, j, k, l) * dNx(n, l) * vol; } } } } } } } } } -inline xt::xtensor Quadrature::DV() const +inline xt::xtensor Quadrature::DV() const { - xt::xtensor out = xt::empty({m_nelem, m_nip}); + xt::xtensor out = xt::empty({m_nelem, m_nip}); this->dV(out); return out; } inline xt::xarray Quadrature::DV(size_t rank) const { std::vector shape = {m_nelem, m_nip}; for (size_t i = 0; i < rank; ++i) { shape.push_back(static_cast(m_ndim)); } xt::xarray out = xt::empty(shape); this->dV(out); return out; } -inline xt::xtensor Quadrature::GradN_vector(const xt::xtensor& elemvec) const +inline xt::xtensor Quadrature::GradN_vector(const xt::xtensor& elemvec) const { - xt::xtensor qtensor = xt::empty({m_nelem, m_nip, m_ndim, m_ndim}); + xt::xtensor qtensor = xt::empty({m_nelem, m_nip, m_ndim, m_ndim}); this->gradN_vector(elemvec, qtensor); return qtensor; } -inline xt::xtensor -Quadrature::GradN_vector_T(const xt::xtensor& elemvec) const +inline xt::xtensor +Quadrature::GradN_vector_T(const xt::xtensor& elemvec) const { - xt::xtensor qtensor = xt::empty({m_nelem, m_nip, m_ndim, m_ndim}); + xt::xtensor qtensor = xt::empty({m_nelem, m_nip, m_ndim, m_ndim}); this->gradN_vector_T(elemvec, qtensor); return qtensor; } -inline xt::xtensor -Quadrature::SymGradN_vector(const xt::xtensor& elemvec) const +inline xt::xtensor +Quadrature::SymGradN_vector(const xt::xtensor& elemvec) const { - xt::xtensor qtensor = xt::empty({m_nelem, m_nip, m_ndim, m_ndim}); + xt::xtensor qtensor = xt::empty({m_nelem, m_nip, m_ndim, m_ndim}); this->symGradN_vector(elemvec, qtensor); return qtensor; } -inline xt::xtensor -Quadrature::Int_N_scalar_NT_dV(const xt::xtensor& qscalar) const +inline xt::xtensor +Quadrature::Int_N_scalar_NT_dV(const xt::xtensor& qscalar) const { - xt::xtensor elemmat = xt::empty({m_nelem, m_nne * m_ndim, m_nne * m_ndim}); + xt::xtensor elemmat = xt::empty({m_nelem, m_nne * m_ndim, m_nne * m_ndim}); this->int_N_scalar_NT_dV(qscalar, elemmat); return elemmat; } -inline xt::xtensor -Quadrature::Int_gradN_dot_tensor2_dV(const xt::xtensor& qtensor) const +inline xt::xtensor +Quadrature::Int_gradN_dot_tensor2_dV(const xt::xtensor& qtensor) const { - xt::xtensor elemvec = xt::empty({m_nelem, m_nne, m_ndim}); + xt::xtensor elemvec = xt::empty({m_nelem, m_nne, m_ndim}); this->int_gradN_dot_tensor2_dV(qtensor, elemvec); return elemvec; } -inline xt::xtensor -Quadrature::Int_gradN_dot_tensor4_dot_gradNT_dV(const xt::xtensor& qtensor) const +inline xt::xtensor +Quadrature::Int_gradN_dot_tensor4_dot_gradNT_dV(const xt::xtensor& qtensor) const { - xt::xtensor elemmat = xt::empty({m_nelem, m_ndim * m_nne, m_ndim * m_nne}); + xt::xtensor elemmat = xt::empty({m_nelem, m_ndim * m_nne, m_ndim * m_nne}); this->int_gradN_dot_tensor4_dot_gradNT_dV(qtensor, elemmat); return elemmat; } } // namespace Quad4 } // namespace Element } // namespace GooseFEM #endif diff --git a/include/GooseFEM/ElementQuad4Axisymmetric.h b/include/GooseFEM/ElementQuad4Axisymmetric.h index 6390580..d307f03 100644 --- a/include/GooseFEM/ElementQuad4Axisymmetric.h +++ b/include/GooseFEM/ElementQuad4Axisymmetric.h @@ -1,126 +1,115 @@ /* (c - GPLv3) T.W.J. de Geus (Tom) | tom@geus.me | www.geus.me | github.com/tdegeus/GooseFEM */ #ifndef GOOSEFEM_ELEMENTQUAD4AXISYMMETRIC_H #define GOOSEFEM_ELEMENTQUAD4AXISYMMETRIC_H #include "config.h" namespace GooseFEM { namespace Element { namespace Quad4 { class QuadratureAxisymmetric { public: // Fixed dimensions: // ndim = 2 - number of dimensions // nne = 4 - number of nodes per element // tdim = 3 - number of dimensions of tensors // // Naming convention: // "elemmat" - matrices stored per element - [nelem, nne*ndim, nne*ndim] // "elemvec" - nodal vectors stored per element - [nelem, nne, ndim] // "qtensor" - integration point tensor - [nelem, nip, tdim, tdim] // "qscalar" - integration point scalar - [nelem, nip] // Constructor: integration point coordinates and weights are optional (default: Gauss) QuadratureAxisymmetric() = default; - QuadratureAxisymmetric(const xt::xtensor& x); + QuadratureAxisymmetric(const xt::xtensor& x); QuadratureAxisymmetric( - const xt::xtensor& x, - const xt::xtensor& xi, - const xt::xtensor& w); + const xt::xtensor& x, + const xt::xtensor& xi, + const xt::xtensor& w); // Update the nodal positions (shape of "x" should match the earlier definition) - void update_x(const xt::xtensor& x); + void update_x(const xt::xtensor& x); // Return dimensions size_t nelem() const; // number of elements size_t nne() const; // number of nodes per element size_t ndim() const; // number of dimension size_t nip() const; // number of integration points // Return integration volume - void dV(xt::xtensor& qscalar) const; - void dV(xt::xtensor& qtensor) const; // same volume for all tensor components - void dV(xt::xarray& qtensor) const; // same volume for all tensor components + void dV(xt::xtensor& qscalar) const; + void dV(xt::xtensor& qtensor) const; // same volume for all tensor components + void dV(xt::xarray& qtensor) const; // same volume for all tensor components // Dyadic product (and its transpose and symmetric part) // qtensor(i,j) += B(m,i,j,k) * elemvec(m,k) - void gradN_vector( - const xt::xtensor& elemvec, - xt::xtensor& qtensor) const; - - void gradN_vector_T( - const xt::xtensor& elemvec, - xt::xtensor& qtensor) const; - - void symGradN_vector( - const xt::xtensor& elemvec, - xt::xtensor& qtensor) const; + void gradN_vector(const xt::xtensor& elemvec, xt::xtensor& qtensor) const; + void gradN_vector_T(const xt::xtensor& elemvec, xt::xtensor& qtensor) const; + void symGradN_vector(const xt::xtensor& elemvec, xt::xtensor& qtensor) const; // Integral of the scalar product // elemmat(m*ndim+i,n*ndim+i) += N(m) * qscalar * N(n) * dV void int_N_scalar_NT_dV( - const xt::xtensor& qscalar, - xt::xtensor& elemmat) const; + const xt::xtensor& qscalar, xt::xtensor& elemmat) const; // Integral of the assembled product // fm = ( Bm^T : qtensor ) dV void int_gradN_dot_tensor2_dV( - const xt::xtensor& qtensor, - xt::xtensor& elemvec) const; + const xt::xtensor& qtensor, xt::xtensor& elemvec) const; // Integral of the assembled product // Kmn = ( Bm^T : qtensor : Bn ) dV void int_gradN_dot_tensor4_dot_gradNT_dV( - const xt::xtensor& qtensor, - xt::xtensor& elemmat) const; + const xt::xtensor& qtensor, xt::xtensor& elemmat) const; // Auto-allocation of the functions above - xt::xtensor DV() const; + xt::xtensor DV() const; xt::xarray DV(size_t rank) const; - xt::xtensor GradN_vector(const xt::xtensor& elemvec) const; - xt::xtensor GradN_vector_T(const xt::xtensor& elemvec) const; - xt::xtensor SymGradN_vector(const xt::xtensor& elemvec) const; - xt::xtensor Int_N_scalar_NT_dV(const xt::xtensor& qscalar) const; - xt::xtensor Int_gradN_dot_tensor2_dV(const xt::xtensor& qtensor) const; - xt::xtensor Int_gradN_dot_tensor4_dot_gradNT_dV( - const xt::xtensor& qtensor) const; + xt::xtensor GradN_vector(const xt::xtensor& elemvec) const; + xt::xtensor GradN_vector_T(const xt::xtensor& elemvec) const; + xt::xtensor SymGradN_vector(const xt::xtensor& elemvec) const; + xt::xtensor Int_N_scalar_NT_dV(const xt::xtensor& qscalar) const; + xt::xtensor Int_gradN_dot_tensor2_dV(const xt::xtensor& qtensor) const; + xt::xtensor Int_gradN_dot_tensor4_dot_gradNT_dV( + const xt::xtensor& qtensor) const; private: // Compute "vol" and "B" based on current "x" void compute_dN(); private: // Dimensions (flexible) size_t m_nelem; // number of elements size_t m_nip; // number of integration points // Dimensions (fixed for this element type) static const size_t m_nne = 4; // number of nodes per element static const size_t m_ndim = 2; // number of dimensions static const size_t m_tdim = 3; // number of dimensions of tensors // Data arrays - xt::xtensor m_x; // nodal positions stored per element [nelem, nne, ndim] - xt::xtensor m_w; // weight of each integration point [nip] - xt::xtensor m_xi; // local coordinate of each integration point [nip, ndim] - xt::xtensor m_N; // shape functions [nip, nne] - xt::xtensor m_dNxi; // shape function grad. wrt local coor. [nip, nne, ndim] - xt::xtensor m_B; // B-matrix [nelem, nne, tdim, tdim, tdim] - xt::xtensor m_vol; // integration point volume [nelem, nip] + xt::xtensor m_x; // nodal positions stored per element [nelem, nne, ndim] + xt::xtensor m_w; // weight of each integration point [nip] + xt::xtensor m_xi; // local coordinate of each integration point [nip, ndim] + xt::xtensor m_N; // shape functions [nip, nne] + xt::xtensor m_dNxi; // shape function grad. wrt local coor. [nip, nne, ndim] + xt::xtensor m_B; // B-matrix [nelem, nne, tdim, tdim, tdim] + xt::xtensor m_vol; // integration point volume [nelem, nip] }; } // namespace Quad4 } // namespace Element } // namespace GooseFEM #include "ElementQuad4Axisymmetric.hpp" #endif diff --git a/include/GooseFEM/ElementQuad4Axisymmetric.hpp b/include/GooseFEM/ElementQuad4Axisymmetric.hpp index 60534df..bd237ee 100644 --- a/include/GooseFEM/ElementQuad4Axisymmetric.hpp +++ b/include/GooseFEM/ElementQuad4Axisymmetric.hpp @@ -1,593 +1,533 @@ /* (c - GPLv3) T.W.J. de Geus (Tom) | tom@geus.me | www.geus.me | github.com/tdegeus/GooseFEM */ #ifndef GOOSEFEM_ELEMENTQUADAXISYMMETRIC_HPP #define GOOSEFEM_ELEMENTQUADAXISYMMETRIC_HPP #include "ElementQuad4Axisymmetric.h" namespace GooseFEM { namespace Element { namespace Quad4 { -inline QuadratureAxisymmetric::QuadratureAxisymmetric(const xt::xtensor& x) +inline QuadratureAxisymmetric::QuadratureAxisymmetric(const xt::xtensor& x) : QuadratureAxisymmetric(x, Gauss::xi(), Gauss::w()) { } inline QuadratureAxisymmetric::QuadratureAxisymmetric( - const xt::xtensor& x, - const xt::xtensor& xi, - const xt::xtensor& w) + const xt::xtensor& x, + const xt::xtensor& xi, + const xt::xtensor& w) : m_x(x), m_w(w), m_xi(xi) { GOOSEFEM_ASSERT(m_x.shape(1) == m_nne); GOOSEFEM_ASSERT(m_x.shape(2) == m_ndim); m_nelem = m_x.shape(0); m_nip = m_w.size(); GOOSEFEM_ASSERT(m_xi.shape(0) == m_nip); GOOSEFEM_ASSERT(m_xi.shape(1) == m_ndim); GOOSEFEM_ASSERT(m_w.size() == m_nip); m_N = xt::empty({m_nip, m_nne}); m_dNxi = xt::empty({m_nip, m_nne, m_ndim}); m_B = xt::empty({m_nelem, m_nip, m_nne, m_tdim, m_tdim, m_tdim}); m_vol = xt::empty({m_nelem, m_nip}); for (size_t q = 0; q < m_nip; ++q) { m_N(q, 0) = 0.25 * (1.0 - m_xi(q, 0)) * (1.0 - m_xi(q, 1)); m_N(q, 1) = 0.25 * (1.0 + m_xi(q, 0)) * (1.0 - m_xi(q, 1)); m_N(q, 2) = 0.25 * (1.0 + m_xi(q, 0)) * (1.0 + m_xi(q, 1)); m_N(q, 3) = 0.25 * (1.0 - m_xi(q, 0)) * (1.0 + m_xi(q, 1)); } for (size_t q = 0; q < m_nip; ++q) { // - dN / dxi_0 m_dNxi(q, 0, 0) = -0.25 * (1.0 - m_xi(q, 1)); m_dNxi(q, 1, 0) = +0.25 * (1.0 - m_xi(q, 1)); m_dNxi(q, 2, 0) = +0.25 * (1.0 + m_xi(q, 1)); m_dNxi(q, 3, 0) = -0.25 * (1.0 + m_xi(q, 1)); // - dN / dxi_1 m_dNxi(q, 0, 1) = -0.25 * (1.0 - m_xi(q, 0)); m_dNxi(q, 1, 1) = -0.25 * (1.0 + m_xi(q, 0)); m_dNxi(q, 2, 1) = +0.25 * (1.0 + m_xi(q, 0)); m_dNxi(q, 3, 1) = +0.25 * (1.0 - m_xi(q, 0)); } compute_dN(); } inline size_t QuadratureAxisymmetric::nelem() const { return m_nelem; } inline size_t QuadratureAxisymmetric::nne() const { return m_nne; } inline size_t QuadratureAxisymmetric::ndim() const { return m_ndim; } inline size_t QuadratureAxisymmetric::nip() const { return m_nip; } -inline void QuadratureAxisymmetric::dV(xt::xtensor& qscalar) const +inline void QuadratureAxisymmetric::dV(xt::xtensor& qscalar) const { GOOSEFEM_ASSERT( qscalar.shape() == std::decay_t::shape_type({m_nelem, m_nip})); #pragma omp parallel for for (size_t e = 0; e < m_nelem; ++e) { for (size_t q = 0; q < m_nip; ++q) { qscalar(e, q) = m_vol(e, q); } } } -inline void QuadratureAxisymmetric::dV(xt::xtensor& qtensor) const +inline void QuadratureAxisymmetric::dV(xt::xtensor& qtensor) const { GOOSEFEM_ASSERT( qtensor.shape() == std::decay_t::shape_type({m_nelem, m_nip, m_tdim, m_tdim})); #pragma omp parallel for for (size_t e = 0; e < m_nelem; ++e) { for (size_t q = 0; q < m_nip; ++q) { for (size_t i = 0; i < m_tdim; ++i) { for (size_t j = 0; j < m_tdim; ++j) { qtensor(e, q, i, j) = m_vol(e, q); } } } } } inline void QuadratureAxisymmetric::dV(xt::xarray& qtensor) const { GOOSEFEM_ASSERT(qtensor.shape(0) == m_nelem); GOOSEFEM_ASSERT(qtensor.shape(1) == m_nip); xt::dynamic_shape strides = {static_cast(m_vol.strides()[0]), static_cast(m_vol.strides()[1])}; for (size_t i = 2; i < qtensor.shape().size(); ++i) { strides.push_back(0); } qtensor = xt::strided_view(m_vol, qtensor.shape(), std::move(strides), 0ul, xt::layout_type::dynamic); } -inline void QuadratureAxisymmetric::update_x(const xt::xtensor& x) +inline void QuadratureAxisymmetric::update_x(const xt::xtensor& x) { GOOSEFEM_ASSERT(x.shape() == m_x.shape()); xt::noalias(m_x) = x; compute_dN(); } inline void QuadratureAxisymmetric::compute_dN() { // most components remain zero, and are not written m_B.fill(0.0); #pragma omp parallel { xt::xtensor_fixed> J; xt::xtensor_fixed> Jinv; #pragma omp for for (size_t e = 0; e < m_nelem; ++e) { auto x = xt::adapt(&m_x(e, 0, 0), xt::xshape()); for (size_t q = 0; q < m_nip; ++q) { - auto dNxi = xt::adapt(&m_dNxi(q,0,0), xt::xshape()); - auto B = xt::adapt(&m_B(e,q,0,0,0,0), xt::xshape()); - auto N = xt::adapt(&m_N(q,0), xt::xshape()); + auto dNxi = xt::adapt(&m_dNxi(q, 0, 0), xt::xshape()); + auto B = xt::adapt(&m_B(e, q, 0, 0, 0, 0), xt::xshape()); + auto N = xt::adapt(&m_N(q, 0), xt::xshape()); // J(i,j) += dNxi(m,i) * x(m,j); - J(0, 0) - = dNxi(0, 0) * x(0, 0) - + dNxi(1, 0) * x(1, 0) - + dNxi(2, 0) * x(2, 0) - + dNxi(3, 0) * x(3, 0); - J(0, 1) - = dNxi(0, 0) * x(0, 1) - + dNxi(1, 0) * x(1, 1) - + dNxi(2, 0) * x(2, 1) - + dNxi(3, 0) * x(3, 1); - J(1, 0) - = dNxi(0, 1) * x(0, 0) - + dNxi(1, 1) * x(1, 0) - + dNxi(2, 1) * x(2, 0) - + dNxi(3, 1) * x(3, 0); - J(1, 1) - = dNxi(0, 1) * x(0, 1) - + dNxi(1, 1) * x(1, 1) - + dNxi(2, 1) * x(2, 1) - + dNxi(3, 1) * x(3, 1); + J(0, 0) = dNxi(0, 0) * x(0, 0) + dNxi(1, 0) * x(1, 0) + dNxi(2, 0) * x(2, 0) + + dNxi(3, 0) * x(3, 0); + J(0, 1) = dNxi(0, 0) * x(0, 1) + dNxi(1, 0) * x(1, 1) + dNxi(2, 0) * x(2, 1) + + dNxi(3, 0) * x(3, 1); + J(1, 0) = dNxi(0, 1) * x(0, 0) + dNxi(1, 1) * x(1, 0) + dNxi(2, 1) * x(2, 0) + + dNxi(3, 1) * x(3, 0); + J(1, 1) = dNxi(0, 1) * x(0, 1) + dNxi(1, 1) * x(1, 1) + dNxi(2, 1) * x(2, 1) + + dNxi(3, 1) * x(3, 1); double Jdet = inv(J, Jinv); // radius for computation of volume double rq = N(0) * x(0, 1) + N(1) * x(1, 1) + N(2) * x(2, 1) + N(3) * x(3, 1); // dNx(m,i) += Jinv(i,j) * dNxi(m,j) for (size_t m = 0; m < m_nne; ++m) { // B(m, r, r, r) = dNdx(m,1) B(m, 0, 0, 0) = Jinv(1, 0) * dNxi(m, 0) + Jinv(1, 1) * dNxi(m, 1); // B(m, r, z, z) = dNdx(m,1) B(m, 0, 2, 2) = Jinv(1, 0) * dNxi(m, 0) + Jinv(1, 1) * dNxi(m, 1); // B(m, t, t, r) B(m, 1, 1, 0) = 1.0 / rq * N(m); // B(m, z, r, r) = dNdx(m,0) B(m, 2, 0, 0) = Jinv(0, 0) * dNxi(m, 0) + Jinv(0, 1) * dNxi(m, 1); // B(m, z, z, z) = dNdx(m,0) B(m, 2, 2, 2) = Jinv(0, 0) * dNxi(m, 0) + Jinv(0, 1) * dNxi(m, 1); } m_vol(e, q) = m_w(q) * Jdet * 2.0 * M_PI * rq; } } } } inline void QuadratureAxisymmetric::gradN_vector( - const xt::xtensor& elemvec, xt::xtensor& qtensor) const + const xt::xtensor& elemvec, xt::xtensor& qtensor) const { GOOSEFEM_ASSERT( elemvec.shape() == std::decay_t::shape_type({m_nelem, m_nne, m_ndim})); GOOSEFEM_ASSERT( qtensor.shape() == std::decay_t::shape_type({m_nelem, m_nip, m_tdim, m_tdim})); qtensor.fill(0.0); #pragma omp parallel for for (size_t e = 0; e < m_nelem; ++e) { auto u = xt::adapt(&elemvec(e, 0, 0), xt::xshape()); for (size_t q = 0; q < m_nip; ++q) { auto B = xt::adapt(&m_B(e, q, 0, 0, 0, 0), xt::xshape()); auto gradu = xt::adapt(&qtensor(e, q, 0, 0), xt::xshape()); // gradu(i,j) += B(m,i,j,k) * u(m,perm(k)) // (where perm(0) = 1, perm(2) = 0) - gradu(0, 0) - = B(0, 0, 0, 0) * u(0, 1) - + B(1, 0, 0, 0) * u(1, 1) - + B(2, 0, 0, 0) * u(2, 1) - + B(3, 0, 0, 0) * u(3, 1); - gradu(1, 1) - = B(0, 1, 1, 0) * u(0, 1) - + B(1, 1, 1, 0) * u(1, 1) - + B(2, 1, 1, 0) * u(2, 1) - + B(3, 1, 1, 0) * u(3, 1); - gradu(2, 2) - = B(0, 2, 2, 2) * u(0, 0) - + B(1, 2, 2, 2) * u(1, 0) - + B(2, 2, 2, 2) * u(2, 0) - + B(3, 2, 2, 2) * u(3, 0); - gradu(0, 2) - = B(0, 0, 2, 2) * u(0, 0) - + B(1, 0, 2, 2) * u(1, 0) - + B(2, 0, 2, 2) * u(2, 0) - + B(3, 0, 2, 2) * u(3, 0); - gradu(2, 0) - = B(0, 2, 0, 0) * u(0, 1) - + B(1, 2, 0, 0) * u(1, 1) - + B(2, 2, 0, 0) * u(2, 1) - + B(3, 2, 0, 0) * u(3, 1); + gradu(0, 0) = B(0, 0, 0, 0) * u(0, 1) + B(1, 0, 0, 0) * u(1, 1) + + B(2, 0, 0, 0) * u(2, 1) + B(3, 0, 0, 0) * u(3, 1); + gradu(1, 1) = B(0, 1, 1, 0) * u(0, 1) + B(1, 1, 1, 0) * u(1, 1) + + B(2, 1, 1, 0) * u(2, 1) + B(3, 1, 1, 0) * u(3, 1); + gradu(2, 2) = B(0, 2, 2, 2) * u(0, 0) + B(1, 2, 2, 2) * u(1, 0) + + B(2, 2, 2, 2) * u(2, 0) + B(3, 2, 2, 2) * u(3, 0); + gradu(0, 2) = B(0, 0, 2, 2) * u(0, 0) + B(1, 0, 2, 2) * u(1, 0) + + B(2, 0, 2, 2) * u(2, 0) + B(3, 0, 2, 2) * u(3, 0); + gradu(2, 0) = B(0, 2, 0, 0) * u(0, 1) + B(1, 2, 0, 0) * u(1, 1) + + B(2, 2, 0, 0) * u(2, 1) + B(3, 2, 0, 0) * u(3, 1); } } } inline void QuadratureAxisymmetric::gradN_vector_T( - const xt::xtensor& elemvec, xt::xtensor& qtensor) const + const xt::xtensor& elemvec, xt::xtensor& qtensor) const { GOOSEFEM_ASSERT( elemvec.shape() == std::decay_t::shape_type({m_nelem, m_nne, m_ndim})); GOOSEFEM_ASSERT( qtensor.shape() == std::decay_t::shape_type({m_nelem, m_nip, m_tdim, m_tdim})); qtensor.fill(0.0); #pragma omp parallel for for (size_t e = 0; e < m_nelem; ++e) { auto u = xt::adapt(&elemvec(e, 0, 0), xt::xshape()); for (size_t q = 0; q < m_nip; ++q) { auto B = xt::adapt(&m_B(e, q, 0, 0, 0, 0), xt::xshape()); auto gradu = xt::adapt(&qtensor(e, q, 0, 0), xt::xshape()); // gradu(j,i) += B(m,i,j,k) * u(m,perm(k)) // (where perm(0) = 1, perm(2) = 0) - gradu(0, 0) - = B(0, 0, 0, 0) * u(0, 1) - + B(1, 0, 0, 0) * u(1, 1) - + B(2, 0, 0, 0) * u(2, 1) - + B(3, 0, 0, 0) * u(3, 1); - gradu(1, 1) - = B(0, 1, 1, 0) * u(0, 1) - + B(1, 1, 1, 0) * u(1, 1) - + B(2, 1, 1, 0) * u(2, 1) - + B(3, 1, 1, 0) * u(3, 1); - gradu(2, 2) - = B(0, 2, 2, 2) * u(0, 0) - + B(1, 2, 2, 2) * u(1, 0) - + B(2, 2, 2, 2) * u(2, 0) - + B(3, 2, 2, 2) * u(3, 0); - gradu(2, 0) - = B(0, 0, 2, 2) * u(0, 0) - + B(1, 0, 2, 2) * u(1, 0) - + B(2, 0, 2, 2) * u(2, 0) - + B(3, 0, 2, 2) * u(3, 0); - gradu(0, 2) - = B(0, 2, 0, 0) * u(0, 1) - + B(1, 2, 0, 0) * u(1, 1) - + B(2, 2, 0, 0) * u(2, 1) - + B(3, 2, 0, 0) * u(3, 1); + gradu(0, 0) = B(0, 0, 0, 0) * u(0, 1) + B(1, 0, 0, 0) * u(1, 1) + + B(2, 0, 0, 0) * u(2, 1) + B(3, 0, 0, 0) * u(3, 1); + gradu(1, 1) = B(0, 1, 1, 0) * u(0, 1) + B(1, 1, 1, 0) * u(1, 1) + + B(2, 1, 1, 0) * u(2, 1) + B(3, 1, 1, 0) * u(3, 1); + gradu(2, 2) = B(0, 2, 2, 2) * u(0, 0) + B(1, 2, 2, 2) * u(1, 0) + + B(2, 2, 2, 2) * u(2, 0) + B(3, 2, 2, 2) * u(3, 0); + gradu(2, 0) = B(0, 0, 2, 2) * u(0, 0) + B(1, 0, 2, 2) * u(1, 0) + + B(2, 0, 2, 2) * u(2, 0) + B(3, 0, 2, 2) * u(3, 0); + gradu(0, 2) = B(0, 2, 0, 0) * u(0, 1) + B(1, 2, 0, 0) * u(1, 1) + + B(2, 2, 0, 0) * u(2, 1) + B(3, 2, 0, 0) * u(3, 1); } } } inline void QuadratureAxisymmetric::symGradN_vector( - const xt::xtensor& elemvec, xt::xtensor& qtensor) const + const xt::xtensor& elemvec, xt::xtensor& qtensor) const { GOOSEFEM_ASSERT( elemvec.shape() == std::decay_t::shape_type({m_nelem, m_nne, m_ndim})); GOOSEFEM_ASSERT( qtensor.shape() == std::decay_t::shape_type({m_nelem, m_nip, m_tdim, m_tdim})); qtensor.fill(0.0); #pragma omp parallel for for (size_t e = 0; e < m_nelem; ++e) { auto u = xt::adapt(&elemvec(e, 0, 0), xt::xshape()); for (size_t q = 0; q < m_nip; ++q) { auto B = xt::adapt(&m_B(e, q, 0, 0, 0, 0), xt::xshape()); auto eps = xt::adapt(&qtensor(e, q, 0, 0), xt::xshape()); // gradu(j,i) += B(m,i,j,k) * u(m,perm(k)) // eps(j,i) = 0.5 * (gradu(i,j) + gradu(j,i)) // (where perm(0) = 1, perm(2) = 0) - eps(0, 0) - = B(0, 0, 0, 0) * u(0, 1) - + B(1, 0, 0, 0) * u(1, 1) - + B(2, 0, 0, 0) * u(2, 1) - + B(3, 0, 0, 0) * u(3, 1); - eps(1, 1) - = B(0, 1, 1, 0) * u(0, 1) - + B(1, 1, 1, 0) * u(1, 1) - + B(2, 1, 1, 0) * u(2, 1) - + B(3, 1, 1, 0) * u(3, 1); - eps(2, 2) - = B(0, 2, 2, 2) * u(0, 0) - + B(1, 2, 2, 2) * u(1, 0) - + B(2, 2, 2, 2) * u(2, 0) - + B(3, 2, 2, 2) * u(3, 0); - eps(2, 0) = 0.5 * - ( B(0, 0, 2, 2) * u(0, 0) - + B(1, 0, 2, 2) * u(1, 0) - + B(2, 0, 2, 2) * u(2, 0) - + B(3, 0, 2, 2) * u(3, 0) - + B(0, 2, 0, 0) * u(0, 1) - + B(1, 2, 0, 0) * u(1, 1) - + B(2, 2, 0, 0) * u(2, 1) - + B(3, 2, 0, 0) * u(3, 1)); + eps(0, 0) = B(0, 0, 0, 0) * u(0, 1) + B(1, 0, 0, 0) * u(1, 1) + + B(2, 0, 0, 0) * u(2, 1) + B(3, 0, 0, 0) * u(3, 1); + eps(1, 1) = B(0, 1, 1, 0) * u(0, 1) + B(1, 1, 1, 0) * u(1, 1) + + B(2, 1, 1, 0) * u(2, 1) + B(3, 1, 1, 0) * u(3, 1); + eps(2, 2) = B(0, 2, 2, 2) * u(0, 0) + B(1, 2, 2, 2) * u(1, 0) + + B(2, 2, 2, 2) * u(2, 0) + B(3, 2, 2, 2) * u(3, 0); + eps(2, 0) = + 0.5 * (B(0, 0, 2, 2) * u(0, 0) + B(1, 0, 2, 2) * u(1, 0) + B(2, 0, 2, 2) * u(2, 0) + + B(3, 0, 2, 2) * u(3, 0) + B(0, 2, 0, 0) * u(0, 1) + B(1, 2, 0, 0) * u(1, 1) + + B(2, 2, 0, 0) * u(2, 1) + B(3, 2, 0, 0) * u(3, 1)); eps(0, 2) = eps(2, 0); } } } inline void QuadratureAxisymmetric::int_N_scalar_NT_dV( - const xt::xtensor& qscalar, xt::xtensor& elemmat) const + const xt::xtensor& qscalar, xt::xtensor& elemmat) const { GOOSEFEM_ASSERT( qscalar.shape() == std::decay_t::shape_type({m_nelem, m_nip})); GOOSEFEM_ASSERT( elemmat.shape() == std::decay_t::shape_type({m_nelem, m_nne * m_ndim, m_nne * m_ndim})); elemmat.fill(0.0); #pragma omp parallel for for (size_t e = 0; e < m_nelem; ++e) { auto M = xt::adapt(&elemmat(e, 0, 0), xt::xshape()); for (size_t q = 0; q < m_nip; ++q) { auto N = xt::adapt(&m_N(q, 0), xt::xshape()); auto& vol = m_vol(e, q); auto& rho = qscalar(e, q); // M(m*ndim+i,n*ndim+i) += N(m) * scalar * N(n) * dV for (size_t m = 0; m < m_nne; ++m) { for (size_t n = 0; n < m_nne; ++n) { M(m * m_ndim + 0, n * m_ndim + 0) += N(m) * rho * N(n) * vol; M(m * m_ndim + 1, n * m_ndim + 1) += N(m) * rho * N(n) * vol; } } } } } inline void QuadratureAxisymmetric::int_gradN_dot_tensor2_dV( - const xt::xtensor& qtensor, xt::xtensor& elemvec) const + const xt::xtensor& qtensor, xt::xtensor& elemvec) const { GOOSEFEM_ASSERT( qtensor.shape() == std::decay_t::shape_type({m_nelem, m_nip, m_tdim, m_tdim})); GOOSEFEM_ASSERT( elemvec.shape() == std::decay_t::shape_type({m_nelem, m_nne, m_ndim})); elemvec.fill(0.0); #pragma omp parallel for for (size_t e = 0; e < m_nelem; ++e) { auto f = xt::adapt(&elemvec(e, 0, 0), xt::xshape()); for (size_t q = 0; q < m_nip; ++q) { auto B = xt::adapt(&m_B(e, q, 0, 0, 0, 0), xt::xshape()); auto sig = xt::adapt(&qtensor(e, q, 0, 0), xt::xshape()); auto& vol = m_vol(e, q); // f(m,i) += B(m,i,j,perm(k)) * sig(i,j) * dV // (where perm(0) = 1, perm(2) = 0) for (size_t m = 0; m < m_nne; ++m) { - f(m, 0) += vol * - ( B(m, 2, 2, 2) * sig(2, 2) - + B(m, 0, 2, 2) * sig(0, 2)); - f(m, 1) += vol * - ( B(m, 0, 0, 0) * sig(0, 0) - + B(m, 1, 1, 0) * sig(1, 1) - + B(m, 2, 0, 0) * sig(2, 0)); + f(m, 0) += vol * (B(m, 2, 2, 2) * sig(2, 2) + B(m, 0, 2, 2) * sig(0, 2)); + f(m, 1) += vol * (B(m, 0, 0, 0) * sig(0, 0) + B(m, 1, 1, 0) * sig(1, 1) + + B(m, 2, 0, 0) * sig(2, 0)); } } } } inline void QuadratureAxisymmetric::int_gradN_dot_tensor4_dot_gradNT_dV( - const xt::xtensor& qtensor, xt::xtensor& elemmat) const + const xt::xtensor& qtensor, xt::xtensor& elemmat) const { GOOSEFEM_ASSERT( - qtensor.shape() == - std::decay_t::shape_type({m_nelem,m_nip,m_tdim,m_tdim,m_tdim,m_tdim})); + qtensor.shape() == std::decay_t::shape_type( + {m_nelem, m_nip, m_tdim, m_tdim, m_tdim, m_tdim})); GOOSEFEM_ASSERT( elemmat.shape() == std::decay_t::shape_type({m_nelem, m_nne * m_ndim, m_nne * m_ndim})); elemmat.fill(0.0); #pragma omp parallel for for (size_t e = 0; e < m_nelem; ++e) { auto K = xt::adapt(&elemmat(e, 0, 0), xt::xshape()); for (size_t q = 0; q < m_nip; ++q) { - auto B = xt::adapt(&m_B(e,q,0,0,0,0), xt::xshape()); - auto C = xt::adapt(&qtensor(e,q,0,0,0,0), xt::xshape()); + auto B = xt::adapt(&m_B(e, q, 0, 0, 0, 0), xt::xshape()); + auto C = xt::adapt(&qtensor(e, q, 0, 0, 0, 0), xt::xshape()); auto& vol = m_vol(e, q); // K(m*m_ndim+perm(c), n*m_ndim+perm(f)) = B(m,a,b,c) * C(a,b,d,e) * B(n,e,d,f) * vol; // (where perm(0) = 1, perm(2) = 0) for (size_t m = 0; m < m_nne; ++m) { for (size_t n = 0; n < m_nne; ++n) { K(m * m_ndim + 1, n * m_ndim + 1) += B(m, 0, 0, 0) * C(0, 0, 0, 0) * B(n, 0, 0, 0) * vol; K(m * m_ndim + 1, n * m_ndim + 1) += B(m, 0, 0, 0) * C(0, 0, 1, 1) * B(n, 1, 1, 0) * vol; K(m * m_ndim + 1, n * m_ndim + 0) += B(m, 0, 0, 0) * C(0, 0, 2, 2) * B(n, 2, 2, 2) * vol; K(m * m_ndim + 1, n * m_ndim + 0) += B(m, 0, 0, 0) * C(0, 0, 2, 0) * B(n, 0, 2, 2) * vol; K(m * m_ndim + 1, n * m_ndim + 1) += B(m, 0, 0, 0) * C(0, 0, 0, 2) * B(n, 2, 0, 0) * vol; K(m * m_ndim + 1, n * m_ndim + 1) += B(m, 1, 1, 0) * C(1, 1, 0, 0) * B(n, 0, 0, 0) * vol; K(m * m_ndim + 1, n * m_ndim + 1) += B(m, 1, 1, 0) * C(1, 1, 1, 1) * B(n, 1, 1, 0) * vol; K(m * m_ndim + 1, n * m_ndim + 0) += B(m, 1, 1, 0) * C(1, 1, 2, 2) * B(n, 2, 2, 2) * vol; K(m * m_ndim + 1, n * m_ndim + 0) += B(m, 1, 1, 0) * C(1, 1, 2, 0) * B(n, 0, 2, 2) * vol; K(m * m_ndim + 1, n * m_ndim + 1) += B(m, 1, 1, 0) * C(1, 1, 0, 2) * B(n, 2, 0, 0) * vol; K(m * m_ndim + 0, n * m_ndim + 1) += B(m, 2, 2, 2) * C(2, 2, 0, 0) * B(n, 0, 0, 0) * vol; K(m * m_ndim + 0, n * m_ndim + 1) += B(m, 2, 2, 2) * C(2, 2, 1, 1) * B(n, 1, 1, 0) * vol; K(m * m_ndim + 0, n * m_ndim + 0) += B(m, 2, 2, 2) * C(2, 2, 2, 2) * B(n, 2, 2, 2) * vol; K(m * m_ndim + 0, n * m_ndim + 0) += B(m, 2, 2, 2) * C(2, 2, 2, 0) * B(n, 0, 2, 2) * vol; K(m * m_ndim + 0, n * m_ndim + 1) += B(m, 2, 2, 2) * C(2, 2, 0, 2) * B(n, 2, 0, 0) * vol; K(m * m_ndim + 0, n * m_ndim + 1) += B(m, 0, 2, 2) * C(0, 2, 0, 0) * B(n, 0, 0, 0) * vol; K(m * m_ndim + 0, n * m_ndim + 1) += B(m, 0, 2, 2) * C(0, 2, 1, 1) * B(n, 1, 1, 0) * vol; K(m * m_ndim + 0, n * m_ndim + 0) += B(m, 0, 2, 2) * C(0, 2, 2, 2) * B(n, 2, 2, 2) * vol; K(m * m_ndim + 0, n * m_ndim + 0) += B(m, 0, 2, 2) * C(0, 2, 2, 0) * B(n, 0, 2, 2) * vol; K(m * m_ndim + 0, n * m_ndim + 1) += B(m, 0, 2, 2) * C(0, 2, 0, 2) * B(n, 2, 0, 0) * vol; K(m * m_ndim + 1, n * m_ndim + 1) += B(m, 2, 0, 0) * C(2, 0, 0, 0) * B(n, 0, 0, 0) * vol; K(m * m_ndim + 1, n * m_ndim + 1) += B(m, 2, 0, 0) * C(2, 0, 1, 1) * B(n, 1, 1, 0) * vol; K(m * m_ndim + 1, n * m_ndim + 0) += B(m, 2, 0, 0) * C(2, 0, 2, 2) * B(n, 2, 2, 2) * vol; K(m * m_ndim + 1, n * m_ndim + 0) += B(m, 2, 0, 0) * C(2, 0, 2, 0) * B(n, 0, 2, 2) * vol; K(m * m_ndim + 1, n * m_ndim + 1) += B(m, 2, 0, 0) * C(2, 0, 0, 2) * B(n, 2, 0, 0) * vol; } } } } } -inline xt::xtensor QuadratureAxisymmetric::DV() const +inline xt::xtensor QuadratureAxisymmetric::DV() const { - xt::xtensor out = xt::empty({m_nelem, m_nip}); + xt::xtensor out = xt::empty({m_nelem, m_nip}); this->dV(out); return out; } inline xt::xarray QuadratureAxisymmetric::DV(size_t rank) const { std::vector shape = {m_nelem, m_nip}; for (size_t i = 0; i < rank; ++i) { shape.push_back(static_cast(m_tdim)); } xt::xarray out = xt::empty(shape); this->dV(out); return out; } -inline xt::xtensor -QuadratureAxisymmetric::GradN_vector(const xt::xtensor& elemvec) const +inline xt::xtensor +QuadratureAxisymmetric::GradN_vector(const xt::xtensor& elemvec) const { - xt::xtensor qtensor = xt::empty({m_nelem, m_nip, m_tdim, m_tdim}); + xt::xtensor qtensor = xt::empty({m_nelem, m_nip, m_tdim, m_tdim}); this->gradN_vector(elemvec, qtensor); return qtensor; } -inline xt::xtensor -QuadratureAxisymmetric::GradN_vector_T(const xt::xtensor& elemvec) const +inline xt::xtensor +QuadratureAxisymmetric::GradN_vector_T(const xt::xtensor& elemvec) const { - xt::xtensor qtensor = xt::empty({m_nelem, m_nip, m_tdim, m_tdim}); + xt::xtensor qtensor = xt::empty({m_nelem, m_nip, m_tdim, m_tdim}); this->gradN_vector_T(elemvec, qtensor); return qtensor; } -inline xt::xtensor -QuadratureAxisymmetric::SymGradN_vector(const xt::xtensor& elemvec) const +inline xt::xtensor +QuadratureAxisymmetric::SymGradN_vector(const xt::xtensor& elemvec) const { - xt::xtensor qtensor = xt::empty({m_nelem, m_nip, m_tdim, m_tdim}); + xt::xtensor qtensor = xt::empty({m_nelem, m_nip, m_tdim, m_tdim}); this->symGradN_vector(elemvec, qtensor); return qtensor; } -inline xt::xtensor -QuadratureAxisymmetric::Int_N_scalar_NT_dV(const xt::xtensor& qscalar) const +inline xt::xtensor +QuadratureAxisymmetric::Int_N_scalar_NT_dV(const xt::xtensor& qscalar) const { - xt::xtensor elemmat = xt::empty({m_nelem, m_nne * m_ndim, m_nne * m_ndim}); + xt::xtensor elemmat = xt::empty({m_nelem, m_nne * m_ndim, m_nne * m_ndim}); this->int_N_scalar_NT_dV(qscalar, elemmat); return elemmat; } -inline xt::xtensor -QuadratureAxisymmetric::Int_gradN_dot_tensor2_dV(const xt::xtensor& qtensor) const +inline xt::xtensor +QuadratureAxisymmetric::Int_gradN_dot_tensor2_dV(const xt::xtensor& qtensor) const { - xt::xtensor elemvec = xt::empty({m_nelem, m_nne, m_ndim}); + xt::xtensor elemvec = xt::empty({m_nelem, m_nne, m_ndim}); this->int_gradN_dot_tensor2_dV(qtensor, elemvec); return elemvec; } -inline xt::xtensor QuadratureAxisymmetric::Int_gradN_dot_tensor4_dot_gradNT_dV( - const xt::xtensor& qtensor) const +inline xt::xtensor QuadratureAxisymmetric::Int_gradN_dot_tensor4_dot_gradNT_dV( + const xt::xtensor& qtensor) const { - xt::xtensor elemmat = xt::empty({m_nelem, m_ndim * m_nne, m_ndim * m_nne}); + xt::xtensor elemmat = xt::empty({m_nelem, m_ndim * m_nne, m_ndim * m_nne}); this->int_gradN_dot_tensor4_dot_gradNT_dV(qtensor, elemmat); return elemmat; } } // namespace Quad4 } // namespace Element } // namespace GooseFEM #endif diff --git a/include/GooseFEM/ElementQuad4Planar.h b/include/GooseFEM/ElementQuad4Planar.h index 95d9c4d..8aa9608 100644 --- a/include/GooseFEM/ElementQuad4Planar.h +++ b/include/GooseFEM/ElementQuad4Planar.h @@ -1,133 +1,122 @@ /* (c - GPLv3) T.W.J. de Geus (Tom) | tom@geus.me | www.geus.me | github.com/tdegeus/GooseFEM */ #ifndef GOOSEFEM_ELEMENTQUAD4PLANAR_H #define GOOSEFEM_ELEMENTQUAD4PLANAR_H #include "config.h" namespace GooseFEM { namespace Element { namespace Quad4 { class QuadraturePlanar { public: // Fixed dimensions: // ndim = 2 - number of dimensions // nne = 4 - number of nodes per element // tdim = 3 - number of dimensions of tensors // // Naming convention: // "elemmat" - matrices stored per element - [nelem, nne*ndim, nne*ndim] // "elemvec" - nodal vectors stored per element - [nelem, nne, ndim] // "qtensor" - integration point tensor - [nelem, nip, tdim, tdim] // "qscalar" - integration point scalar - [nelem, nip] // Constructor: integration point coordinates and weights are optional (default: Gauss) QuadraturePlanar() = default; - QuadraturePlanar(const xt::xtensor& x, double thick = 1.0); + QuadraturePlanar(const xt::xtensor& x, double thick = 1.0); QuadraturePlanar( - const xt::xtensor& x, - const xt::xtensor& xi, - const xt::xtensor& w, + const xt::xtensor& x, + const xt::xtensor& xi, + const xt::xtensor& w, double thick = 1.0); // Update the nodal positions (shape of "x" should match the earlier definition) - void update_x(const xt::xtensor& x); + void update_x(const xt::xtensor& x); // Return dimensions size_t nelem() const; // number of elements size_t nne() const; // number of nodes per element size_t ndim() const; // number of dimension size_t nip() const; // number of integration points // Return shape function gradients - xt::xtensor GradN() const; + xt::xtensor GradN() const; // Return integration volume - void dV(xt::xtensor& qscalar) const; - void dV(xt::xtensor& qtensor) const; // same volume for all tensor components - void dV(xt::xarray& qtensor) const; // same volume for all tensor components + void dV(xt::xtensor& qscalar) const; + void dV(xt::xtensor& qtensor) const; // same volume for all tensor components + void dV(xt::xarray& qtensor) const; // same volume for all tensor components // Dyadic product (and its transpose and symmetric part) // qtensor(i,j) += dNdx(m,i) * elemvec(m,j) - void gradN_vector( - const xt::xtensor& elemvec, - xt::xtensor& qtensor) const; - - void gradN_vector_T( - const xt::xtensor& elemvec, - xt::xtensor& qtensor) const; - - void symGradN_vector( - const xt::xtensor& elemvec, - xt::xtensor& qtensor) const; + void gradN_vector(const xt::xtensor& elemvec, xt::xtensor& qtensor) const; + void gradN_vector_T(const xt::xtensor& elemvec, xt::xtensor& qtensor) const; + void symGradN_vector(const xt::xtensor& elemvec, xt::xtensor& qtensor) const; // Integral of the scalar product // elemmat(m*ndim+i,n*ndim+i) += N(m) * qscalar * N(n) * dV void int_N_scalar_NT_dV( - const xt::xtensor& qscalar, - xt::xtensor& elemmat) const; + const xt::xtensor& qscalar, xt::xtensor& elemmat) const; // Integral of the dot product // elemvec(m,j) += dNdx(m,i) * qtensor(i,j) * dV void int_gradN_dot_tensor2_dV( - const xt::xtensor& qtensor, - xt::xtensor& elemvec) const; + const xt::xtensor& qtensor, xt::xtensor& elemvec) const; // Integral of the dot product // elemmat(m*2+j, n*2+k) += dNdx(m,i) * qtensor(i,j,k,l) * dNdx(n,l) * dV void int_gradN_dot_tensor4_dot_gradNT_dV( - const xt::xtensor& qtensor, - xt::xtensor& elemmat) const; + const xt::xtensor& qtensor, xt::xtensor& elemmat) const; // Auto-allocation of the functions above - xt::xtensor DV() const; + xt::xtensor DV() const; xt::xarray DV(size_t rank) const; - xt::xtensor GradN_vector(const xt::xtensor& elemvec) const; - xt::xtensor GradN_vector_T(const xt::xtensor& elemvec) const; - xt::xtensor SymGradN_vector(const xt::xtensor& elemvec) const; - xt::xtensor Int_N_scalar_NT_dV(const xt::xtensor& qscalar) const; - xt::xtensor Int_gradN_dot_tensor2_dV(const xt::xtensor& qtensor) const; - xt::xtensor Int_gradN_dot_tensor4_dot_gradNT_dV( - const xt::xtensor& qtensor) const; + xt::xtensor GradN_vector(const xt::xtensor& elemvec) const; + xt::xtensor GradN_vector_T(const xt::xtensor& elemvec) const; + xt::xtensor SymGradN_vector(const xt::xtensor& elemvec) const; + xt::xtensor Int_N_scalar_NT_dV(const xt::xtensor& qscalar) const; + xt::xtensor Int_gradN_dot_tensor2_dV(const xt::xtensor& qtensor) const; + xt::xtensor Int_gradN_dot_tensor4_dot_gradNT_dV( + const xt::xtensor& qtensor) const; private: // Compute "vol" and "dNdx" based on current "x" void compute_dN(); private: // Dimensions (flexible) size_t m_nelem; // number of elements size_t m_nip; // number of integration points // Dimensions (fixed for this element type) static const size_t m_nne = 4; // number of nodes per element static const size_t m_ndim = 2; // number of dimensions static const size_t m_tdim = 3; // number of dimensions of tensors // Data arrays - xt::xtensor m_x; // nodal positions stored per element [nelem, nne, ndim] - xt::xtensor m_w; // weight of each integration point [nip] - xt::xtensor m_xi; // local coordinate of each integration point [nip, ndim] - xt::xtensor m_N; // shape functions [nip, nne] - xt::xtensor m_dNxi; // shape function grad. wrt local coor. [nip, nne, ndim] - xt::xtensor m_dNx; // shape function grad. wrt global coor. [nelem, nip, nne, ndim] - xt::xtensor m_vol; // integration point volume [nelem, nip] + xt::xtensor m_x; // nodal positions stored per element [nelem, nne, ndim] + xt::xtensor m_w; // weight of each integration point [nip] + xt::xtensor m_xi; // local coordinate of each integration point [nip, ndim] + xt::xtensor m_N; // shape functions [nip, nne] + xt::xtensor m_dNxi; // shape function grad. wrt local coor. [nip, nne, ndim] + xt::xtensor m_dNx; // shape function grad. wrt global coor. [nelem, nip, nne, ndim] + xt::xtensor m_vol; // integration point volume [nelem, nip] // Thickness double m_thick; }; } // namespace Quad4 } // namespace Element } // namespace GooseFEM #include "ElementQuad4Planar.hpp" #endif diff --git a/include/GooseFEM/ElementQuad4Planar.hpp b/include/GooseFEM/ElementQuad4Planar.hpp index 97ec69b..f9d3a88 100644 --- a/include/GooseFEM/ElementQuad4Planar.hpp +++ b/include/GooseFEM/ElementQuad4Planar.hpp @@ -1,513 +1,465 @@ /* (c - GPLv3) T.W.J. de Geus (Tom) | tom@geus.me | www.geus.me | github.com/tdegeus/GooseFEM */ #ifndef GOOSEFEM_ELEMENTQUAD4PLANAR_HPP #define GOOSEFEM_ELEMENTQUAD4PLANAR_HPP #include "ElementQuad4Planar.h" namespace GooseFEM { namespace Element { namespace Quad4 { -inline QuadraturePlanar::QuadraturePlanar(const xt::xtensor& x, double thick) +inline QuadraturePlanar::QuadraturePlanar(const xt::xtensor& x, double thick) : QuadraturePlanar(x, Gauss::xi(), Gauss::w(), thick) { } inline QuadraturePlanar::QuadraturePlanar( - const xt::xtensor& x, - const xt::xtensor& xi, - const xt::xtensor& w, + const xt::xtensor& x, + const xt::xtensor& xi, + const xt::xtensor& w, double thick) : m_x(x), m_w(w), m_xi(xi), m_thick(thick) { GOOSEFEM_ASSERT(m_x.shape(1) == m_nne); GOOSEFEM_ASSERT(m_x.shape(2) == m_ndim); m_nelem = m_x.shape(0); m_nip = m_w.size(); GOOSEFEM_ASSERT(m_xi.shape(0) == m_nip); GOOSEFEM_ASSERT(m_xi.shape(1) == m_ndim); GOOSEFEM_ASSERT(m_w.size() == m_nip); m_N = xt::empty({m_nip, m_nne}); m_dNxi = xt::empty({m_nip, m_nne, m_ndim}); m_dNx = xt::empty({m_nelem, m_nip, m_nne, m_ndim}); m_vol = xt::empty({m_nelem, m_nip}); for (size_t q = 0; q < m_nip; ++q) { m_N(q, 0) = 0.25 * (1.0 - m_xi(q, 0)) * (1.0 - m_xi(q, 1)); m_N(q, 1) = 0.25 * (1.0 + m_xi(q, 0)) * (1.0 - m_xi(q, 1)); m_N(q, 2) = 0.25 * (1.0 + m_xi(q, 0)) * (1.0 + m_xi(q, 1)); m_N(q, 3) = 0.25 * (1.0 - m_xi(q, 0)) * (1.0 + m_xi(q, 1)); } for (size_t q = 0; q < m_nip; ++q) { // - dN / dxi_0 m_dNxi(q, 0, 0) = -0.25 * (1.0 - m_xi(q, 1)); m_dNxi(q, 1, 0) = +0.25 * (1.0 - m_xi(q, 1)); m_dNxi(q, 2, 0) = +0.25 * (1.0 + m_xi(q, 1)); m_dNxi(q, 3, 0) = -0.25 * (1.0 + m_xi(q, 1)); // - dN / dxi_1 m_dNxi(q, 0, 1) = -0.25 * (1.0 - m_xi(q, 0)); m_dNxi(q, 1, 1) = -0.25 * (1.0 + m_xi(q, 0)); m_dNxi(q, 2, 1) = +0.25 * (1.0 + m_xi(q, 0)); m_dNxi(q, 3, 1) = +0.25 * (1.0 - m_xi(q, 0)); } compute_dN(); } inline size_t QuadraturePlanar::nelem() const { return m_nelem; } inline size_t QuadraturePlanar::nne() const { return m_nne; } inline size_t QuadraturePlanar::ndim() const { return m_ndim; } inline size_t QuadraturePlanar::nip() const { return m_nip; } -inline xt::xtensor QuadraturePlanar::GradN() const +inline xt::xtensor QuadraturePlanar::GradN() const { return m_dNx; } -inline void QuadraturePlanar::dV(xt::xtensor& qscalar) const +inline void QuadraturePlanar::dV(xt::xtensor& qscalar) const { GOOSEFEM_ASSERT( qscalar.shape() == std::decay_t::shape_type({m_nelem, m_nip})); #pragma omp parallel for for (size_t e = 0; e < m_nelem; ++e) { for (size_t q = 0; q < m_nip; ++q) { qscalar(e, q) = m_vol(e, q); } } } -inline void QuadraturePlanar::dV(xt::xtensor& qtensor) const +inline void QuadraturePlanar::dV(xt::xtensor& qtensor) const { GOOSEFEM_ASSERT( qtensor.shape() == std::decay_t::shape_type({m_nelem, m_nip, m_tdim, m_tdim})); #pragma omp parallel for for (size_t e = 0; e < m_nelem; ++e) { for (size_t q = 0; q < m_nip; ++q) { for (size_t i = 0; i < m_tdim; ++i) { for (size_t j = 0; j < m_tdim; ++j) { qtensor(e, q, i, j) = m_vol(e, q); } } } } } inline void QuadraturePlanar::dV(xt::xarray& qtensor) const { GOOSEFEM_ASSERT(qtensor.shape(0) == m_nelem); GOOSEFEM_ASSERT(qtensor.shape(1) == m_nip); xt::dynamic_shape strides = {static_cast(m_vol.strides()[0]), static_cast(m_vol.strides()[1])}; for (size_t i = 2; i < qtensor.shape().size(); ++i) { strides.push_back(0); } qtensor = xt::strided_view(m_vol, qtensor.shape(), std::move(strides), 0ul, xt::layout_type::dynamic); } -inline void QuadraturePlanar::update_x(const xt::xtensor& x) +inline void QuadraturePlanar::update_x(const xt::xtensor& x) { GOOSEFEM_ASSERT(x.shape() == m_x.shape()); xt::noalias(m_x) = x; compute_dN(); } inline void QuadraturePlanar::compute_dN() { #pragma omp parallel { xt::xtensor_fixed> J; xt::xtensor_fixed> Jinv; #pragma omp for for (size_t e = 0; e < m_nelem; ++e) { auto x = xt::adapt(&m_x(e, 0, 0), xt::xshape()); for (size_t q = 0; q < m_nip; ++q) { auto dNxi = xt::adapt(&m_dNxi(q, 0, 0), xt::xshape()); auto dNx = xt::adapt(&m_dNx(e, q, 0, 0), xt::xshape()); // J(i,j) += dNxi(m,i) * x(m,j); - J(0, 0) - = dNxi(0, 0) * x(0, 0) - + dNxi(1, 0) * x(1, 0) - + dNxi(2, 0) * x(2, 0) - + dNxi(3, 0) * x(3, 0); - J(0, 1) - = dNxi(0, 0) * x(0, 1) - + dNxi(1, 0) * x(1, 1) - + dNxi(2, 0) * x(2, 1) - + dNxi(3, 0) * x(3, 1); - J(1, 0) - = dNxi(0, 1) * x(0, 0) - + dNxi(1, 1) * x(1, 0) - + dNxi(2, 1) * x(2, 0) - + dNxi(3, 1) * x(3, 0); - J(1, 1) - = dNxi(0, 1) * x(0, 1) - + dNxi(1, 1) * x(1, 1) - + dNxi(2, 1) * x(2, 1) - + dNxi(3, 1) * x(3, 1); + J(0, 0) = dNxi(0, 0) * x(0, 0) + dNxi(1, 0) * x(1, 0) + dNxi(2, 0) * x(2, 0) + + dNxi(3, 0) * x(3, 0); + J(0, 1) = dNxi(0, 0) * x(0, 1) + dNxi(1, 0) * x(1, 1) + dNxi(2, 0) * x(2, 1) + + dNxi(3, 0) * x(3, 1); + J(1, 0) = dNxi(0, 1) * x(0, 0) + dNxi(1, 1) * x(1, 0) + dNxi(2, 1) * x(2, 0) + + dNxi(3, 1) * x(3, 0); + J(1, 1) = dNxi(0, 1) * x(0, 1) + dNxi(1, 1) * x(1, 1) + dNxi(2, 1) * x(2, 1) + + dNxi(3, 1) * x(3, 1); double Jdet = inv(J, Jinv); // dNx(m,i) += Jinv(i,j) * dNxi(m,j); for (size_t m = 0; m < m_nne; ++m) { dNx(m, 0) = Jinv(0, 0) * dNxi(m, 0) + Jinv(0, 1) * dNxi(m, 1); dNx(m, 1) = Jinv(1, 0) * dNxi(m, 0) + Jinv(1, 1) * dNxi(m, 1); } m_vol(e, q) = m_w(q) * Jdet * m_thick; } } } } inline void QuadraturePlanar::gradN_vector( - const xt::xtensor& elemvec, xt::xtensor& qtensor) const + const xt::xtensor& elemvec, xt::xtensor& qtensor) const { GOOSEFEM_ASSERT( elemvec.shape() == std::decay_t::shape_type({m_nelem, m_nne, m_ndim})); GOOSEFEM_ASSERT( qtensor.shape() == std::decay_t::shape_type({m_nelem, m_nip, m_tdim, m_tdim})); qtensor.fill(0.0); #pragma omp parallel for for (size_t e = 0; e < m_nelem; ++e) { auto u = xt::adapt(&elemvec(e, 0, 0), xt::xshape()); for (size_t q = 0; q < m_nip; ++q) { auto dNx = xt::adapt(&m_dNx(e, q, 0, 0), xt::xshape()); auto gradu = xt::adapt(&qtensor(e, q, 0, 0), xt::xshape()); // gradu(i,j) += dNx(m,i) * u(m,j) - gradu(0, 0) - = dNx(0, 0) * u(0, 0) - + dNx(1, 0) * u(1, 0) - + dNx(2, 0) * u(2, 0) - + dNx(3, 0) * u(3, 0); - gradu(0, 1) - = dNx(0, 0) * u(0, 1) - + dNx(1, 0) * u(1, 1) - + dNx(2, 0) * u(2, 1) - + dNx(3, 0) * u(3, 1); - gradu(1, 0) - = dNx(0, 1) * u(0, 0) - + dNx(1, 1) * u(1, 0) - + dNx(2, 1) * u(2, 0) - + dNx(3, 1) * u(3, 0); - gradu(1, 1) - = dNx(0, 1) * u(0, 1) - + dNx(1, 1) * u(1, 1) - + dNx(2, 1) * u(2, 1) - + dNx(3, 1) * u(3, 1); + gradu(0, 0) = dNx(0, 0) * u(0, 0) + dNx(1, 0) * u(1, 0) + dNx(2, 0) * u(2, 0) + + dNx(3, 0) * u(3, 0); + gradu(0, 1) = dNx(0, 0) * u(0, 1) + dNx(1, 0) * u(1, 1) + dNx(2, 0) * u(2, 1) + + dNx(3, 0) * u(3, 1); + gradu(1, 0) = dNx(0, 1) * u(0, 0) + dNx(1, 1) * u(1, 0) + dNx(2, 1) * u(2, 0) + + dNx(3, 1) * u(3, 0); + gradu(1, 1) = dNx(0, 1) * u(0, 1) + dNx(1, 1) * u(1, 1) + dNx(2, 1) * u(2, 1) + + dNx(3, 1) * u(3, 1); } } } inline void QuadraturePlanar::gradN_vector_T( - const xt::xtensor& elemvec, xt::xtensor& qtensor) const + const xt::xtensor& elemvec, xt::xtensor& qtensor) const { GOOSEFEM_ASSERT( elemvec.shape() == std::decay_t::shape_type({m_nelem, m_nne, m_ndim})); GOOSEFEM_ASSERT( qtensor.shape() == std::decay_t::shape_type({m_nelem, m_nip, m_tdim, m_tdim})); qtensor.fill(0.0); #pragma omp parallel for for (size_t e = 0; e < m_nelem; ++e) { auto u = xt::adapt(&elemvec(e, 0, 0), xt::xshape()); for (size_t q = 0; q < m_nip; ++q) { auto dNx = xt::adapt(&m_dNx(e, q, 0, 0), xt::xshape()); auto gradu = xt::adapt(&qtensor(e, q, 0, 0), xt::xshape()); // gradu(j,i) += dNx(m,i) * u(m,j) - gradu(0, 0) - = dNx(0, 0) * u(0, 0) - + dNx(1, 0) * u(1, 0) - + dNx(2, 0) * u(2, 0) - + dNx(3, 0) * u(3, 0); - gradu(1, 0) - = dNx(0, 0) * u(0, 1) - + dNx(1, 0) * u(1, 1) - + dNx(2, 0) * u(2, 1) - + dNx(3, 0) * u(3, 1); - gradu(0, 1) - = dNx(0, 1) * u(0, 0) - + dNx(1, 1) * u(1, 0) - + dNx(2, 1) * u(2, 0) - + dNx(3, 1) * u(3, 0); - gradu(1, 1) - = dNx(0, 1) * u(0, 1) - + dNx(1, 1) * u(1, 1) - + dNx(2, 1) * u(2, 1) - + dNx(3, 1) * u(3, 1); + gradu(0, 0) = dNx(0, 0) * u(0, 0) + dNx(1, 0) * u(1, 0) + dNx(2, 0) * u(2, 0) + + dNx(3, 0) * u(3, 0); + gradu(1, 0) = dNx(0, 0) * u(0, 1) + dNx(1, 0) * u(1, 1) + dNx(2, 0) * u(2, 1) + + dNx(3, 0) * u(3, 1); + gradu(0, 1) = dNx(0, 1) * u(0, 0) + dNx(1, 1) * u(1, 0) + dNx(2, 1) * u(2, 0) + + dNx(3, 1) * u(3, 0); + gradu(1, 1) = dNx(0, 1) * u(0, 1) + dNx(1, 1) * u(1, 1) + dNx(2, 1) * u(2, 1) + + dNx(3, 1) * u(3, 1); } } } inline void QuadraturePlanar::symGradN_vector( - const xt::xtensor& elemvec, xt::xtensor& qtensor) const + const xt::xtensor& elemvec, xt::xtensor& qtensor) const { GOOSEFEM_ASSERT( elemvec.shape() == std::decay_t::shape_type({m_nelem, m_nne, m_ndim})); GOOSEFEM_ASSERT( qtensor.shape() == std::decay_t::shape_type({m_nelem, m_nip, m_tdim, m_tdim})); qtensor.fill(0.0); #pragma omp parallel for for (size_t e = 0; e < m_nelem; ++e) { auto u = xt::adapt(&elemvec(e, 0, 0), xt::xshape()); for (size_t q = 0; q < m_nip; ++q) { auto dNx = xt::adapt(&m_dNx(e, q, 0, 0), xt::xshape()); auto eps = xt::adapt(&qtensor(e, q, 0, 0), xt::xshape()); // gradu(i,j) += dNx(m,i) * u(m,j) // eps(j,i) = 0.5 * (gradu(i,j) + gradu(j,i)) - eps(0, 0) - = dNx(0, 0) * u(0, 0) - + dNx(1, 0) * u(1, 0) - + dNx(2, 0) * u(2, 0) - + dNx(3, 0) * u(3, 0); - eps(1, 1) - = dNx(0, 1) * u(0, 1) - + dNx(1, 1) * u(1, 1) - + dNx(2, 1) * u(2, 1) - + dNx(3, 1) * u(3, 1); - eps(0, 1) = 0.5 * - ( dNx(0, 0) * u(0, 1) - + dNx(1, 0) * u(1, 1) - + dNx(2, 0) * u(2, 1) - + dNx(3, 0) * u(3, 1) - + dNx(0, 1) * u(0, 0) - + dNx(1, 1) * u(1, 0) - + dNx(2, 1) * u(2, 0) - + dNx(3, 1) * u(3, 0)); + eps(0, 0) = dNx(0, 0) * u(0, 0) + dNx(1, 0) * u(1, 0) + dNx(2, 0) * u(2, 0) + + dNx(3, 0) * u(3, 0); + eps(1, 1) = dNx(0, 1) * u(0, 1) + dNx(1, 1) * u(1, 1) + dNx(2, 1) * u(2, 1) + + dNx(3, 1) * u(3, 1); + eps(0, 1) = 0.5 * (dNx(0, 0) * u(0, 1) + dNx(1, 0) * u(1, 1) + dNx(2, 0) * u(2, 1) + + dNx(3, 0) * u(3, 1) + dNx(0, 1) * u(0, 0) + dNx(1, 1) * u(1, 0) + + dNx(2, 1) * u(2, 0) + dNx(3, 1) * u(3, 0)); eps(1, 0) = eps(0, 1); } } } inline void QuadraturePlanar::int_N_scalar_NT_dV( - const xt::xtensor& qscalar, xt::xtensor& elemmat) const + const xt::xtensor& qscalar, xt::xtensor& elemmat) const { GOOSEFEM_ASSERT( qscalar.shape() == std::decay_t::shape_type({m_nelem, m_nip})); GOOSEFEM_ASSERT( elemmat.shape() == std::decay_t::shape_type({m_nelem, m_nne * m_ndim, m_nne * m_ndim})); elemmat.fill(0.0); #pragma omp parallel for for (size_t e = 0; e < m_nelem; ++e) { auto M = xt::adapt(&elemmat(e, 0, 0), xt::xshape()); for (size_t q = 0; q < m_nip; ++q) { auto N = xt::adapt(&m_N(q, 0), xt::xshape()); auto& vol = m_vol(e, q); auto& rho = qscalar(e, q); // M(m*ndim+i,n*ndim+i) += N(m) * scalar * N(n) * dV for (size_t m = 0; m < m_nne; ++m) { for (size_t n = 0; n < m_nne; ++n) { M(m * m_ndim + 0, n * m_ndim + 0) += N(m) * rho * N(n) * vol; M(m * m_ndim + 1, n * m_ndim + 1) += N(m) * rho * N(n) * vol; } } } } } inline void QuadraturePlanar::int_gradN_dot_tensor2_dV( - const xt::xtensor& qtensor, xt::xtensor& elemvec) const + const xt::xtensor& qtensor, xt::xtensor& elemvec) const { GOOSEFEM_ASSERT( qtensor.shape() == std::decay_t::shape_type({m_nelem, m_nip, m_tdim, m_tdim})); GOOSEFEM_ASSERT( elemvec.shape() == std::decay_t::shape_type({m_nelem, m_nne, m_ndim})); elemvec.fill(0.0); #pragma omp parallel for for (size_t e = 0; e < m_nelem; ++e) { auto f = xt::adapt(&elemvec(e, 0, 0), xt::xshape()); for (size_t q = 0; q < m_nip; ++q) { auto dNx = xt::adapt(&m_dNx(e, q, 0, 0), xt::xshape()); auto sig = xt::adapt(&qtensor(e, q, 0, 0), xt::xshape()); auto& vol = m_vol(e, q); for (size_t m = 0; m < m_nne; ++m) { f(m, 0) += (dNx(m, 0) * sig(0, 0) + dNx(m, 1) * sig(1, 0)) * vol; f(m, 1) += (dNx(m, 0) * sig(0, 1) + dNx(m, 1) * sig(1, 1)) * vol; } } } } inline void QuadraturePlanar::int_gradN_dot_tensor4_dot_gradNT_dV( - const xt::xtensor& qtensor, xt::xtensor& elemmat) const + const xt::xtensor& qtensor, xt::xtensor& elemmat) const { GOOSEFEM_ASSERT( - qtensor.shape() == - std::decay_t::shape_type({m_nelem,m_nip,m_tdim,m_tdim,m_tdim,m_tdim})); + qtensor.shape() == std::decay_t::shape_type( + {m_nelem, m_nip, m_tdim, m_tdim, m_tdim, m_tdim})); GOOSEFEM_ASSERT( elemmat.shape() == std::decay_t::shape_type({m_nelem, m_nne * m_ndim, m_nne * m_ndim})); elemmat.fill(0.0); #pragma omp parallel for for (size_t e = 0; e < m_nelem; ++e) { auto K = xt::adapt(&elemmat(e, 0, 0), xt::xshape()); for (size_t q = 0; q < m_nip; ++q) { - auto dNx = xt::adapt(&m_dNx(e,q,0,0), xt::xshape()); - auto C = xt::adapt(&qtensor(e,q,0,0,0,0), xt::xshape()); + auto dNx = xt::adapt(&m_dNx(e, q, 0, 0), xt::xshape()); + auto C = xt::adapt(&qtensor(e, q, 0, 0, 0, 0), xt::xshape()); auto& vol = m_vol(e, q); for (size_t m = 0; m < m_nne; ++m) { for (size_t n = 0; n < m_nne; ++n) { for (size_t i = 0; i < m_ndim; ++i) { for (size_t j = 0; j < m_ndim; ++j) { for (size_t k = 0; k < m_ndim; ++k) { for (size_t l = 0; l < m_ndim; ++l) { K(m * m_ndim + j, n * m_ndim + k) += dNx(m, i) * C(i, j, k, l) * dNx(n, l) * vol; } } } } } } } } } -inline xt::xtensor QuadraturePlanar::DV() const +inline xt::xtensor QuadraturePlanar::DV() const { - xt::xtensor out = xt::empty({m_nelem, m_nip}); + xt::xtensor out = xt::empty({m_nelem, m_nip}); this->dV(out); return out; } inline xt::xarray QuadraturePlanar::DV(size_t rank) const { std::vector shape = {m_nelem, m_nip}; for (size_t i = 0; i < rank; ++i) { shape.push_back(static_cast(m_tdim)); } xt::xarray out = xt::empty(shape); this->dV(out); return out; } -inline xt::xtensor -QuadraturePlanar::GradN_vector(const xt::xtensor& elemvec) const +inline xt::xtensor +QuadraturePlanar::GradN_vector(const xt::xtensor& elemvec) const { - xt::xtensor qtensor = xt::empty({m_nelem, m_nip, m_tdim, m_tdim}); + xt::xtensor qtensor = xt::empty({m_nelem, m_nip, m_tdim, m_tdim}); this->gradN_vector(elemvec, qtensor); return qtensor; } -inline xt::xtensor -QuadraturePlanar::GradN_vector_T(const xt::xtensor& elemvec) const +inline xt::xtensor +QuadraturePlanar::GradN_vector_T(const xt::xtensor& elemvec) const { - xt::xtensor qtensor = xt::empty({m_nelem, m_nip, m_tdim, m_tdim}); + xt::xtensor qtensor = xt::empty({m_nelem, m_nip, m_tdim, m_tdim}); this->gradN_vector_T(elemvec, qtensor); return qtensor; } -inline xt::xtensor -QuadraturePlanar::SymGradN_vector(const xt::xtensor& elemvec) const +inline xt::xtensor +QuadraturePlanar::SymGradN_vector(const xt::xtensor& elemvec) const { - xt::xtensor qtensor = xt::empty({m_nelem, m_nip, m_tdim, m_tdim}); + xt::xtensor qtensor = xt::empty({m_nelem, m_nip, m_tdim, m_tdim}); this->symGradN_vector(elemvec, qtensor); return qtensor; } -inline xt::xtensor -QuadraturePlanar::Int_N_scalar_NT_dV(const xt::xtensor& qscalar) const +inline xt::xtensor +QuadraturePlanar::Int_N_scalar_NT_dV(const xt::xtensor& qscalar) const { - xt::xtensor elemmat = xt::empty({m_nelem, m_nne * m_ndim, m_nne * m_ndim}); + xt::xtensor elemmat = xt::empty({m_nelem, m_nne * m_ndim, m_nne * m_ndim}); this->int_N_scalar_NT_dV(qscalar, elemmat); return elemmat; } -inline xt::xtensor -QuadraturePlanar::Int_gradN_dot_tensor2_dV(const xt::xtensor& qtensor) const +inline xt::xtensor +QuadraturePlanar::Int_gradN_dot_tensor2_dV(const xt::xtensor& qtensor) const { - xt::xtensor elemvec = xt::empty({m_nelem, m_nne, m_ndim}); + xt::xtensor elemvec = xt::empty({m_nelem, m_nne, m_ndim}); this->int_gradN_dot_tensor2_dV(qtensor, elemvec); return elemvec; } -inline xt::xtensor -QuadraturePlanar::Int_gradN_dot_tensor4_dot_gradNT_dV(const xt::xtensor& qtensor) const +inline xt::xtensor +QuadraturePlanar::Int_gradN_dot_tensor4_dot_gradNT_dV(const xt::xtensor& qtensor) const { - xt::xtensor elemmat = xt::empty({m_nelem, m_ndim * m_nne, m_ndim * m_nne}); + xt::xtensor elemmat = xt::empty({m_nelem, m_ndim * m_nne, m_ndim * m_nne}); this->int_gradN_dot_tensor4_dot_gradNT_dV(qtensor, elemmat); return elemmat; } } // namespace Quad4 } // namespace Element } // namespace GooseFEM #endif diff --git a/include/GooseFEM/GooseFEM.h b/include/GooseFEM/GooseFEM.h index 48c53a3..30c1bfd 100644 --- a/include/GooseFEM/GooseFEM.h +++ b/include/GooseFEM/GooseFEM.h @@ -1,37 +1,37 @@ /* (c - GPLv3) T.W.J. de Geus (Tom) | tom@geus.me | www.geus.me | github.com/tdegeus/GooseFEM */ #ifndef GOOSEFEM_H #define GOOSEFEM_H #ifdef EIGEN_WORLD_VERSION - #define GOOSEFEM_EIGEN +#define GOOSEFEM_EIGEN #endif #include "Element.h" #include "ElementHex8.h" #include "ElementQuad4.h" #include "ElementQuad4Axisymmetric.h" #include "ElementQuad4Planar.h" #include "Iterate.h" #include "MatrixDiagonal.h" #include "MatrixDiagonalPartitioned.h" #include "Mesh.h" #include "MeshHex8.h" #include "MeshQuad4.h" #include "MeshTri3.h" #include "Vector.h" #include "VectorPartitioned.h" #ifdef GOOSEFEM_EIGEN #include "Matrix.h" #include "MatrixPartitioned.h" #include "MatrixPartitionedTyings.h" #include "TyingsPeriodic.h" #include "VectorPartitionedTyings.h" #endif #endif diff --git a/include/GooseFEM/Matrix.h b/include/GooseFEM/Matrix.h index db079fe..58efb4a 100644 --- a/include/GooseFEM/Matrix.h +++ b/include/GooseFEM/Matrix.h @@ -1,91 +1,91 @@ /* (c - GPLv3) T.W.J. de Geus (Tom) | tom@geus.me | www.geus.me | github.com/tdegeus/GooseFEM */ #ifndef GOOSEFEM_MATRIX_H #define GOOSEFEM_MATRIX_H #include "config.h" #include #include #include namespace GooseFEM { template >> class Matrix { public: // Constructors Matrix() = default; - Matrix(const xt::xtensor& conn, const xt::xtensor& dofs); + Matrix(const xt::xtensor& conn, const xt::xtensor& dofs); // Dimensions size_t nelem() const; // number of elements size_t nne() const; // number of nodes per element size_t nnode() const; // number of nodes size_t ndim() const; // number of dimensions size_t ndof() const; // number of DOFs // DOF lists - xt::xtensor dofs() const; // DOFs + xt::xtensor dofs() const; // DOFs // Assemble from matrices stored per element [nelem, nne*ndim, nne*ndim] - void assemble(const xt::xtensor& elemmat); + void assemble(const xt::xtensor& elemmat); // Dot-product: // b_i = A_ij * x_j - void dot(const xt::xtensor& x, xt::xtensor& b) const; - void dot(const xt::xtensor& x, xt::xtensor& b) const; + void dot(const xt::xtensor& x, xt::xtensor& b) const; + void dot(const xt::xtensor& x, xt::xtensor& b) const; // Solve // x_u = A_uu \ ( b_u - A_up * x_p ) - void solve(const xt::xtensor& b, xt::xtensor& x); - void solve(const xt::xtensor& b, xt::xtensor& x); + void solve(const xt::xtensor& b, xt::xtensor& x); + void solve(const xt::xtensor& b, xt::xtensor& x); // Auto-allocation of the functions above - xt::xtensor Dot(const xt::xtensor& x) const; - xt::xtensor Dot(const xt::xtensor& x) const; - xt::xtensor Solve(const xt::xtensor& b); - xt::xtensor Solve(const xt::xtensor& b); + xt::xtensor Dot(const xt::xtensor& x) const; + xt::xtensor Dot(const xt::xtensor& x) const; + xt::xtensor Solve(const xt::xtensor& b); + xt::xtensor Solve(const xt::xtensor& b); private: // The matrix Eigen::SparseMatrix m_A; // Matrix entries std::vector> m_T; // Solver (re-used to solve different RHS) Solver m_solver; // Signal changes to data compare to the last inverse bool m_factor = false; // Bookkeeping - xt::xtensor m_conn; // connectivity [nelem, nne] - xt::xtensor m_dofs; // DOF-numbers per node [nnode, ndim] + xt::xtensor m_conn; // connectivity [nelem, nne] + xt::xtensor m_dofs; // DOF-numbers per node [nnode, ndim] // Dimensions size_t m_nelem; // number of elements size_t m_nne; // number of nodes per element size_t m_nnode; // number of nodes size_t m_ndim; // number of dimensions size_t m_ndof; // number of DOFs // Compute inverse (automatically evaluated by "solve") void factorize(); // Convert arrays (Eigen version of Vector, which contains public functions) - Eigen::VectorXd asDofs(const xt::xtensor& nodevec) const; + Eigen::VectorXd asDofs(const xt::xtensor& nodevec) const; - void asNode(const Eigen::VectorXd& dofval, xt::xtensor& nodevec) const; + void asNode(const Eigen::VectorXd& dofval, xt::xtensor& nodevec) const; }; } // namespace GooseFEM #include "Matrix.hpp" #endif diff --git a/include/GooseFEM/Matrix.hpp b/include/GooseFEM/Matrix.hpp index 9fe5178..e2b9676 100644 --- a/include/GooseFEM/Matrix.hpp +++ b/include/GooseFEM/Matrix.hpp @@ -1,216 +1,216 @@ /* (c - GPLv3) T.W.J. de Geus (Tom) | tom@geus.me | www.geus.me | github.com/tdegeus/GooseFEM */ #ifndef GOOSEFEM_MATRIX_HPP #define GOOSEFEM_MATRIX_HPP #include "Matrix.h" namespace GooseFEM { template inline Matrix::Matrix( - const xt::xtensor& conn, const xt::xtensor& dofs) + const xt::xtensor& conn, const xt::xtensor& dofs) : m_conn(conn), m_dofs(dofs) { m_nelem = m_conn.shape(0); m_nne = m_conn.shape(1); m_nnode = m_dofs.shape(0); m_ndim = m_dofs.shape(1); m_ndof = xt::amax(m_dofs)[0] + 1; m_T.reserve(m_nelem * m_nne * m_ndim * m_nne * m_ndim); m_A.resize(m_ndof, m_ndof); GOOSEFEM_ASSERT(xt::amax(m_conn)[0] + 1 == m_nnode); GOOSEFEM_ASSERT(m_ndof <= m_nnode * m_ndim); } template inline size_t Matrix::nelem() const { return m_nelem; } template inline size_t Matrix::nne() const { return m_nne; } template inline size_t Matrix::nnode() const { return m_nnode; } template inline size_t Matrix::ndim() const { return m_ndim; } template inline size_t Matrix::ndof() const { return m_ndof; } template -inline xt::xtensor Matrix::dofs() const +inline xt::xtensor Matrix::dofs() const { return m_dofs; } template inline void Matrix::factorize() { if (!m_factor) { return; } m_solver.compute(m_A); m_factor = false; } template -inline void Matrix::assemble(const xt::xtensor& elemmat) +inline void Matrix::assemble(const xt::xtensor& elemmat) { GOOSEFEM_ASSERT( elemmat.shape() == std::decay_t::shape_type({m_nelem, m_nne * m_ndim, m_nne * m_ndim})); m_T.clear(); for (size_t e = 0; e < m_nelem; ++e) { for (size_t m = 0; m < m_nne; ++m) { for (size_t i = 0; i < m_ndim; ++i) { for (size_t n = 0; n < m_nne; ++n) { for (size_t j = 0; j < m_ndim; ++j) { m_T.push_back(Eigen::Triplet( m_dofs(m_conn(e, m), i), m_dofs(m_conn(e, n), j), elemmat(e, m * m_ndim + i, n * m_ndim + j))); } } } } } m_A.setFromTriplets(m_T.begin(), m_T.end()); m_factor = true; } template -inline void Matrix::dot(const xt::xtensor& x, xt::xtensor& b) const +inline void Matrix::dot(const xt::xtensor& x, xt::xtensor& b) const { GOOSEFEM_ASSERT(b.shape() == std::decay_t::shape_type({m_nnode, m_ndim})); GOOSEFEM_ASSERT(x.shape() == std::decay_t::shape_type({m_nnode, m_ndim})); Eigen::VectorXd B = m_A * this->asDofs(x); this->asNode(B, b); } template -inline void Matrix::dot(const xt::xtensor& x, xt::xtensor& b) const +inline void Matrix::dot(const xt::xtensor& x, xt::xtensor& b) const { GOOSEFEM_ASSERT(b.size() == m_ndof); GOOSEFEM_ASSERT(x.size() == m_ndof); Eigen::VectorXd B = m_A * Eigen::Map(x.data(), m_ndof); std::copy(B.data(), B.data() + m_ndof, b.begin()); } template -inline void Matrix::solve(const xt::xtensor& b, xt::xtensor& x) +inline void Matrix::solve(const xt::xtensor& b, xt::xtensor& x) { GOOSEFEM_ASSERT(b.shape() == std::decay_t::shape_type({m_nnode, m_ndim})); GOOSEFEM_ASSERT(x.shape() == std::decay_t::shape_type({m_nnode, m_ndim})); this->factorize(); Eigen::VectorXd B = this->asDofs(b); Eigen::VectorXd X = m_solver.solve(B); this->asNode(X, x); } template -inline void Matrix::solve(const xt::xtensor& b, xt::xtensor& x) +inline void Matrix::solve(const xt::xtensor& b, xt::xtensor& x) { GOOSEFEM_ASSERT(b.size() == m_ndof); GOOSEFEM_ASSERT(x.size() == m_ndof); this->factorize(); Eigen::VectorXd X = m_solver.solve(Eigen::Map(b.data(), m_ndof)); std::copy(X.data(), X.data() + m_ndof, x.begin()); } template -inline xt::xtensor Matrix::Dot(const xt::xtensor& x) const +inline xt::xtensor Matrix::Dot(const xt::xtensor& x) const { - xt::xtensor b = xt::empty({m_nnode, m_ndim}); + xt::xtensor b = xt::empty({m_nnode, m_ndim}); this->dot(x, b); return b; } template -inline xt::xtensor Matrix::Dot(const xt::xtensor& x) const +inline xt::xtensor Matrix::Dot(const xt::xtensor& x) const { - xt::xtensor b = xt::empty({m_ndof}); + xt::xtensor b = xt::empty({m_ndof}); this->dot(x, b); return b; } template -inline xt::xtensor Matrix::Solve(const xt::xtensor& b) +inline xt::xtensor Matrix::Solve(const xt::xtensor& b) { - xt::xtensor x = xt::empty({m_nnode, m_ndim}); + xt::xtensor x = xt::empty({m_nnode, m_ndim}); this->solve(b, x); return x; } template -inline xt::xtensor Matrix::Solve(const xt::xtensor& b) +inline xt::xtensor Matrix::Solve(const xt::xtensor& b) { - xt::xtensor x = xt::empty({m_ndof}); + xt::xtensor x = xt::empty({m_ndof}); this->solve(b, x); return x; } template -inline Eigen::VectorXd Matrix::asDofs(const xt::xtensor& nodevec) const +inline Eigen::VectorXd Matrix::asDofs(const xt::xtensor& nodevec) const { assert(nodevec.shape() == std::decay_t::shape_type({m_nnode, m_ndim})); Eigen::VectorXd dofval(m_ndof, 1); #pragma omp parallel for for (size_t m = 0; m < m_nnode; ++m) { for (size_t i = 0; i < m_ndim; ++i) { dofval(m_dofs(m, i)) = nodevec(m, i); } } return dofval; } template inline void -Matrix::asNode(const Eigen::VectorXd& dofval, xt::xtensor& nodevec) const +Matrix::asNode(const Eigen::VectorXd& dofval, xt::xtensor& nodevec) const { assert(static_cast(dofval.size()) == m_ndof); assert(nodevec.shape() == std::decay_t::shape_type({m_nnode, m_ndim})); #pragma omp parallel for for (size_t m = 0; m < m_nnode; ++m) { for (size_t i = 0; i < m_ndim; ++i) { nodevec(m, i) = dofval(m_dofs(m, i)); } } } } // namespace GooseFEM #endif diff --git a/include/GooseFEM/MatrixDiagonal.h b/include/GooseFEM/MatrixDiagonal.h index 1881ee2..baaddde 100644 --- a/include/GooseFEM/MatrixDiagonal.h +++ b/include/GooseFEM/MatrixDiagonal.h @@ -1,83 +1,83 @@ /* (c - GPLv3) T.W.J. de Geus (Tom) | tom@geus.me | www.geus.me | github.com/tdegeus/GooseFEM */ #ifndef GOOSEFEM_MATRIXDIAGONAL_H #define GOOSEFEM_MATRIXDIAGONAL_H #include "config.h" namespace GooseFEM { class MatrixDiagonal { public: // Constructors MatrixDiagonal() = default; - MatrixDiagonal(const xt::xtensor& conn, const xt::xtensor& dofs); + MatrixDiagonal(const xt::xtensor& conn, const xt::xtensor& dofs); // Dimensions size_t nelem() const; // number of elements size_t nne() const; // number of nodes per element size_t nnode() const; // number of nodes size_t ndim() const; // number of dimensions size_t ndof() const; // number of DOFs // DOF lists - xt::xtensor dofs() const; // DOFs + xt::xtensor dofs() const; // DOFs // Set matrix components - void set(const xt::xtensor& A); + void set(const xt::xtensor& A); // assemble from matrices stored per element [nelem, nne*ndim, nne*ndim] // WARNING: ignores any off-diagonal terms - void assemble(const xt::xtensor& elemmat); + void assemble(const xt::xtensor& elemmat); // Dot-product: // b_i = A_ij * x_j - void dot(const xt::xtensor& x, xt::xtensor& b) const; - void dot(const xt::xtensor& x, xt::xtensor& b) const; + void dot(const xt::xtensor& x, xt::xtensor& b) const; + void dot(const xt::xtensor& x, xt::xtensor& b) const; // Solve: // x = A \ b - void solve(const xt::xtensor& b, xt::xtensor& x); - void solve(const xt::xtensor& b, xt::xtensor& x); + void solve(const xt::xtensor& b, xt::xtensor& x); + void solve(const xt::xtensor& b, xt::xtensor& x); // Return matrix as diagonal matrix (column) - xt::xtensor AsDiagonal() const; + xt::xtensor AsDiagonal() const; // Auto-allocation of the functions above - xt::xtensor Dot(const xt::xtensor& x) const; - xt::xtensor Dot(const xt::xtensor& x) const; - xt::xtensor Solve(const xt::xtensor& b); - xt::xtensor Solve(const xt::xtensor& b); + xt::xtensor Dot(const xt::xtensor& x) const; + xt::xtensor Dot(const xt::xtensor& x) const; + xt::xtensor Solve(const xt::xtensor& b); + xt::xtensor Solve(const xt::xtensor& b); private: // The diagonal matrix, and its inverse (re-used to solve different RHS) - xt::xtensor m_A; - xt::xtensor m_inv; + xt::xtensor m_A; + xt::xtensor m_inv; // Signal changes to data compare to the last inverse bool m_factor = false; // Bookkeeping - xt::xtensor m_conn; // connectivity [nelem, nne] - xt::xtensor m_dofs; // DOF-numbers per node [nnode, ndim] + xt::xtensor m_conn; // connectivity [nelem, nne] + xt::xtensor m_dofs; // DOF-numbers per node [nnode, ndim] // Dimensions size_t m_nelem; // number of elements size_t m_nne; // number of nodes per element size_t m_nnode; // number of nodes size_t m_ndim; // number of dimensions size_t m_ndof; // number of DOFs // Compute inverse (automatically evaluated by "solve") void factorize(); }; } // namespace GooseFEM #include "MatrixDiagonal.hpp" #endif diff --git a/include/GooseFEM/MatrixDiagonal.hpp b/include/GooseFEM/MatrixDiagonal.hpp index 9a4a208..203334a 100644 --- a/include/GooseFEM/MatrixDiagonal.hpp +++ b/include/GooseFEM/MatrixDiagonal.hpp @@ -1,179 +1,179 @@ /* (c - GPLv3) T.W.J. de Geus (Tom) | tom@geus.me | www.geus.me | github.com/tdegeus/GooseFEM */ #ifndef GOOSEFEM_MATRIXDIAGONAL_HPP #define GOOSEFEM_MATRIXDIAGONAL_HPP #include "MatrixDiagonal.h" namespace GooseFEM { inline MatrixDiagonal::MatrixDiagonal( - const xt::xtensor& conn, const xt::xtensor& dofs) + const xt::xtensor& conn, const xt::xtensor& dofs) : m_conn(conn), m_dofs(dofs) { m_nelem = m_conn.shape(0); m_nne = m_conn.shape(1); m_nnode = m_dofs.shape(0); m_ndim = m_dofs.shape(1); m_ndof = xt::amax(m_dofs)[0] + 1; m_A = xt::empty({m_ndof}); m_inv = xt::empty({m_ndof}); GOOSEFEM_ASSERT(xt::amax(m_conn)[0] + 1 == m_nnode); GOOSEFEM_ASSERT(m_ndof <= m_nnode * m_ndim); } inline size_t MatrixDiagonal::nelem() const { return m_nelem; } inline size_t MatrixDiagonal::nne() const { return m_nne; } inline size_t MatrixDiagonal::nnode() const { return m_nnode; } inline size_t MatrixDiagonal::ndim() const { return m_ndim; } inline size_t MatrixDiagonal::ndof() const { return m_ndof; } -inline xt::xtensor MatrixDiagonal::dofs() const +inline xt::xtensor MatrixDiagonal::dofs() const { return m_dofs; } inline void MatrixDiagonal::factorize() { if (!m_factor) { return; } #pragma omp parallel for for (size_t d = 0; d < m_ndof; ++d) m_inv(d) = 1.0 / m_A(d); m_factor = false; } -inline void MatrixDiagonal::set(const xt::xtensor& A) +inline void MatrixDiagonal::set(const xt::xtensor& A) { GOOSEFEM_ASSERT(A.size() == m_ndof); std::copy(A.begin(), A.end(), m_A.begin()); m_factor = true; } -inline void MatrixDiagonal::assemble(const xt::xtensor& elemmat) +inline void MatrixDiagonal::assemble(const xt::xtensor& elemmat) { GOOSEFEM_ASSERT( elemmat.shape() == std::decay_t::shape_type({m_nelem, m_nne * m_ndim, m_nne * m_ndim})); GOOSEFEM_ASSERT(Element::isDiagonal(elemmat)); m_A.fill(0.0); for (size_t e = 0; e < m_nelem; ++e) { for (size_t m = 0; m < m_nne; ++m) { for (size_t i = 0; i < m_ndim; ++i) { m_A(m_dofs(m_conn(e, m), i)) += elemmat(e, m * m_ndim + i, m * m_ndim + i); } } } m_factor = true; } -inline void MatrixDiagonal::dot(const xt::xtensor& x, xt::xtensor& b) const +inline void MatrixDiagonal::dot(const xt::xtensor& x, xt::xtensor& b) const { GOOSEFEM_ASSERT(x.shape() == std::decay_t::shape_type({m_nnode, m_ndim})); GOOSEFEM_ASSERT(b.shape() == std::decay_t::shape_type({m_nnode, m_ndim})); #pragma omp parallel for for (size_t m = 0; m < m_nnode; ++m) { for (size_t i = 0; i < m_ndim; ++i) { b(m, i) = m_A(m_dofs(m, i)) * x(m, i); } } } -inline void MatrixDiagonal::dot(const xt::xtensor& x, xt::xtensor& b) const +inline void MatrixDiagonal::dot(const xt::xtensor& x, xt::xtensor& b) const { GOOSEFEM_ASSERT(x.size() == m_ndof); GOOSEFEM_ASSERT(b.size() == m_ndof); xt::noalias(b) = m_A * x; } -inline void MatrixDiagonal::solve(const xt::xtensor& b, xt::xtensor& x) +inline void MatrixDiagonal::solve(const xt::xtensor& b, xt::xtensor& x) { GOOSEFEM_ASSERT(b.shape() == std::decay_t::shape_type({m_nnode, m_ndim})); GOOSEFEM_ASSERT(x.shape() == std::decay_t::shape_type({m_nnode, m_ndim})); this->factorize(); #pragma omp parallel for for (size_t m = 0; m < m_nnode; ++m) { for (size_t i = 0; i < m_ndim; ++i) { x(m, i) = m_inv(m_dofs(m, i)) * b(m, i); } } } -inline void MatrixDiagonal::solve(const xt::xtensor& b, xt::xtensor& x) +inline void MatrixDiagonal::solve(const xt::xtensor& b, xt::xtensor& x) { GOOSEFEM_ASSERT(b.size() == m_ndof); GOOSEFEM_ASSERT(x.size() == m_ndof); this->factorize(); xt::noalias(x) = m_inv * b; } -inline xt::xtensor MatrixDiagonal::AsDiagonal() const +inline xt::xtensor MatrixDiagonal::AsDiagonal() const { return m_A; } -inline xt::xtensor MatrixDiagonal::Dot(const xt::xtensor& x) const +inline xt::xtensor MatrixDiagonal::Dot(const xt::xtensor& x) const { - xt::xtensor b = xt::empty({m_nnode, m_ndim}); + xt::xtensor b = xt::empty({m_nnode, m_ndim}); this->dot(x, b); return b; } -inline xt::xtensor MatrixDiagonal::Dot(const xt::xtensor& x) const +inline xt::xtensor MatrixDiagonal::Dot(const xt::xtensor& x) const { - xt::xtensor b = xt::empty({m_ndof}); + xt::xtensor b = xt::empty({m_ndof}); this->dot(x, b); return b; } -inline xt::xtensor MatrixDiagonal::Solve(const xt::xtensor& b) +inline xt::xtensor MatrixDiagonal::Solve(const xt::xtensor& b) { - xt::xtensor x = xt::empty({m_nnode, m_ndim}); + xt::xtensor x = xt::empty({m_nnode, m_ndim}); this->solve(b, x); return x; } -inline xt::xtensor MatrixDiagonal::Solve(const xt::xtensor& b) +inline xt::xtensor MatrixDiagonal::Solve(const xt::xtensor& b) { - xt::xtensor x = xt::empty({m_ndof}); + xt::xtensor x = xt::empty({m_ndof}); this->solve(b, x); return x; } } // namespace GooseFEM #endif diff --git a/include/GooseFEM/MatrixDiagonalPartitioned.h b/include/GooseFEM/MatrixDiagonalPartitioned.h index dfc0875..3b9cde3 100644 --- a/include/GooseFEM/MatrixDiagonalPartitioned.h +++ b/include/GooseFEM/MatrixDiagonalPartitioned.h @@ -1,148 +1,142 @@ /* (c - GPLv3) T.W.J. de Geus (Tom) | tom@geus.me | www.geus.me | github.com/tdegeus/GooseFEM */ #ifndef GOOSEFEM_MATRIXDIAGONALPARTITIONED_H #define GOOSEFEM_MATRIXDIAGONALPARTITIONED_H #include "config.h" namespace GooseFEM { class MatrixDiagonalPartitioned { public: // Constructors MatrixDiagonalPartitioned() = default; MatrixDiagonalPartitioned( - const xt::xtensor& conn, - const xt::xtensor& dofs, - const xt::xtensor& iip); + const xt::xtensor& conn, + const xt::xtensor& dofs, + const xt::xtensor& iip); // Dimensions size_t nelem() const; // number of elements size_t nne() const; // number of nodes per element size_t nnode() const; // number of nodes size_t ndim() const; // number of dimensions size_t ndof() const; // number of DOFs size_t nnu() const; // number of unknown DOFs size_t nnp() const; // number of prescribed DOFs // DOF lists - xt::xtensor dofs() const; // DOFs - xt::xtensor iiu() const; // unknown DOFs - xt::xtensor iip() const; // prescribed DOFs + xt::xtensor dofs() const; // DOFs + xt::xtensor iiu() const; // unknown DOFs + xt::xtensor iip() const; // prescribed DOFs // Assemble from matrices stored per element [nelem, nne*ndim, nne*ndim] // WARNING: ignores any off-diagonal terms - void assemble(const xt::xtensor& elemmat); + void assemble(const xt::xtensor& elemmat); // Dot-product: // b_i = A_ij * x_j - void dot(const xt::xtensor& x, xt::xtensor& b) const; - void dot(const xt::xtensor& x, xt::xtensor& b) const; + void dot(const xt::xtensor& x, xt::xtensor& b) const; + void dot(const xt::xtensor& x, xt::xtensor& b) const; void dot_u( - const xt::xtensor& x_u, - const xt::xtensor& x_p, - xt::xtensor& b_u) const; + const xt::xtensor& x_u, + const xt::xtensor& x_p, + xt::xtensor& b_u) const; void dot_p( - const xt::xtensor& x_u, - const xt::xtensor& x_p, - xt::xtensor& b_p) const; + const xt::xtensor& x_u, + const xt::xtensor& x_p, + xt::xtensor& b_p) const; // Solve: // x_u = A_uu \ ( b_u - A_up * x_p ) = A_uu \ b_u - void solve(const xt::xtensor& b, xt::xtensor& x); // modified with "x_u" + void solve(const xt::xtensor& b, xt::xtensor& x); // modified with "x_u" - void solve(const xt::xtensor& b, xt::xtensor& x); // modified with "x_u" + void solve(const xt::xtensor& b, xt::xtensor& x); // modified with "x_u" void solve_u( - const xt::xtensor& b_u, - const xt::xtensor& x_p, - xt::xtensor& x_u); + const xt::xtensor& b_u, + const xt::xtensor& x_p, + xt::xtensor& x_u); // Get right-hand-size for corresponding to the prescribed DOFs: // b_p = A_pu * x_u + A_pp * x_p = A_pp * x_p void reaction( - const xt::xtensor& x, xt::xtensor& b) const; // modified with "b_p" + const xt::xtensor& x, xt::xtensor& b) const; // modified with "b_p" void reaction( - const xt::xtensor& x, xt::xtensor& b) const; // modified with "b_p" + const xt::xtensor& x, xt::xtensor& b) const; // modified with "b_p" void reaction_p( - const xt::xtensor& x_u, - const xt::xtensor& x_p, - xt::xtensor& b_p) const; + const xt::xtensor& x_u, + const xt::xtensor& x_p, + xt::xtensor& b_p) const; // Return matrix as diagonal matrix (column) - xt::xtensor AsDiagonal() const; + xt::xtensor AsDiagonal() const; // Auto-allocation of the functions above - xt::xtensor Dot(const xt::xtensor& x) const; - xt::xtensor Dot(const xt::xtensor& x) const; + xt::xtensor Dot(const xt::xtensor& x) const; + xt::xtensor Dot(const xt::xtensor& x) const; - xt::xtensor Dot_u( - const xt::xtensor& x_u, - const xt::xtensor& x_p) const; + xt::xtensor Dot_u( + const xt::xtensor& x_u, const xt::xtensor& x_p) const; - xt::xtensor Dot_p( - const xt::xtensor& x_u, - const xt::xtensor& x_p) const; + xt::xtensor Dot_p( + const xt::xtensor& x_u, const xt::xtensor& x_p) const; - xt::xtensor Solve(const xt::xtensor& b, const xt::xtensor& x); - xt::xtensor Solve(const xt::xtensor& b, const xt::xtensor& x); + xt::xtensor Solve(const xt::xtensor& b, const xt::xtensor& x); + xt::xtensor Solve(const xt::xtensor& b, const xt::xtensor& x); - xt::xtensor Solve_u( - const xt::xtensor& b_u, - const xt::xtensor& x_p); + xt::xtensor Solve_u( + const xt::xtensor& b_u, const xt::xtensor& x_p); - xt::xtensor Reaction( - const xt::xtensor& x, - const xt::xtensor& b) const; + xt::xtensor Reaction( + const xt::xtensor& x, const xt::xtensor& b) const; - xt::xtensor Reaction( - const xt::xtensor& x, - const xt::xtensor& b) const; + xt::xtensor Reaction( + const xt::xtensor& x, const xt::xtensor& b) const; - xt::xtensor Reaction_p( - const xt::xtensor& x_u, - const xt::xtensor& x_p) const; + xt::xtensor Reaction_p( + const xt::xtensor& x_u, const xt::xtensor& x_p) const; private: // The diagonal matrix, and its inverse (re-used to solve different RHS) - xt::xtensor m_Auu; - xt::xtensor m_App; - xt::xtensor m_inv_uu; + xt::xtensor m_Auu; + xt::xtensor m_App; + xt::xtensor m_inv_uu; // Signal changes to data compare to the last inverse bool m_factor = false; // Bookkeeping - xt::xtensor m_conn; // connectivity [nelem, nne ] - xt::xtensor m_dofs; // DOF-numbers per node [nnode, ndim] - xt::xtensor m_part; // DOF-numbers per node, renumbered [nnode, ndim] - xt::xtensor m_iiu; // DOF-numbers that are unknown [nnu] - xt::xtensor m_iip; // DOF-numbers that are prescribed [nnp] + xt::xtensor m_conn; // connectivity [nelem, nne ] + xt::xtensor m_dofs; // DOF-numbers per node [nnode, ndim] + xt::xtensor m_part; // DOF-numbers per node, renumbered [nnode, ndim] + xt::xtensor m_iiu; // DOF-numbers that are unknown [nnu] + xt::xtensor m_iip; // DOF-numbers that are prescribed [nnp] // Dimensions size_t m_nelem; // number of elements size_t m_nne; // number of nodes per element size_t m_nnode; // number of nodes size_t m_ndim; // number of dimensions size_t m_ndof; // number of DOFs size_t m_nnu; // number of unknown DOFs size_t m_nnp; // number of prescribed DOFs // Compute inverse (automatically evaluated by "solve") void factorize(); }; } // namespace GooseFEM #include "MatrixDiagonalPartitioned.hpp" #endif diff --git a/include/GooseFEM/MatrixDiagonalPartitioned.hpp b/include/GooseFEM/MatrixDiagonalPartitioned.hpp index f7c4635..085c9a1 100644 --- a/include/GooseFEM/MatrixDiagonalPartitioned.hpp +++ b/include/GooseFEM/MatrixDiagonalPartitioned.hpp @@ -1,398 +1,398 @@ /* (c - GPLv3) T.W.J. de Geus (Tom) | tom@geus.me | www.geus.me | github.com/tdegeus/GooseFEM */ #ifndef GOOSEFEM_MATRIXDIAGONALPARTITIONED_HPP #define GOOSEFEM_MATRIXDIAGONALPARTITIONED_HPP #include "MatrixDiagonalPartitioned.h" #include "Mesh.h" namespace GooseFEM { inline MatrixDiagonalPartitioned::MatrixDiagonalPartitioned( - const xt::xtensor& conn, - const xt::xtensor& dofs, - const xt::xtensor& iip) + const xt::xtensor& conn, + const xt::xtensor& dofs, + const xt::xtensor& iip) : m_conn(conn), m_dofs(dofs), m_iip(iip) { m_nelem = m_conn.shape(0); m_nne = m_conn.shape(1); m_nnode = m_dofs.shape(0); m_ndim = m_dofs.shape(1); m_iiu = xt::setdiff1d(dofs, iip); m_ndof = xt::amax(m_dofs)[0] + 1; m_nnp = m_iip.size(); m_nnu = m_iiu.size(); m_part = Mesh::Reorder({m_iiu, m_iip}).get(m_dofs); m_Auu = xt::empty({m_nnu}); m_App = xt::empty({m_nnp}); m_inv_uu = xt::empty({m_nnu}); GOOSEFEM_ASSERT(xt::amax(m_conn)[0] + 1 == m_nnode); GOOSEFEM_ASSERT(xt::amax(m_iip)[0] <= xt::amax(m_dofs)[0]); GOOSEFEM_ASSERT(m_ndof <= m_nnode * m_ndim); } inline size_t MatrixDiagonalPartitioned::nelem() const { return m_nelem; } inline size_t MatrixDiagonalPartitioned::nne() const { return m_nne; } inline size_t MatrixDiagonalPartitioned::nnode() const { return m_nnode; } inline size_t MatrixDiagonalPartitioned::ndim() const { return m_ndim; } inline size_t MatrixDiagonalPartitioned::ndof() const { return m_ndof; } inline size_t MatrixDiagonalPartitioned::nnu() const { return m_nnu; } inline size_t MatrixDiagonalPartitioned::nnp() const { return m_nnp; } -inline xt::xtensor MatrixDiagonalPartitioned::dofs() const +inline xt::xtensor MatrixDiagonalPartitioned::dofs() const { return m_dofs; } -inline xt::xtensor MatrixDiagonalPartitioned::iiu() const +inline xt::xtensor MatrixDiagonalPartitioned::iiu() const { return m_iiu; } -inline xt::xtensor MatrixDiagonalPartitioned::iip() const +inline xt::xtensor MatrixDiagonalPartitioned::iip() const { return m_iip; } inline void MatrixDiagonalPartitioned::factorize() { if (!m_factor) { return; } #pragma omp parallel for for (size_t d = 0; d < m_nnu; ++d) { m_inv_uu(d) = 1.0 / m_Auu(d); } m_factor = false; } -inline void MatrixDiagonalPartitioned::assemble(const xt::xtensor& elemmat) +inline void MatrixDiagonalPartitioned::assemble(const xt::xtensor& elemmat) { GOOSEFEM_ASSERT( elemmat.shape() == std::decay_t::shape_type({m_nelem, m_nne * m_ndim, m_nne * m_ndim})); GOOSEFEM_ASSERT(Element::isDiagonal(elemmat)); m_Auu.fill(0.0); m_App.fill(0.0); for (size_t e = 0; e < m_nelem; ++e) { for (size_t m = 0; m < m_nne; ++m) { for (size_t i = 0; i < m_ndim; ++i) { size_t d = m_part(m_conn(e, m), i); if (d < m_nnu) { m_Auu(d) += elemmat(e, m * m_ndim + i, m * m_ndim + i); } else { m_App(d - m_nnu) += elemmat(e, m * m_ndim + i, m * m_ndim + i); } } } } m_factor = true; } inline void -MatrixDiagonalPartitioned::dot(const xt::xtensor& x, xt::xtensor& b) const +MatrixDiagonalPartitioned::dot(const xt::xtensor& x, xt::xtensor& b) const { GOOSEFEM_ASSERT(x.shape() == std::decay_t::shape_type({m_nnode, m_ndim})); GOOSEFEM_ASSERT(b.shape() == std::decay_t::shape_type({m_nnode, m_ndim})); #pragma omp parallel for for (size_t m = 0; m < m_nnode; ++m) { for (size_t i = 0; i < m_ndim; ++i) { size_t d = m_part(m, i); if (d < m_nnu) { b(m, i) = m_Auu(d) * x(m, i); } else { b(m, i) = m_App(d - m_nnu) * x(m, i); } } } } inline void -MatrixDiagonalPartitioned::dot(const xt::xtensor& x, xt::xtensor& b) const +MatrixDiagonalPartitioned::dot(const xt::xtensor& x, xt::xtensor& b) const { GOOSEFEM_ASSERT(x.size() == m_ndof); GOOSEFEM_ASSERT(b.size() == m_ndof); #pragma omp parallel for for (size_t d = 0; d < m_nnu; ++d) { b(m_iiu(d)) = m_Auu(d) * x(m_iiu(d)); } #pragma omp parallel for for (size_t d = 0; d < m_nnp; ++d) { b(m_iip(d)) = m_App(d) * x(m_iip(d)); } } inline void MatrixDiagonalPartitioned::dot_u( - const xt::xtensor& x_u, - const xt::xtensor& x_p, - xt::xtensor& b_u) const + const xt::xtensor& x_u, + const xt::xtensor& x_p, + xt::xtensor& b_u) const { UNUSED(x_p); GOOSEFEM_ASSERT(x_u.size() == m_nnu); GOOSEFEM_ASSERT(x_p.size() == m_nnp); GOOSEFEM_ASSERT(b_u.size() == m_nnu); #pragma omp parallel for for (size_t d = 0; d < m_nnu; ++d) { b_u(d) = m_Auu(d) * x_u(d); } } inline void MatrixDiagonalPartitioned::dot_p( - const xt::xtensor& x_u, - const xt::xtensor& x_p, - xt::xtensor& b_p) const + const xt::xtensor& x_u, + const xt::xtensor& x_p, + xt::xtensor& b_p) const { UNUSED(x_u); GOOSEFEM_ASSERT(x_u.size() == m_nnu); GOOSEFEM_ASSERT(x_p.size() == m_nnp); GOOSEFEM_ASSERT(b_p.size() == m_nnp); #pragma omp parallel for for (size_t d = 0; d < m_nnp; ++d) { b_p(d) = m_App(d) * x_p(d); } } inline void -MatrixDiagonalPartitioned::solve(const xt::xtensor& b, xt::xtensor& x) +MatrixDiagonalPartitioned::solve(const xt::xtensor& b, xt::xtensor& x) { GOOSEFEM_ASSERT(b.shape() == std::decay_t::shape_type({m_nnode, m_ndim})); GOOSEFEM_ASSERT(x.shape() == std::decay_t::shape_type({m_nnode, m_ndim})); this->factorize(); #pragma omp parallel for for (size_t m = 0; m < m_nnode; ++m) { for (size_t i = 0; i < m_ndim; ++i) { if (m_part(m, i) < m_nnu) { x(m, i) = m_inv_uu(m_part(m, i)) * b(m, i); } } } } inline void -MatrixDiagonalPartitioned::solve(const xt::xtensor& b, xt::xtensor& x) +MatrixDiagonalPartitioned::solve(const xt::xtensor& b, xt::xtensor& x) { GOOSEFEM_ASSERT(b.size() == m_ndof); GOOSEFEM_ASSERT(x.size() == m_ndof); this->factorize(); #pragma omp parallel for for (size_t d = 0; d < m_nnu; ++d) { x(m_iiu(d)) = m_inv_uu(d) * b(m_iiu(d)); } } inline void MatrixDiagonalPartitioned::solve_u( - const xt::xtensor& b_u, - const xt::xtensor& x_p, - xt::xtensor& x_u) + const xt::xtensor& b_u, + const xt::xtensor& x_p, + xt::xtensor& x_u) { UNUSED(x_p); GOOSEFEM_ASSERT(b_u.size() == m_nnu); GOOSEFEM_ASSERT(x_p.size() == m_nnp); GOOSEFEM_ASSERT(x_u.size() == m_nnu); this->factorize(); #pragma omp parallel for for (size_t d = 0; d < m_nnu; ++d) { x_u(d) = m_inv_uu(d) * b_u(d); } } inline void MatrixDiagonalPartitioned::reaction( - const xt::xtensor& x, xt::xtensor& b) const + const xt::xtensor& x, xt::xtensor& b) const { GOOSEFEM_ASSERT(x.shape() == std::decay_t::shape_type({m_nnode, m_ndim})); GOOSEFEM_ASSERT(b.shape() == std::decay_t::shape_type({m_nnode, m_ndim})); #pragma omp parallel for for (size_t m = 0; m < m_nnode; ++m) { for (size_t i = 0; i < m_ndim; ++i) { if (m_part(m, i) >= m_nnu) { b(m, i) = m_App(m_part(m, i) - m_nnu) * x(m, i); } } } } inline void MatrixDiagonalPartitioned::reaction( - const xt::xtensor& x, xt::xtensor& b) const + const xt::xtensor& x, xt::xtensor& b) const { GOOSEFEM_ASSERT(x.size() == m_ndof); GOOSEFEM_ASSERT(b.size() == m_ndof); #pragma omp parallel for for (size_t d = 0; d < m_nnp; ++d) { b(m_iip(d)) = m_App(d) * x(m_iip(d)); } } inline void MatrixDiagonalPartitioned::reaction_p( - const xt::xtensor& x_u, - const xt::xtensor& x_p, - xt::xtensor& b_p) const + const xt::xtensor& x_u, + const xt::xtensor& x_p, + xt::xtensor& b_p) const { UNUSED(x_u); GOOSEFEM_ASSERT(x_u.size() == m_nnu); GOOSEFEM_ASSERT(x_p.size() == m_nnp); GOOSEFEM_ASSERT(b_p.size() == m_nnp); #pragma omp parallel for for (size_t d = 0; d < m_nnp; ++d) { b_p(d) = m_App(d) * x_p(d); } } -inline xt::xtensor MatrixDiagonalPartitioned::AsDiagonal() const +inline xt::xtensor MatrixDiagonalPartitioned::AsDiagonal() const { - xt::xtensor out = xt::zeros({m_ndof}); + xt::xtensor out = xt::zeros({m_ndof}); #pragma omp parallel for for (size_t d = 0; d < m_nnu; ++d) { out(m_iiu(d)) = m_Auu(d); } #pragma omp parallel for for (size_t d = 0; d < m_nnp; ++d) { out(m_iip(d)) = m_App(d); } return out; } -inline xt::xtensor MatrixDiagonalPartitioned::Dot(const xt::xtensor& x) const +inline xt::xtensor MatrixDiagonalPartitioned::Dot(const xt::xtensor& x) const { - xt::xtensor b = xt::empty({m_nnode, m_ndim}); + xt::xtensor b = xt::empty({m_nnode, m_ndim}); this->dot(x, b); return b; } -inline xt::xtensor MatrixDiagonalPartitioned::Dot(const xt::xtensor& x) const +inline xt::xtensor MatrixDiagonalPartitioned::Dot(const xt::xtensor& x) const { - xt::xtensor b = xt::empty({m_ndof}); + xt::xtensor b = xt::empty({m_ndof}); this->dot(x, b); return b; } -inline xt::xtensor MatrixDiagonalPartitioned::Dot_u( - const xt::xtensor& x_u, const xt::xtensor& x_p) const +inline xt::xtensor MatrixDiagonalPartitioned::Dot_u( + const xt::xtensor& x_u, const xt::xtensor& x_p) const { - xt::xtensor b_u = xt::empty({m_nnu}); + xt::xtensor b_u = xt::empty({m_nnu}); this->dot_u(x_u, x_p, b_u); return b_u; } -inline xt::xtensor MatrixDiagonalPartitioned::Dot_p( - const xt::xtensor& x_u, const xt::xtensor& x_p) const +inline xt::xtensor MatrixDiagonalPartitioned::Dot_p( + const xt::xtensor& x_u, const xt::xtensor& x_p) const { - xt::xtensor b_p = xt::empty({m_nnp}); + xt::xtensor b_p = xt::empty({m_nnp}); this->dot_p(x_u, x_p, b_p); return b_p; } -inline xt::xtensor -MatrixDiagonalPartitioned::Solve(const xt::xtensor& b, const xt::xtensor& x) +inline xt::xtensor +MatrixDiagonalPartitioned::Solve(const xt::xtensor& b, const xt::xtensor& x) { - xt::xtensor out = x; + xt::xtensor out = x; this->solve(b, out); return out; } -inline xt::xtensor -MatrixDiagonalPartitioned::Solve(const xt::xtensor& b, const xt::xtensor& x) +inline xt::xtensor +MatrixDiagonalPartitioned::Solve(const xt::xtensor& b, const xt::xtensor& x) { - xt::xtensor out = x; + xt::xtensor out = x; this->solve(b, out); return out; } -inline xt::xtensor MatrixDiagonalPartitioned::Solve_u( - const xt::xtensor& b_u, const xt::xtensor& x_p) +inline xt::xtensor MatrixDiagonalPartitioned::Solve_u( + const xt::xtensor& b_u, const xt::xtensor& x_p) { - xt::xtensor x_u = xt::empty({m_nnu}); + xt::xtensor x_u = xt::empty({m_nnu}); this->solve_u(b_u, x_p, x_u); return x_u; } -inline xt::xtensor MatrixDiagonalPartitioned::Reaction( - const xt::xtensor& x, const xt::xtensor& b) const +inline xt::xtensor MatrixDiagonalPartitioned::Reaction( + const xt::xtensor& x, const xt::xtensor& b) const { - xt::xtensor out = b; + xt::xtensor out = b; this->reaction(x, out); return out; } -inline xt::xtensor MatrixDiagonalPartitioned::Reaction( - const xt::xtensor& x, const xt::xtensor& b) const +inline xt::xtensor MatrixDiagonalPartitioned::Reaction( + const xt::xtensor& x, const xt::xtensor& b) const { - xt::xtensor out = b; + xt::xtensor out = b; this->reaction(x, out); return out; } -inline xt::xtensor MatrixDiagonalPartitioned::Reaction_p( - const xt::xtensor& x_u, const xt::xtensor& x_p) const +inline xt::xtensor MatrixDiagonalPartitioned::Reaction_p( + const xt::xtensor& x_u, const xt::xtensor& x_p) const { - xt::xtensor b_p = xt::empty({m_nnp}); + xt::xtensor b_p = xt::empty({m_nnp}); this->reaction_p(x_u, x_p, b_p); return b_p; } } // namespace GooseFEM #endif diff --git a/include/GooseFEM/MatrixPartitioned.h b/include/GooseFEM/MatrixPartitioned.h index edd185c..a7390e7 100644 --- a/include/GooseFEM/MatrixPartitioned.h +++ b/include/GooseFEM/MatrixPartitioned.h @@ -1,140 +1,134 @@ /* (c - GPLv3) T.W.J. de Geus (Tom) | tom@geus.me | www.geus.me | github.com/tdegeus/GooseFEM */ #ifndef GOOSEFEM_MATRIXPARTITIONED_H #define GOOSEFEM_MATRIXPARTITIONED_H #include "config.h" #include #include #include namespace GooseFEM { template >> class MatrixPartitioned { public: // Constructors MatrixPartitioned() = default; MatrixPartitioned( - const xt::xtensor& conn, - const xt::xtensor& dofs, - const xt::xtensor& iip); + const xt::xtensor& conn, + const xt::xtensor& dofs, + const xt::xtensor& iip); // Dimensions size_t nelem() const; // number of elements size_t nne() const; // number of nodes per element size_t nnode() const; // number of nodes size_t ndim() const; // number of dimensions size_t ndof() const; // number of DOFs size_t nnu() const; // number of unknown DOFs size_t nnp() const; // number of prescribed DOFs // DOF lists - xt::xtensor dofs() const; // DOFs - xt::xtensor iiu() const; // unknown DOFs - xt::xtensor iip() const; // prescribed DOFs + xt::xtensor dofs() const; // DOFs + xt::xtensor iiu() const; // unknown DOFs + xt::xtensor iip() const; // prescribed DOFs // Assemble from matrices stored per element [nelem, nne*ndim, nne*ndim] - void assemble(const xt::xtensor& elemmat); + void assemble(const xt::xtensor& elemmat); // Solve: // x_u = A_uu \ ( b_u - A_up * x_p ) - void solve(const xt::xtensor& b, xt::xtensor& x); // modified with "x_u" - void solve(const xt::xtensor& b, xt::xtensor& x); // modified with "x_u" + void solve(const xt::xtensor& b, xt::xtensor& x); // modified with "x_u" + void solve(const xt::xtensor& b, xt::xtensor& x); // modified with "x_u" void solve_u( - const xt::xtensor& b_u, - const xt::xtensor& x_p, - xt::xtensor& x_u); + const xt::xtensor& b_u, + const xt::xtensor& x_p, + xt::xtensor& x_u); // Get right-hand-size for corresponding to the prescribed DOFs: // b_p = A_pu * x_u + A_pp * x_p = A_pp * x_p void reaction( - const xt::xtensor& x, - xt::xtensor& b) const; // modified with "b_p" + const xt::xtensor& x, xt::xtensor& b) const; // modified with "b_p" void reaction( - const xt::xtensor& x, - xt::xtensor& b) const; // modified with "b_p" + const xt::xtensor& x, xt::xtensor& b) const; // modified with "b_p" void reaction_p( - const xt::xtensor& x_u, - const xt::xtensor& x_p, - xt::xtensor& b_p) const; + const xt::xtensor& x_u, + const xt::xtensor& x_p, + xt::xtensor& b_p) const; // Auto-allocation of the functions above - xt::xtensor Solve(const xt::xtensor& b, const xt::xtensor& x); - xt::xtensor Solve(const xt::xtensor& b, const xt::xtensor& x); + xt::xtensor Solve(const xt::xtensor& b, const xt::xtensor& x); + xt::xtensor Solve(const xt::xtensor& b, const xt::xtensor& x); - xt::xtensor Solve_u( - const xt::xtensor& b_u, - const xt::xtensor& x_p); + xt::xtensor Solve_u( + const xt::xtensor& b_u, const xt::xtensor& x_p); - xt::xtensor Reaction( - const xt::xtensor& x, - const xt::xtensor& b) const; + xt::xtensor Reaction( + const xt::xtensor& x, const xt::xtensor& b) const; - xt::xtensor Reaction( - const xt::xtensor& x, - const xt::xtensor& b) const; + xt::xtensor Reaction( + const xt::xtensor& x, const xt::xtensor& b) const; - xt::xtensor Reaction_p( - const xt::xtensor& x_u, - const xt::xtensor& x_p) const; + xt::xtensor Reaction_p( + const xt::xtensor& x_u, const xt::xtensor& x_p) const; private: // The matrix Eigen::SparseMatrix m_Auu; Eigen::SparseMatrix m_Aup; Eigen::SparseMatrix m_Apu; Eigen::SparseMatrix m_App; // Matrix entries std::vector> m_Tuu; std::vector> m_Tup; std::vector> m_Tpu; std::vector> m_Tpp; // Solver (re-used to solve different RHS) Solver m_solver; // Signal changes to data compare to the last inverse bool m_factor = false; // Bookkeeping - xt::xtensor m_conn; // connectivity [nelem, nne ] - xt::xtensor m_dofs; // DOF-numbers per node [nnode, ndim] - xt::xtensor m_part; // DOF-numbers per node, renumbered [nnode, ndim] - xt::xtensor m_iiu; // unknown DOFs [nnu] - xt::xtensor m_iip; // prescribed DOFs [nnp] + xt::xtensor m_conn; // connectivity [nelem, nne ] + xt::xtensor m_dofs; // DOF-numbers per node [nnode, ndim] + xt::xtensor m_part; // DOF-numbers per node, renumbered [nnode, ndim] + xt::xtensor m_iiu; // unknown DOFs [nnu] + xt::xtensor m_iip; // prescribed DOFs [nnp] // Dimensions size_t m_nelem; // number of elements size_t m_nne; // number of nodes per element size_t m_nnode; // number of nodes size_t m_ndim; // number of dimensions size_t m_ndof; // number of DOFs size_t m_nnu; // number of unknown DOFs size_t m_nnp; // number of prescribed DOFs // Compute inverse (automatically evaluated by "solve") void factorize(); // Convert arrays (Eigen version of VectorPartitioned, which contains public functions) - Eigen::VectorXd asDofs_u(const xt::xtensor& dofval) const; - Eigen::VectorXd asDofs_u(const xt::xtensor& nodevec) const; - Eigen::VectorXd asDofs_p(const xt::xtensor& dofval) const; - Eigen::VectorXd asDofs_p(const xt::xtensor& nodevec) const; + Eigen::VectorXd asDofs_u(const xt::xtensor& dofval) const; + Eigen::VectorXd asDofs_u(const xt::xtensor& nodevec) const; + Eigen::VectorXd asDofs_p(const xt::xtensor& dofval) const; + Eigen::VectorXd asDofs_p(const xt::xtensor& nodevec) const; }; } // namespace GooseFEM #include "MatrixPartitioned.hpp" #endif diff --git a/include/GooseFEM/MatrixPartitioned.hpp b/include/GooseFEM/MatrixPartitioned.hpp index 8b4500d..f34da13 100644 --- a/include/GooseFEM/MatrixPartitioned.hpp +++ b/include/GooseFEM/MatrixPartitioned.hpp @@ -1,432 +1,426 @@ /* (c - GPLv3) T.W.J. de Geus (Tom) | tom@geus.me | www.geus.me | github.com/tdegeus/GooseFEM */ #ifndef GOOSEFEM_MATRIXPARTITIONED_HPP #define GOOSEFEM_MATRIXPARTITIONED_HPP #include "MatrixPartitioned.h" #include "Mesh.h" namespace GooseFEM { template inline MatrixPartitioned::MatrixPartitioned( - const xt::xtensor& conn, - const xt::xtensor& dofs, - const xt::xtensor& iip) + const xt::xtensor& conn, + const xt::xtensor& dofs, + const xt::xtensor& iip) : m_conn(conn), m_dofs(dofs), m_iip(iip) { m_nelem = m_conn.shape(0); m_nne = m_conn.shape(1); m_nnode = m_dofs.shape(0); m_ndim = m_dofs.shape(1); m_iiu = xt::setdiff1d(dofs, iip); m_ndof = xt::amax(m_dofs)[0] + 1; m_nnp = m_iip.size(); m_nnu = m_iiu.size(); m_part = Mesh::Reorder({m_iiu, m_iip}).get(m_dofs); m_Tuu.reserve(m_nelem * m_nne * m_ndim * m_nne * m_ndim); m_Tup.reserve(m_nelem * m_nne * m_ndim * m_nne * m_ndim); m_Tpu.reserve(m_nelem * m_nne * m_ndim * m_nne * m_ndim); m_Tpp.reserve(m_nelem * m_nne * m_ndim * m_nne * m_ndim); m_Auu.resize(m_nnu, m_nnu); m_Aup.resize(m_nnu, m_nnp); m_Apu.resize(m_nnp, m_nnu); m_App.resize(m_nnp, m_nnp); GOOSEFEM_ASSERT(xt::amax(m_conn)[0] + 1 == m_nnode); GOOSEFEM_ASSERT(xt::amax(m_iip)[0] <= xt::amax(m_dofs)[0]); GOOSEFEM_ASSERT(m_ndof <= m_nnode * m_ndim); } template inline size_t MatrixPartitioned::nelem() const { return m_nelem; } template inline size_t MatrixPartitioned::nne() const { return m_nne; } template inline size_t MatrixPartitioned::nnode() const { return m_nnode; } template inline size_t MatrixPartitioned::ndim() const { return m_ndim; } template inline size_t MatrixPartitioned::ndof() const { return m_ndof; } template inline size_t MatrixPartitioned::nnu() const { return m_nnu; } template inline size_t MatrixPartitioned::nnp() const { return m_nnp; } template -inline xt::xtensor MatrixPartitioned::dofs() const +inline xt::xtensor MatrixPartitioned::dofs() const { return m_dofs; } template -inline xt::xtensor MatrixPartitioned::iiu() const +inline xt::xtensor MatrixPartitioned::iiu() const { return m_iiu; } template -inline xt::xtensor MatrixPartitioned::iip() const +inline xt::xtensor MatrixPartitioned::iip() const { return m_iip; } template inline void MatrixPartitioned::factorize() { if (!m_factor) { return; } m_solver.compute(m_Auu); m_factor = false; } template -inline void MatrixPartitioned::assemble(const xt::xtensor& elemmat) +inline void MatrixPartitioned::assemble(const xt::xtensor& elemmat) { GOOSEFEM_ASSERT( elemmat.shape() == std::decay_t::shape_type({m_nelem, m_nne * m_ndim, m_nne * m_ndim})); m_Tuu.clear(); m_Tup.clear(); m_Tpu.clear(); m_Tpp.clear(); for (size_t e = 0; e < m_nelem; ++e) { for (size_t m = 0; m < m_nne; ++m) { for (size_t i = 0; i < m_ndim; ++i) { size_t di = m_part(m_conn(e, m), i); for (size_t n = 0; n < m_nne; ++n) { for (size_t j = 0; j < m_ndim; ++j) { size_t dj = m_part(m_conn(e, n), j); if (di < m_nnu && dj < m_nnu) { m_Tuu.push_back(Eigen::Triplet( - di, - dj, - elemmat(e, m * m_ndim + i, n * m_ndim + j))); + di, dj, elemmat(e, m * m_ndim + i, n * m_ndim + j))); } else if (di < m_nnu) { m_Tup.push_back(Eigen::Triplet( - di, - dj - m_nnu, - elemmat(e, m * m_ndim + i, n * m_ndim + j))); + di, dj - m_nnu, elemmat(e, m * m_ndim + i, n * m_ndim + j))); } else if (dj < m_nnu) { m_Tpu.push_back(Eigen::Triplet( - di - m_nnu, - dj, - elemmat(e, m * m_ndim + i, n * m_ndim + j))); + di - m_nnu, dj, elemmat(e, m * m_ndim + i, n * m_ndim + j))); } else { m_Tpp.push_back(Eigen::Triplet( di - m_nnu, dj - m_nnu, elemmat(e, m * m_ndim + i, n * m_ndim + j))); } } } } } } m_Auu.setFromTriplets(m_Tuu.begin(), m_Tuu.end()); m_Aup.setFromTriplets(m_Tup.begin(), m_Tup.end()); m_Apu.setFromTriplets(m_Tpu.begin(), m_Tpu.end()); m_App.setFromTriplets(m_Tpp.begin(), m_Tpp.end()); m_factor = true; } template inline void -MatrixPartitioned::solve(const xt::xtensor& b, xt::xtensor& x) +MatrixPartitioned::solve(const xt::xtensor& b, xt::xtensor& x) { GOOSEFEM_ASSERT(b.shape() == std::decay_t::shape_type({m_nnode, m_ndim})); GOOSEFEM_ASSERT(x.shape() == std::decay_t::shape_type({m_nnode, m_ndim})); this->factorize(); Eigen::VectorXd B_u = this->asDofs_u(b); Eigen::VectorXd X_p = this->asDofs_p(x); Eigen::VectorXd X_u = m_solver.solve(Eigen::VectorXd(B_u - m_Aup * X_p)); #pragma omp parallel for for (size_t m = 0; m < m_nnode; ++m) { for (size_t i = 0; i < m_ndim; ++i) { if (m_part(m, i) < m_nnu) { x(m, i) = X_u(m_part(m, i)); } } } } template inline void -MatrixPartitioned::solve(const xt::xtensor& b, xt::xtensor& x) +MatrixPartitioned::solve(const xt::xtensor& b, xt::xtensor& x) { GOOSEFEM_ASSERT(b.size() == m_ndof); GOOSEFEM_ASSERT(x.size() == m_ndof); this->factorize(); Eigen::VectorXd B_u = this->asDofs_u(b); Eigen::VectorXd X_p = this->asDofs_p(x); Eigen::VectorXd X_u = m_solver.solve(Eigen::VectorXd(B_u - m_Aup * X_p)); #pragma omp parallel for for (size_t d = 0; d < m_nnu; ++d) { x(m_iiu(d)) = X_u(d); } } template inline void MatrixPartitioned::solve_u( - const xt::xtensor& b_u, - const xt::xtensor& x_p, - xt::xtensor& x_u) + const xt::xtensor& b_u, + const xt::xtensor& x_p, + xt::xtensor& x_u) { GOOSEFEM_ASSERT(b_u.size() == m_nnu); GOOSEFEM_ASSERT(x_p.size() == m_nnp); GOOSEFEM_ASSERT(x_u.size() == m_nnu); this->factorize(); Eigen::VectorXd B_u(m_nnu, 1); Eigen::VectorXd X_p(m_nnp, 1); std::copy(b_u.begin(), b_u.end(), B_u.data()); std::copy(x_p.begin(), x_p.end(), X_p.data()); Eigen::VectorXd X_u = m_solver.solve(Eigen::VectorXd(B_u - m_Aup * X_p)); std::copy(X_u.data(), X_u.data() + m_nnu, x_u.begin()); } template inline void MatrixPartitioned::reaction( - const xt::xtensor& x, xt::xtensor& b) const + const xt::xtensor& x, xt::xtensor& b) const { GOOSEFEM_ASSERT(x.shape() == std::decay_t::shape_type({m_nnode, m_ndim})); GOOSEFEM_ASSERT(b.shape() == std::decay_t::shape_type({m_nnode, m_ndim})); Eigen::VectorXd X_u = this->asDofs_u(x); Eigen::VectorXd X_p = this->asDofs_p(x); Eigen::VectorXd B_p = m_Apu * X_u + m_App * X_p; #pragma omp parallel for for (size_t m = 0; m < m_nnode; ++m) { for (size_t i = 0; i < m_ndim; ++i) { if (m_part(m, i) >= m_nnu) { b(m, i) = B_p(m_part(m, i) - m_nnu); } } } } template inline void MatrixPartitioned::reaction( - const xt::xtensor& x, xt::xtensor& b) const + const xt::xtensor& x, xt::xtensor& b) const { GOOSEFEM_ASSERT(x.size() == m_ndof); GOOSEFEM_ASSERT(b.size() == m_ndof); Eigen::VectorXd X_u = this->asDofs_u(x); Eigen::VectorXd X_p = this->asDofs_p(x); Eigen::VectorXd B_p = m_Apu * X_u + m_App * X_p; #pragma omp parallel for for (size_t d = 0; d < m_nnp; ++d) { b(m_iip(d)) = B_p(d); } } template inline void MatrixPartitioned::reaction_p( - const xt::xtensor& x_u, - const xt::xtensor& x_p, - xt::xtensor& b_p) const + const xt::xtensor& x_u, + const xt::xtensor& x_p, + xt::xtensor& b_p) const { GOOSEFEM_ASSERT(x_u.size() == m_nnu); GOOSEFEM_ASSERT(x_p.size() == m_nnp); GOOSEFEM_ASSERT(b_p.size() == m_nnp); Eigen::VectorXd X_u(m_nnu, 1); Eigen::VectorXd X_p(m_nnp, 1); std::copy(x_u.begin(), x_u.end(), X_u.data()); std::copy(x_p.begin(), x_p.end(), X_p.data()); Eigen::VectorXd B_p = m_Apu * X_u + m_App * X_p; std::copy(B_p.data(), B_p.data() + m_nnp, b_p.begin()); } template -inline xt::xtensor -MatrixPartitioned::Solve(const xt::xtensor& b, const xt::xtensor& x) +inline xt::xtensor +MatrixPartitioned::Solve(const xt::xtensor& b, const xt::xtensor& x) { - xt::xtensor out = x; + xt::xtensor out = x; this->solve(b, out); return out; } template -inline xt::xtensor -MatrixPartitioned::Solve(const xt::xtensor& b, const xt::xtensor& x) +inline xt::xtensor +MatrixPartitioned::Solve(const xt::xtensor& b, const xt::xtensor& x) { - xt::xtensor out = x; + xt::xtensor out = x; this->solve(b, out); return out; } template -inline xt::xtensor MatrixPartitioned::Solve_u( - const xt::xtensor& b_u, const xt::xtensor& x_p) +inline xt::xtensor MatrixPartitioned::Solve_u( + const xt::xtensor& b_u, const xt::xtensor& x_p) { - xt::xtensor x_u = xt::empty({m_nnu}); + xt::xtensor x_u = xt::empty({m_nnu}); this->solve_u(b_u, x_p, x_u); return x_u; } template -inline xt::xtensor MatrixPartitioned::Reaction( - const xt::xtensor& x, const xt::xtensor& b) const +inline xt::xtensor MatrixPartitioned::Reaction( + const xt::xtensor& x, const xt::xtensor& b) const { - xt::xtensor out = b; + xt::xtensor out = b; this->reaction(x, out); return out; } template -inline xt::xtensor MatrixPartitioned::Reaction( - const xt::xtensor& x, const xt::xtensor& b) const +inline xt::xtensor MatrixPartitioned::Reaction( + const xt::xtensor& x, const xt::xtensor& b) const { - xt::xtensor out = b; + xt::xtensor out = b; this->reaction(x, out); return out; } template -inline xt::xtensor MatrixPartitioned::Reaction_p( - const xt::xtensor& x_u, const xt::xtensor& x_p) const +inline xt::xtensor MatrixPartitioned::Reaction_p( + const xt::xtensor& x_u, const xt::xtensor& x_p) const { - xt::xtensor b_p = xt::empty({m_nnp}); + xt::xtensor b_p = xt::empty({m_nnp}); this->reaction_p(x_u, x_p, b_p); return b_p; } template inline Eigen::VectorXd -MatrixPartitioned::asDofs_u(const xt::xtensor& dofval) const +MatrixPartitioned::asDofs_u(const xt::xtensor& dofval) const { assert(dofval.size() == m_ndof); Eigen::VectorXd dofval_u(m_nnu, 1); #pragma omp parallel for for (size_t d = 0; d < m_nnu; ++d) { dofval_u(d) = dofval(m_iiu(d)); } return dofval_u; } template inline Eigen::VectorXd -MatrixPartitioned::asDofs_u(const xt::xtensor& nodevec) const +MatrixPartitioned::asDofs_u(const xt::xtensor& nodevec) const { assert(nodevec.shape() == std::decay_t::shape_type({m_nnode, m_ndim})); Eigen::VectorXd dofval_u(m_nnu, 1); #pragma omp parallel for for (size_t m = 0; m < m_nnode; ++m) { for (size_t i = 0; i < m_ndim; ++i) { if (m_part(m, i) < m_nnu) { dofval_u(m_part(m, i)) = nodevec(m, i); } } } return dofval_u; } template inline Eigen::VectorXd -MatrixPartitioned::asDofs_p(const xt::xtensor& dofval) const +MatrixPartitioned::asDofs_p(const xt::xtensor& dofval) const { assert(dofval.size() == m_ndof); Eigen::VectorXd dofval_p(m_nnp, 1); #pragma omp parallel for for (size_t d = 0; d < m_nnp; ++d) { dofval_p(d) = dofval(m_iip(d)); } return dofval_p; } template inline Eigen::VectorXd -MatrixPartitioned::asDofs_p(const xt::xtensor& nodevec) const +MatrixPartitioned::asDofs_p(const xt::xtensor& nodevec) const { assert(nodevec.shape() == std::decay_t::shape_type({m_nnode, m_ndim})); Eigen::VectorXd dofval_p(m_nnp, 1); #pragma omp parallel for for (size_t m = 0; m < m_nnode; ++m) { for (size_t i = 0; i < m_ndim; ++i) { if (m_part(m, i) >= m_nnu) { dofval_p(m_part(m, i) - m_nnu) = nodevec(m, i); } } } return dofval_p; } } // namespace GooseFEM #endif diff --git a/include/GooseFEM/MatrixPartitionedTyings.h b/include/GooseFEM/MatrixPartitionedTyings.h index 724242f..8b3fa0c 100644 --- a/include/GooseFEM/MatrixPartitionedTyings.h +++ b/include/GooseFEM/MatrixPartitionedTyings.h @@ -1,150 +1,150 @@ /* (c - GPLv3) T.W.J. de Geus (Tom) | tom@geus.me | www.geus.me | github.com/tdegeus/GooseFEM */ #ifndef GOOSEFEM_MATRIXPARTITIONEDTYINGS_H #define GOOSEFEM_MATRIXPARTITIONEDTYINGS_H #include "config.h" #include #include #include namespace GooseFEM { template >> class MatrixPartitionedTyings { public: // Constructors MatrixPartitionedTyings() = default; MatrixPartitionedTyings( - const xt::xtensor& conn, - const xt::xtensor& dofs, + const xt::xtensor& conn, + const xt::xtensor& dofs, const Eigen::SparseMatrix& Cdu, const Eigen::SparseMatrix& Cdp); // Dimensions size_t nelem() const; // number of elements size_t nne() const; // number of nodes per element size_t nnode() const; // number of nodes size_t ndim() const; // number of dimensions size_t ndof() const; // number of DOFs size_t nnu() const; // number of independent, unknown DOFs size_t nnp() const; // number of independent, prescribed DOFs size_t nni() const; // number of independent DOFs size_t nnd() const; // number of dependent DOFs // DOF lists - xt::xtensor dofs() const; // DOFs - xt::xtensor iiu() const; // independent, unknown DOFs - xt::xtensor iip() const; // independent, prescribed DOFs - xt::xtensor iii() const; // independent DOFs - xt::xtensor iid() const; // dependent DOFs + xt::xtensor dofs() const; // DOFs + xt::xtensor iiu() const; // independent, unknown DOFs + xt::xtensor iip() const; // independent, prescribed DOFs + xt::xtensor iii() const; // independent DOFs + xt::xtensor iid() const; // dependent DOFs // Assemble from matrices stored per element [nelem, nne*ndim, nne*ndim] - void assemble(const xt::xtensor& elemmat); + void assemble(const xt::xtensor& elemmat); // Solve: // A' = A_ii + K_id * C_di + C_di^T * K_di + C_di^T * K_dd * C_di // b' = b_i + C_di^T * b_d // x_u = A'_uu \ ( b'_u - A'_up * x_p ) // x_i = [x_u, x_p] // x_d = C_di * x_i - void solve(const xt::xtensor& b, xt::xtensor& x); // updates x_u and x_d - void solve(const xt::xtensor& b, xt::xtensor& x); // updates x_u and x_d + void solve(const xt::xtensor& b, xt::xtensor& x); // updates x_u and x_d + void solve(const xt::xtensor& b, xt::xtensor& x); // updates x_u and x_d void solve_u( - const xt::xtensor& b_u, - const xt::xtensor& b_d, - const xt::xtensor& x_p, - xt::xtensor& x_u); + const xt::xtensor& b_u, + const xt::xtensor& b_d, + const xt::xtensor& x_p, + xt::xtensor& x_u); // Auto-allocation of the functions above - xt::xtensor Solve(const xt::xtensor& b, const xt::xtensor& x); - xt::xtensor Solve(const xt::xtensor& b, const xt::xtensor& x); + xt::xtensor Solve(const xt::xtensor& b, const xt::xtensor& x); + xt::xtensor Solve(const xt::xtensor& b, const xt::xtensor& x); - xt::xtensor Solve_u( - const xt::xtensor& b_u, - const xt::xtensor& b_d, - const xt::xtensor& x_p); + xt::xtensor Solve_u( + const xt::xtensor& b_u, + const xt::xtensor& b_d, + const xt::xtensor& x_p); private: // The matrix Eigen::SparseMatrix m_Auu; Eigen::SparseMatrix m_Aup; Eigen::SparseMatrix m_Apu; Eigen::SparseMatrix m_App; Eigen::SparseMatrix m_Aud; Eigen::SparseMatrix m_Apd; Eigen::SparseMatrix m_Adu; Eigen::SparseMatrix m_Adp; Eigen::SparseMatrix m_Add; // The matrix for which the tyings have been applied Eigen::SparseMatrix m_ACuu; Eigen::SparseMatrix m_ACup; Eigen::SparseMatrix m_ACpu; Eigen::SparseMatrix m_ACpp; // Matrix entries std::vector> m_Tuu; std::vector> m_Tup; std::vector> m_Tpu; std::vector> m_Tpp; std::vector> m_Tud; std::vector> m_Tpd; std::vector> m_Tdu; std::vector> m_Tdp; std::vector> m_Tdd; // Solver (re-used to solve different RHS) Solver m_solver; // Signal changes to data compare to the last inverse bool m_factor = false; // Bookkeeping - xt::xtensor m_conn; // connectivity [nelem, nne ] - xt::xtensor m_dofs; // DOF-numbers per node [nnode, ndim] - xt::xtensor m_iiu; // unknown DOFs [nnu] - xt::xtensor m_iip; // prescribed DOFs [nnp] - xt::xtensor m_iid; // dependent DOFs [nnd] + xt::xtensor m_conn; // connectivity [nelem, nne ] + xt::xtensor m_dofs; // DOF-numbers per node [nnode, ndim] + xt::xtensor m_iiu; // unknown DOFs [nnu] + xt::xtensor m_iip; // prescribed DOFs [nnp] + xt::xtensor m_iid; // dependent DOFs [nnd] // Dimensions size_t m_nelem; // number of elements size_t m_nne; // number of nodes per element size_t m_nnode; // number of nodes size_t m_ndim; // number of dimensions size_t m_ndof; // number of DOFs size_t m_nnu; // number of independent, unknown DOFs size_t m_nnp; // number of independent, prescribed DOFs size_t m_nni; // number of independent DOFs size_t m_nnd; // number of dependent DOFs // Tyings Eigen::SparseMatrix m_Cdu; Eigen::SparseMatrix m_Cdp; Eigen::SparseMatrix m_Cud; Eigen::SparseMatrix m_Cpd; // Compute inverse (automatically evaluated by "solve") void factorize(); // Convert arrays (Eigen version of VectorPartitioned, which contains public functions) - Eigen::VectorXd asDofs_u(const xt::xtensor& dofval) const; - Eigen::VectorXd asDofs_u(const xt::xtensor& nodevec) const; - Eigen::VectorXd asDofs_p(const xt::xtensor& dofval) const; - Eigen::VectorXd asDofs_p(const xt::xtensor& nodevec) const; - Eigen::VectorXd asDofs_d(const xt::xtensor& dofval) const; - Eigen::VectorXd asDofs_d(const xt::xtensor& nodevec) const; + Eigen::VectorXd asDofs_u(const xt::xtensor& dofval) const; + Eigen::VectorXd asDofs_u(const xt::xtensor& nodevec) const; + Eigen::VectorXd asDofs_p(const xt::xtensor& dofval) const; + Eigen::VectorXd asDofs_p(const xt::xtensor& nodevec) const; + Eigen::VectorXd asDofs_d(const xt::xtensor& dofval) const; + Eigen::VectorXd asDofs_d(const xt::xtensor& nodevec) const; }; } // namespace GooseFEM #include "MatrixPartitionedTyings.hpp" #endif diff --git a/include/GooseFEM/MatrixPartitionedTyings.hpp b/include/GooseFEM/MatrixPartitionedTyings.hpp index 4ab7068..e38bc83 100644 --- a/include/GooseFEM/MatrixPartitionedTyings.hpp +++ b/include/GooseFEM/MatrixPartitionedTyings.hpp @@ -1,487 +1,477 @@ /* (c - GPLv3) T.W.J. de Geus (Tom) | tom@geus.me | www.geus.me | github.com/tdegeus/GooseFEM */ #ifndef GOOSEFEM_MATRIXPARTITIONEDTYINGS_HPP #define GOOSEFEM_MATRIXPARTITIONEDTYINGS_HPP #include "MatrixPartitionedTyings.h" namespace GooseFEM { template inline MatrixPartitionedTyings::MatrixPartitionedTyings( - const xt::xtensor& conn, - const xt::xtensor& dofs, + const xt::xtensor& conn, + const xt::xtensor& dofs, const Eigen::SparseMatrix& Cdu, const Eigen::SparseMatrix& Cdp) : m_conn(conn), m_dofs(dofs), m_Cdu(Cdu), m_Cdp(Cdp) { GOOSEFEM_ASSERT(Cdu.rows() == Cdp.rows()); m_nnu = static_cast(m_Cdu.cols()); m_nnp = static_cast(m_Cdp.cols()); m_nnd = static_cast(m_Cdp.rows()); m_nni = m_nnu + m_nnp; m_ndof = m_nni + m_nnd; m_iiu = xt::arange(m_nnu); m_iip = xt::arange(m_nnu, m_nnu + m_nnp); m_iid = xt::arange(m_nni, m_nni + m_nnd); m_nelem = m_conn.shape(0); m_nne = m_conn.shape(1); m_nnode = m_dofs.shape(0); m_ndim = m_dofs.shape(1); m_Cud = m_Cdu.transpose(); m_Cpd = m_Cdp.transpose(); m_Tuu.reserve(m_nelem * m_nne * m_ndim * m_nne * m_ndim); m_Tup.reserve(m_nelem * m_nne * m_ndim * m_nne * m_ndim); m_Tpu.reserve(m_nelem * m_nne * m_ndim * m_nne * m_ndim); m_Tpp.reserve(m_nelem * m_nne * m_ndim * m_nne * m_ndim); m_Tud.reserve(m_nelem * m_nne * m_ndim * m_nne * m_ndim); m_Tpd.reserve(m_nelem * m_nne * m_ndim * m_nne * m_ndim); m_Tdu.reserve(m_nelem * m_nne * m_ndim * m_nne * m_ndim); m_Tdp.reserve(m_nelem * m_nne * m_ndim * m_nne * m_ndim); m_Tdd.reserve(m_nelem * m_nne * m_ndim * m_nne * m_ndim); m_Auu.resize(m_nnu, m_nnu); m_Aup.resize(m_nnu, m_nnp); m_Apu.resize(m_nnp, m_nnu); m_App.resize(m_nnp, m_nnp); m_Aud.resize(m_nnu, m_nnd); m_Apd.resize(m_nnp, m_nnd); m_Adu.resize(m_nnd, m_nnu); m_Adp.resize(m_nnd, m_nnp); m_Add.resize(m_nnd, m_nnd); GOOSEFEM_ASSERT(m_ndof <= m_nnode * m_ndim); GOOSEFEM_ASSERT(m_ndof == xt::amax(m_dofs)[0] + 1); } template inline size_t MatrixPartitionedTyings::nelem() const { return m_nelem; } template inline size_t MatrixPartitionedTyings::nne() const { return m_nne; } template inline size_t MatrixPartitionedTyings::nnode() const { return m_nnode; } template inline size_t MatrixPartitionedTyings::ndim() const { return m_ndim; } template inline size_t MatrixPartitionedTyings::ndof() const { return m_ndof; } template inline size_t MatrixPartitionedTyings::nnu() const { return m_nnu; } template inline size_t MatrixPartitionedTyings::nnp() const { return m_nnp; } template inline size_t MatrixPartitionedTyings::nni() const { return m_nni; } template inline size_t MatrixPartitionedTyings::nnd() const { return m_nnd; } template -inline xt::xtensor MatrixPartitionedTyings::dofs() const +inline xt::xtensor MatrixPartitionedTyings::dofs() const { return m_dofs; } template -inline xt::xtensor MatrixPartitionedTyings::iiu() const +inline xt::xtensor MatrixPartitionedTyings::iiu() const { return m_iiu; } template -inline xt::xtensor MatrixPartitionedTyings::iip() const +inline xt::xtensor MatrixPartitionedTyings::iip() const { return m_iip; } template -inline xt::xtensor MatrixPartitionedTyings::iii() const +inline xt::xtensor MatrixPartitionedTyings::iii() const { return xt::arange(m_nni); } template -inline xt::xtensor MatrixPartitionedTyings::iid() const +inline xt::xtensor MatrixPartitionedTyings::iid() const { return m_iid; } template inline void MatrixPartitionedTyings::factorize() { if (!m_factor) { return; } m_ACuu = m_Auu + m_Aud * m_Cdu + m_Cud * m_Adu + m_Cud * m_Add * m_Cdu; m_ACup = m_Aup + m_Aud * m_Cdp + m_Cud * m_Adp + m_Cud * m_Add * m_Cdp; // m_ACpu = m_Apu + m_Apd * m_Cdu + m_Cpd * m_Adu + m_Cpd * m_Add * m_Cdu; // m_ACpp = m_App + m_Apd * m_Cdp + m_Cpd * m_Adp + m_Cpd * m_Add * m_Cdp; m_solver.compute(m_ACuu); m_factor = false; } template -inline void MatrixPartitionedTyings::assemble(const xt::xtensor& elemmat) +inline void MatrixPartitionedTyings::assemble(const xt::xtensor& elemmat) { GOOSEFEM_ASSERT( elemmat.shape() == std::decay_t::shape_type({m_nelem, m_nne * m_ndim, m_nne * m_ndim})); m_Tuu.clear(); m_Tup.clear(); m_Tpu.clear(); m_Tpp.clear(); m_Tud.clear(); m_Tpd.clear(); m_Tdu.clear(); m_Tdp.clear(); m_Tdd.clear(); for (size_t e = 0; e < m_nelem; ++e) { for (size_t m = 0; m < m_nne; ++m) { for (size_t i = 0; i < m_ndim; ++i) { size_t di = m_dofs(m_conn(e, m), i); for (size_t n = 0; n < m_nne; ++n) { for (size_t j = 0; j < m_ndim; ++j) { size_t dj = m_dofs(m_conn(e, n), j); if (di < m_nnu && dj < m_nnu) { m_Tuu.push_back(Eigen::Triplet( - di, - dj, - elemmat(e, m * m_ndim + i, n * m_ndim + j))); + di, dj, elemmat(e, m * m_ndim + i, n * m_ndim + j))); } else if (di < m_nnu && dj < m_nni) { m_Tup.push_back(Eigen::Triplet( - di, - dj - m_nnu, - elemmat(e, m * m_ndim + i, n * m_ndim + j))); + di, dj - m_nnu, elemmat(e, m * m_ndim + i, n * m_ndim + j))); } else if (di < m_nnu) { m_Tud.push_back(Eigen::Triplet( - di, - dj - m_nni, - elemmat(e, m * m_ndim + i, n * m_ndim + j))); + di, dj - m_nni, elemmat(e, m * m_ndim + i, n * m_ndim + j))); } else if (di < m_nni && dj < m_nnu) { m_Tpu.push_back(Eigen::Triplet( - di - m_nnu, - dj, - elemmat(e, m * m_ndim + i, n * m_ndim + j))); + di - m_nnu, dj, elemmat(e, m * m_ndim + i, n * m_ndim + j))); } else if (di < m_nni && dj < m_nni) { m_Tpp.push_back(Eigen::Triplet( di - m_nnu, dj - m_nnu, elemmat(e, m * m_ndim + i, n * m_ndim + j))); } else if (di < m_nni) { m_Tpd.push_back(Eigen::Triplet( di - m_nnu, dj - m_nni, elemmat(e, m * m_ndim + i, n * m_ndim + j))); } else if (dj < m_nnu) { m_Tdu.push_back(Eigen::Triplet( - di - m_nni, - dj, - elemmat(e, m * m_ndim + i, n * m_ndim + j))); + di - m_nni, dj, elemmat(e, m * m_ndim + i, n * m_ndim + j))); } else if (dj < m_nni) { m_Tdp.push_back(Eigen::Triplet( di - m_nni, dj - m_nnu, elemmat(e, m * m_ndim + i, n * m_ndim + j))); } else { m_Tdd.push_back(Eigen::Triplet( di - m_nni, dj - m_nni, elemmat(e, m * m_ndim + i, n * m_ndim + j))); } } } } } } m_Auu.setFromTriplets(m_Tuu.begin(), m_Tuu.end()); m_Aup.setFromTriplets(m_Tup.begin(), m_Tup.end()); m_Apu.setFromTriplets(m_Tpu.begin(), m_Tpu.end()); m_App.setFromTriplets(m_Tpp.begin(), m_Tpp.end()); m_Aud.setFromTriplets(m_Tud.begin(), m_Tud.end()); m_Apd.setFromTriplets(m_Tpd.begin(), m_Tpd.end()); m_Adu.setFromTriplets(m_Tdu.begin(), m_Tdu.end()); m_Adp.setFromTriplets(m_Tdp.begin(), m_Tdp.end()); m_Add.setFromTriplets(m_Tdd.begin(), m_Tdd.end()); m_factor = true; } template inline void -MatrixPartitionedTyings::solve(const xt::xtensor& b, xt::xtensor& x) +MatrixPartitionedTyings::solve(const xt::xtensor& b, xt::xtensor& x) { GOOSEFEM_ASSERT(b.shape() == std::decay_t::shape_type({m_nnode, m_ndim})); GOOSEFEM_ASSERT(x.shape() == std::decay_t::shape_type({m_nnode, m_ndim})); this->factorize(); Eigen::VectorXd B_u = this->asDofs_u(b); Eigen::VectorXd B_d = this->asDofs_d(b); Eigen::VectorXd X_p = this->asDofs_p(x); B_u += m_Cud * B_d; Eigen::VectorXd X_u = m_solver.solve(Eigen::VectorXd(B_u - m_ACup * X_p)); Eigen::VectorXd X_d = m_Cdu * X_u + m_Cdp * X_p; #pragma omp parallel for for (size_t m = 0; m < m_nnode; ++m) { for (size_t i = 0; i < m_ndim; ++i) { if (m_dofs(m, i) < m_nnu) { x(m, i) = X_u(m_dofs(m, i)); } else if (m_dofs(m, i) >= m_nni) { x(m, i) = X_d(m_dofs(m, i) - m_nni); } } } } template inline void -MatrixPartitionedTyings::solve(const xt::xtensor& b, xt::xtensor& x) +MatrixPartitionedTyings::solve(const xt::xtensor& b, xt::xtensor& x) { GOOSEFEM_ASSERT(b.size() == m_ndof); GOOSEFEM_ASSERT(x.size() == m_ndof); this->factorize(); Eigen::VectorXd B_u = this->asDofs_u(b); Eigen::VectorXd B_d = this->asDofs_d(b); Eigen::VectorXd X_p = this->asDofs_p(x); Eigen::VectorXd X_u = m_solver.solve(Eigen::VectorXd(B_u - m_ACup * X_p)); Eigen::VectorXd X_d = m_Cdu * X_u + m_Cdp * X_p; #pragma omp parallel for for (size_t d = 0; d < m_nnu; ++d) { x(m_iiu(d)) = X_u(d); } #pragma omp parallel for for (size_t d = 0; d < m_nnd; ++d) { x(m_iid(d)) = X_d(d); } } template inline void MatrixPartitionedTyings::solve_u( - const xt::xtensor& b_u, - const xt::xtensor& b_d, - const xt::xtensor& x_p, - xt::xtensor& x_u) + const xt::xtensor& b_u, + const xt::xtensor& b_d, + const xt::xtensor& x_p, + xt::xtensor& x_u) { GOOSEFEM_ASSERT(b_u.size() == m_nnu); GOOSEFEM_ASSERT(b_d.size() == m_nnd); GOOSEFEM_ASSERT(x_p.size() == m_nnp); GOOSEFEM_ASSERT(x_u.size() == m_nnu); this->factorize(); Eigen::VectorXd B_u(m_nnu, 1); Eigen::VectorXd B_d(m_nnd, 1); Eigen::VectorXd X_p(m_nnp, 1); std::copy(b_u.begin(), b_u.end(), B_u.data()); std::copy(b_d.begin(), b_d.end(), B_d.data()); std::copy(x_p.begin(), x_p.end(), X_p.data()); Eigen::VectorXd X_u = m_solver.solve(Eigen::VectorXd(B_u - m_ACup * X_p)); std::copy(X_u.data(), X_u.data() + m_nnu, x_u.begin()); } template -inline xt::xtensor MatrixPartitionedTyings::Solve( - const xt::xtensor& b, const xt::xtensor& x) +inline xt::xtensor MatrixPartitionedTyings::Solve( + const xt::xtensor& b, const xt::xtensor& x) { - xt::xtensor out = x; + xt::xtensor out = x; this->solve(b, out); return out; } template -inline xt::xtensor MatrixPartitionedTyings::Solve( - const xt::xtensor& b, const xt::xtensor& x) +inline xt::xtensor MatrixPartitionedTyings::Solve( + const xt::xtensor& b, const xt::xtensor& x) { - xt::xtensor out = x; + xt::xtensor out = x; this->solve(b, out); return out; } template -inline xt::xtensor MatrixPartitionedTyings::Solve_u( - const xt::xtensor& b_u, - const xt::xtensor& b_d, - const xt::xtensor& x_p) +inline xt::xtensor MatrixPartitionedTyings::Solve_u( + const xt::xtensor& b_u, + const xt::xtensor& b_d, + const xt::xtensor& x_p) { - xt::xtensor x_u = xt::empty({m_nnu}); + xt::xtensor x_u = xt::empty({m_nnu}); this->solve_u(b_u, b_d, x_p, x_u); return x_u; } template inline Eigen::VectorXd -MatrixPartitionedTyings::asDofs_u(const xt::xtensor& dofval) const +MatrixPartitionedTyings::asDofs_u(const xt::xtensor& dofval) const { assert(dofval.size() == m_ndof); Eigen::VectorXd dofval_u(m_nnu, 1); #pragma omp parallel for for (size_t d = 0; d < m_nnu; ++d) { dofval_u(d) = dofval(m_iiu(d)); } return dofval_u; } template inline Eigen::VectorXd -MatrixPartitionedTyings::asDofs_u(const xt::xtensor& nodevec) const +MatrixPartitionedTyings::asDofs_u(const xt::xtensor& nodevec) const { assert(nodevec.shape() == std::decay_t::shape_type({m_nnode, m_ndim})); Eigen::VectorXd dofval_u(m_nnu, 1); #pragma omp parallel for for (size_t m = 0; m < m_nnode; ++m) { for (size_t i = 0; i < m_ndim; ++i) { if (m_dofs(m, i) < m_nnu) { dofval_u(m_dofs(m, i)) = nodevec(m, i); } } } return dofval_u; } template inline Eigen::VectorXd -MatrixPartitionedTyings::asDofs_p(const xt::xtensor& dofval) const +MatrixPartitionedTyings::asDofs_p(const xt::xtensor& dofval) const { assert(dofval.size() == m_ndof); Eigen::VectorXd dofval_p(m_nnp, 1); #pragma omp parallel for for (size_t d = 0; d < m_nnp; ++d) { dofval_p(d) = dofval(m_iip(d)); } return dofval_p; } template inline Eigen::VectorXd -MatrixPartitionedTyings::asDofs_p(const xt::xtensor& nodevec) const +MatrixPartitionedTyings::asDofs_p(const xt::xtensor& nodevec) const { assert(nodevec.shape() == std::decay_t::shape_type({m_nnode, m_ndim})); Eigen::VectorXd dofval_p(m_nnp, 1); #pragma omp parallel for for (size_t m = 0; m < m_nnode; ++m) { for (size_t i = 0; i < m_ndim; ++i) { if (m_dofs(m, i) >= m_nnu && m_dofs(m, i) < m_nni) { dofval_p(m_dofs(m, i) - m_nnu) = nodevec(m, i); } } } return dofval_p; } template inline Eigen::VectorXd -MatrixPartitionedTyings::asDofs_d(const xt::xtensor& dofval) const +MatrixPartitionedTyings::asDofs_d(const xt::xtensor& dofval) const { assert(dofval.size() == m_ndof); Eigen::VectorXd dofval_d(m_nnd, 1); #pragma omp parallel for for (size_t d = 0; d < m_nnd; ++d) { dofval_d(d) = dofval(m_iip(d)); } return dofval_d; } template inline Eigen::VectorXd -MatrixPartitionedTyings::asDofs_d(const xt::xtensor& nodevec) const +MatrixPartitionedTyings::asDofs_d(const xt::xtensor& nodevec) const { assert(nodevec.shape() == std::decay_t::shape_type({m_nnode, m_ndim})); Eigen::VectorXd dofval_d(m_nnd, 1); #pragma omp parallel for for (size_t m = 0; m < m_nnode; ++m) { for (size_t i = 0; i < m_ndim; ++i) { if (m_dofs(m, i) >= m_nni) { dofval_d(m_dofs(m, i) - m_nni) = nodevec(m, i); } } } return dofval_d; } } // namespace GooseFEM #endif diff --git a/include/GooseFEM/Mesh.h b/include/GooseFEM/Mesh.h index 878b79a..9c18505 100644 --- a/include/GooseFEM/Mesh.h +++ b/include/GooseFEM/Mesh.h @@ -1,99 +1,96 @@ /* (c - GPLv3) T.W.J. de Geus (Tom) | tom@geus.me | www.geus.me | github.com/tdegeus/GooseFEM */ #ifndef GOOSEFEM_MESH_H #define GOOSEFEM_MESH_H #include "config.h" namespace GooseFEM { namespace Mesh { enum class ElementType { Quad4, Hex8, Tri3 }; // Renumber to lowest possible index. For example [0,3,4,2] -> [0,2,3,1] class Renumber { public: // constructors Renumber() = default; Renumber(const xt::xarray& dofs); // get renumbered DOFs (same as "Renumber::apply(dofs)") - xt::xtensor get(const xt::xtensor& dofs) const; + xt::xtensor get(const xt::xtensor& dofs) const; // apply renumbering to other set template T apply(const T& list) const; // get the list needed to renumber, e.g.: // dofs_renumbered(i,j) = index(dofs(i,j)) - xt::xtensor index() const; + xt::xtensor index() const; private: - xt::xtensor m_renum; + xt::xtensor m_renum; }; // Reorder to lowest possible index, in specific order. // // For example for "Reorder({iiu,iip})" after reordering: // // iiu = xt::range(nnu); // iip = xt::range(nnp) + nnu; class Reorder { public: // constructors Reorder() = default; - Reorder(const std::initializer_list> args); + Reorder(const std::initializer_list> args); // get reordered DOFs (same as "Reorder::apply(dofs)") - xt::xtensor get(const xt::xtensor& dofs) const; + xt::xtensor get(const xt::xtensor& dofs) const; // apply renumbering to other set template T apply(const T& list) const; // get the list needed to reorder, e.g.: // dofs_reordered(i,j) = index(dofs(i,j)) - xt::xtensor index() const; + xt::xtensor index() const; private: - xt::xtensor m_renum; + xt::xtensor m_renum; }; // list with DOF-numbers in sequential order -inline xt::xtensor dofs(size_t nnode, size_t ndim); +inline xt::xtensor dofs(size_t nnode, size_t ndim); // renumber to lowest possible index (see "GooseFEM::Mesh::Renumber") -inline xt::xtensor renumber(const xt::xtensor& dofs); +inline xt::xtensor renumber(const xt::xtensor& dofs); // number of elements connected to each node -inline xt::xtensor coordination(const xt::xtensor& conn); +inline xt::xtensor coordination(const xt::xtensor& conn); // elements connected to each node -inline std::vector> elem2node(const xt::xtensor& conn); +inline std::vector> elem2node(const xt::xtensor& conn); // return size of each element edge -inline xt::xtensor edgesize( - const xt::xtensor& coor, - const xt::xtensor& conn, - ElementType type); +inline xt::xtensor edgesize( + const xt::xtensor& coor, const xt::xtensor& conn, ElementType type); // return size of each element edge: extract element-type based on shape of "conn" -inline xt::xtensor edgesize( - const xt::xtensor& coor, - const xt::xtensor& conn); +inline xt::xtensor edgesize( + const xt::xtensor& coor, const xt::xtensor& conn); } // namespace Mesh } // namespace GooseFEM #include "Mesh.hpp" #endif diff --git a/include/GooseFEM/Mesh.hpp b/include/GooseFEM/Mesh.hpp index 3d33899..d9f3117 100644 --- a/include/GooseFEM/Mesh.hpp +++ b/include/GooseFEM/Mesh.hpp @@ -1,206 +1,203 @@ /* (c - GPLv3) T.W.J. de Geus (Tom) | tom@geus.me | www.geus.me | github.com/tdegeus/GooseFEM */ #ifndef GOOSEFEM_MESH_HPP #define GOOSEFEM_MESH_HPP #include "Mesh.h" namespace GooseFEM { namespace Mesh { inline Renumber::Renumber(const xt::xarray& dofs) { size_t n = xt::amax(dofs)[0] + 1; size_t i = 0; - xt::xtensor unique = xt::unique(dofs); + xt::xtensor unique = xt::unique(dofs); m_renum = xt::empty({n}); for (auto& j : unique) { m_renum(j) = i; ++i; } } // out(i,j) = renum(list(i,j)) template T Renumber::apply(const T& list) const { T out = T::from_shape(list.shape()); auto jt = out.begin(); for (auto it = list.begin(); it != list.end(); ++it, ++jt) { *jt = m_renum(*it); } return out; } -inline xt::xtensor Renumber::get(const xt::xtensor& dofs) const +inline xt::xtensor Renumber::get(const xt::xtensor& dofs) const { return this->apply(dofs); } -inline xt::xtensor Renumber::index() const +inline xt::xtensor Renumber::index() const { return m_renum; } -inline Reorder::Reorder(const std::initializer_list> args) +inline Reorder::Reorder(const std::initializer_list> args) { size_t n = 0; size_t i = 0; for (auto& arg : args) { if (arg.size() == 0) { continue; } n = std::max(n, xt::amax(arg)[0] + 1); } #ifdef GOOSEFEM_ENABLE_ASSERT for (auto& arg : args) GOOSEFEM_ASSERT(xt::unique(arg) == xt::sort(arg)); #endif m_renum = xt::empty({n}); for (auto& arg : args) { for (auto& j : arg) { m_renum(j) = i; ++i; } } } -inline xt::xtensor Reorder::get(const xt::xtensor& dofs) const +inline xt::xtensor Reorder::get(const xt::xtensor& dofs) const { return this->apply(dofs); } -inline xt::xtensor Reorder::index() const +inline xt::xtensor Reorder::index() const { return m_renum; } // apply renumbering, e.g. for a matrix: // // out(i,j) = renum(list(i,j)) template T Reorder::apply(const T& list) const { T out = T::from_shape(list.shape()); auto jt = out.begin(); for (auto it = list.begin(); it != list.end(); ++it, ++jt) { *jt = m_renum(*it); } return out; } -inline xt::xtensor renumber(const xt::xtensor& dofs) +inline xt::xtensor renumber(const xt::xtensor& dofs) { return Renumber(dofs).get(dofs); } -inline xt::xtensor dofs(size_t nnode, size_t ndim) +inline xt::xtensor dofs(size_t nnode, size_t ndim) { return xt::reshape_view(xt::arange(nnode * ndim), {nnode, ndim}); } -inline xt::xtensor coordination(const xt::xtensor& conn) +inline xt::xtensor coordination(const xt::xtensor& conn) { size_t nnode = xt::amax(conn)[0] + 1; - xt::xtensor N = xt::zeros({nnode}); + xt::xtensor N = xt::zeros({nnode}); for (auto it = conn.begin(); it != conn.end(); ++it) { N(*it) += 1; } return N; } -inline std::vector> elem2node(const xt::xtensor& conn) +inline std::vector> elem2node(const xt::xtensor& conn) { auto N = coordination(conn); auto nnode = N.size(); std::vector> out; out.resize(nnode); for (size_t i = 0; i < nnode; ++i) { out[i].reserve(N(i)); } for (size_t e = 0; e < conn.shape(0); ++e) { for (size_t m = 0; m < conn.shape(1); ++m) { out[conn(e, m)].push_back(e); } } return out; } -inline xt::xtensor edgesize( - const xt::xtensor& coor, - const xt::xtensor& conn, - ElementType type) +inline xt::xtensor edgesize( + const xt::xtensor& coor, const xt::xtensor& conn, ElementType type) { GOOSEFEM_ASSERT(xt::amax(conn)() < coor.shape(0)); if (type == ElementType::Quad4) { GOOSEFEM_ASSERT(coor.shape(1) == 2ul); GOOSEFEM_ASSERT(conn.shape(1) == 4ul); - xt::xtensor n0 = xt::view(conn, xt::all(), 0); - xt::xtensor n1 = xt::view(conn, xt::all(), 1); - xt::xtensor n2 = xt::view(conn, xt::all(), 2); - xt::xtensor n3 = xt::view(conn, xt::all(), 3); - xt::xtensor x0 = xt::view(coor, xt::keep(n0), 0); - xt::xtensor x1 = xt::view(coor, xt::keep(n1), 0); - xt::xtensor x2 = xt::view(coor, xt::keep(n2), 0); - xt::xtensor x3 = xt::view(coor, xt::keep(n3), 0); - xt::xtensor y0 = xt::view(coor, xt::keep(n0), 1); - xt::xtensor y1 = xt::view(coor, xt::keep(n1), 1); - xt::xtensor y2 = xt::view(coor, xt::keep(n2), 1); - xt::xtensor y3 = xt::view(coor, xt::keep(n3), 1); - xt::xtensor out = xt::empty(conn.shape()); + xt::xtensor n0 = xt::view(conn, xt::all(), 0); + xt::xtensor n1 = xt::view(conn, xt::all(), 1); + xt::xtensor n2 = xt::view(conn, xt::all(), 2); + xt::xtensor n3 = xt::view(conn, xt::all(), 3); + xt::xtensor x0 = xt::view(coor, xt::keep(n0), 0); + xt::xtensor x1 = xt::view(coor, xt::keep(n1), 0); + xt::xtensor x2 = xt::view(coor, xt::keep(n2), 0); + xt::xtensor x3 = xt::view(coor, xt::keep(n3), 0); + xt::xtensor y0 = xt::view(coor, xt::keep(n0), 1); + xt::xtensor y1 = xt::view(coor, xt::keep(n1), 1); + xt::xtensor y2 = xt::view(coor, xt::keep(n2), 1); + xt::xtensor y3 = xt::view(coor, xt::keep(n3), 1); + xt::xtensor out = xt::empty(conn.shape()); xt::view(out, xt::all(), 0) = xt::sqrt(xt::pow(x1 - x0, 2.0) + xt::pow(y1 - y0, 2.0)); xt::view(out, xt::all(), 1) = xt::sqrt(xt::pow(x2 - x1, 2.0) + xt::pow(y2 - y1, 2.0)); xt::view(out, xt::all(), 2) = xt::sqrt(xt::pow(x3 - x2, 2.0) + xt::pow(y3 - y2, 2.0)); xt::view(out, xt::all(), 3) = xt::sqrt(xt::pow(x0 - x3, 2.0) + xt::pow(y0 - y3, 2.0)); return out; } throw std::runtime_error("Element-type not implemented"); } -inline xt::xtensor edgesize( - const xt::xtensor& coor, - const xt::xtensor& conn) +inline xt::xtensor edgesize( + const xt::xtensor& coor, const xt::xtensor& conn) { if (coor.shape(1) == 2ul && conn.shape(1) == 3ul) { return edgesize(coor, conn, ElementType::Tri3); } if (coor.shape(1) == 2ul && conn.shape(1) == 4ul) { return edgesize(coor, conn, ElementType::Quad4); } if (coor.shape(1) == 3ul && conn.shape(1) == 8ul) { return edgesize(coor, conn, ElementType::Hex8); } throw std::runtime_error("Element-type not implemented"); } } // namespace Mesh } // namespace GooseFEM #endif diff --git a/include/GooseFEM/MeshHex8.h b/include/GooseFEM/MeshHex8.h index 920cc19..f2bc84c 100644 --- a/include/GooseFEM/MeshHex8.h +++ b/include/GooseFEM/MeshHex8.h @@ -1,366 +1,366 @@ /* (c - GPLv3) T.W.J. de Geus (Tom) | tom@geus.me | www.geus.me | github.com/tdegeus/GooseFEM */ #ifndef GOOSEFEM_MESHHEX8_H #define GOOSEFEM_MESHHEX8_H #include "config.h" namespace GooseFEM { namespace Mesh { namespace Hex8 { class Regular { public: Regular(size_t nelx, size_t nely, size_t nelz, double h = 1.); // size size_t nelem() const; // number of elements size_t nnode() const; // number of nodes size_t nne() const; // number of nodes-per-element size_t ndim() const; // number of dimensions // type ElementType getElementType() const; // mesh - xt::xtensor coor() const; // nodal positions [nnode, ndim] - xt::xtensor conn() const; // connectivity [nelem, nne] + xt::xtensor coor() const; // nodal positions [nnode, ndim] + xt::xtensor conn() const; // connectivity [nelem, nne] // boundary nodes: planes - xt::xtensor nodesFront() const; - xt::xtensor nodesBack() const; - xt::xtensor nodesLeft() const; - xt::xtensor nodesRight() const; - xt::xtensor nodesBottom() const; - xt::xtensor nodesTop() const; + xt::xtensor nodesFront() const; + xt::xtensor nodesBack() const; + xt::xtensor nodesLeft() const; + xt::xtensor nodesRight() const; + xt::xtensor nodesBottom() const; + xt::xtensor nodesTop() const; // boundary nodes: faces - xt::xtensor nodesFrontFace() const; - xt::xtensor nodesBackFace() const; - xt::xtensor nodesLeftFace() const; - xt::xtensor nodesRightFace() const; - xt::xtensor nodesBottomFace() const; - xt::xtensor nodesTopFace() const; + xt::xtensor nodesFrontFace() const; + xt::xtensor nodesBackFace() const; + xt::xtensor nodesLeftFace() const; + xt::xtensor nodesRightFace() const; + xt::xtensor nodesBottomFace() const; + xt::xtensor nodesTopFace() const; // boundary nodes: edges - xt::xtensor nodesFrontBottomEdge() const; - xt::xtensor nodesFrontTopEdge() const; - xt::xtensor nodesFrontLeftEdge() const; - xt::xtensor nodesFrontRightEdge() const; - xt::xtensor nodesBackBottomEdge() const; - xt::xtensor nodesBackTopEdge() const; - xt::xtensor nodesBackLeftEdge() const; - xt::xtensor nodesBackRightEdge() const; - xt::xtensor nodesBottomLeftEdge() const; - xt::xtensor nodesBottomRightEdge() const; - xt::xtensor nodesTopLeftEdge() const; - xt::xtensor nodesTopRightEdge() const; + xt::xtensor nodesFrontBottomEdge() const; + xt::xtensor nodesFrontTopEdge() const; + xt::xtensor nodesFrontLeftEdge() const; + xt::xtensor nodesFrontRightEdge() const; + xt::xtensor nodesBackBottomEdge() const; + xt::xtensor nodesBackTopEdge() const; + xt::xtensor nodesBackLeftEdge() const; + xt::xtensor nodesBackRightEdge() const; + xt::xtensor nodesBottomLeftEdge() const; + xt::xtensor nodesBottomRightEdge() const; + xt::xtensor nodesTopLeftEdge() const; + xt::xtensor nodesTopRightEdge() const; // boundary nodes: edges (aliases) - xt::xtensor nodesBottomFrontEdge() const; - xt::xtensor nodesBottomBackEdge() const; - xt::xtensor nodesTopFrontEdge() const; - xt::xtensor nodesTopBackEdge() const; - xt::xtensor nodesLeftBottomEdge() const; - xt::xtensor nodesLeftFrontEdge() const; - xt::xtensor nodesLeftBackEdge() const; - xt::xtensor nodesLeftTopEdge() const; - xt::xtensor nodesRightBottomEdge() const; - xt::xtensor nodesRightTopEdge() const; - xt::xtensor nodesRightFrontEdge() const; - xt::xtensor nodesRightBackEdge() const; + xt::xtensor nodesBottomFrontEdge() const; + xt::xtensor nodesBottomBackEdge() const; + xt::xtensor nodesTopFrontEdge() const; + xt::xtensor nodesTopBackEdge() const; + xt::xtensor nodesLeftBottomEdge() const; + xt::xtensor nodesLeftFrontEdge() const; + xt::xtensor nodesLeftBackEdge() const; + xt::xtensor nodesLeftTopEdge() const; + xt::xtensor nodesRightBottomEdge() const; + xt::xtensor nodesRightTopEdge() const; + xt::xtensor nodesRightFrontEdge() const; + xt::xtensor nodesRightBackEdge() const; // boundary nodes: edges, without corners - xt::xtensor nodesFrontBottomOpenEdge() const; - xt::xtensor nodesFrontTopOpenEdge() const; - xt::xtensor nodesFrontLeftOpenEdge() const; - xt::xtensor nodesFrontRightOpenEdge() const; - xt::xtensor nodesBackBottomOpenEdge() const; - xt::xtensor nodesBackTopOpenEdge() const; - xt::xtensor nodesBackLeftOpenEdge() const; - xt::xtensor nodesBackRightOpenEdge() const; - xt::xtensor nodesBottomLeftOpenEdge() const; - xt::xtensor nodesBottomRightOpenEdge() const; - xt::xtensor nodesTopLeftOpenEdge() const; - xt::xtensor nodesTopRightOpenEdge() const; + xt::xtensor nodesFrontBottomOpenEdge() const; + xt::xtensor nodesFrontTopOpenEdge() const; + xt::xtensor nodesFrontLeftOpenEdge() const; + xt::xtensor nodesFrontRightOpenEdge() const; + xt::xtensor nodesBackBottomOpenEdge() const; + xt::xtensor nodesBackTopOpenEdge() const; + xt::xtensor nodesBackLeftOpenEdge() const; + xt::xtensor nodesBackRightOpenEdge() const; + xt::xtensor nodesBottomLeftOpenEdge() const; + xt::xtensor nodesBottomRightOpenEdge() const; + xt::xtensor nodesTopLeftOpenEdge() const; + xt::xtensor nodesTopRightOpenEdge() const; // boundary nodes: edges, without corners (aliases) - xt::xtensor nodesBottomFrontOpenEdge() const; - xt::xtensor nodesBottomBackOpenEdge() const; - xt::xtensor nodesTopFrontOpenEdge() const; - xt::xtensor nodesTopBackOpenEdge() const; - xt::xtensor nodesLeftBottomOpenEdge() const; - xt::xtensor nodesLeftFrontOpenEdge() const; - xt::xtensor nodesLeftBackOpenEdge() const; - xt::xtensor nodesLeftTopOpenEdge() const; - xt::xtensor nodesRightBottomOpenEdge() const; - xt::xtensor nodesRightTopOpenEdge() const; - xt::xtensor nodesRightFrontOpenEdge() const; - xt::xtensor nodesRightBackOpenEdge() const; + xt::xtensor nodesBottomFrontOpenEdge() const; + xt::xtensor nodesBottomBackOpenEdge() const; + xt::xtensor nodesTopFrontOpenEdge() const; + xt::xtensor nodesTopBackOpenEdge() const; + xt::xtensor nodesLeftBottomOpenEdge() const; + xt::xtensor nodesLeftFrontOpenEdge() const; + xt::xtensor nodesLeftBackOpenEdge() const; + xt::xtensor nodesLeftTopOpenEdge() const; + xt::xtensor nodesRightBottomOpenEdge() const; + xt::xtensor nodesRightTopOpenEdge() const; + xt::xtensor nodesRightFrontOpenEdge() const; + xt::xtensor nodesRightBackOpenEdge() const; // boundary nodes: corners size_t nodesFrontBottomLeftCorner() const; size_t nodesFrontBottomRightCorner() const; size_t nodesFrontTopLeftCorner() const; size_t nodesFrontTopRightCorner() const; size_t nodesBackBottomLeftCorner() const; size_t nodesBackBottomRightCorner() const; size_t nodesBackTopLeftCorner() const; size_t nodesBackTopRightCorner() const; // boundary nodes: corners (aliases) size_t nodesFrontLeftBottomCorner() const; size_t nodesBottomFrontLeftCorner() const; size_t nodesBottomLeftFrontCorner() const; size_t nodesLeftFrontBottomCorner() const; size_t nodesLeftBottomFrontCorner() const; size_t nodesFrontRightBottomCorner() const; size_t nodesBottomFrontRightCorner() const; size_t nodesBottomRightFrontCorner() const; size_t nodesRightFrontBottomCorner() const; size_t nodesRightBottomFrontCorner() const; size_t nodesFrontLeftTopCorner() const; size_t nodesTopFrontLeftCorner() const; size_t nodesTopLeftFrontCorner() const; size_t nodesLeftFrontTopCorner() const; size_t nodesLeftTopFrontCorner() const; size_t nodesFrontRightTopCorner() const; size_t nodesTopFrontRightCorner() const; size_t nodesTopRightFrontCorner() const; size_t nodesRightFrontTopCorner() const; size_t nodesRightTopFrontCorner() const; size_t nodesBackLeftBottomCorner() const; size_t nodesBottomBackLeftCorner() const; size_t nodesBottomLeftBackCorner() const; size_t nodesLeftBackBottomCorner() const; size_t nodesLeftBottomBackCorner() const; size_t nodesBackRightBottomCorner() const; size_t nodesBottomBackRightCorner() const; size_t nodesBottomRightBackCorner() const; size_t nodesRightBackBottomCorner() const; size_t nodesRightBottomBackCorner() const; size_t nodesBackLeftTopCorner() const; size_t nodesTopBackLeftCorner() const; size_t nodesTopLeftBackCorner() const; size_t nodesLeftBackTopCorner() const; size_t nodesLeftTopBackCorner() const; size_t nodesBackRightTopCorner() const; size_t nodesTopBackRightCorner() const; size_t nodesTopRightBackCorner() const; size_t nodesRightBackTopCorner() const; size_t nodesRightTopBackCorner() const; // DOF-numbers for each component of each node (sequential) - xt::xtensor dofs() const; + xt::xtensor dofs() const; // DOF-numbers for the case that the periodicity if fully eliminated - xt::xtensor dofsPeriodic() const; + xt::xtensor dofsPeriodic() const; // periodic node pairs [:,2]: (independent, dependent) - xt::xtensor nodesPeriodic() const; + xt::xtensor nodesPeriodic() const; // front-bottom-left node, used as reference for periodicity size_t nodesOrigin() const; private: double m_h; // elementary element edge-size (in all directions) size_t m_nelx; // number of elements in x-direction (length == "m_nelx * m_h") size_t m_nely; // number of elements in y-direction (length == "m_nely * m_h") size_t m_nelz; // number of elements in z-direction (length == "m_nely * m_h") size_t m_nelem; // number of elements size_t m_nnode; // number of nodes static const size_t m_nne = 8; // number of nodes-per-element static const size_t m_ndim = 3; // number of dimensions }; class FineLayer { public: FineLayer(size_t nelx, size_t nely, size_t nelz, double h = 1.0, size_t nfine = 1); // size size_t nelem() const; // number of elements size_t nnode() const; // number of nodes size_t nne() const; // number of nodes-per-element size_t ndim() const; // number of dimensions size_t nelx() const; // number of elements in x-direction size_t nely() const; // number of elements in y-direction size_t nelz() const; // number of elements in y-direction // type ElementType getElementType() const; // mesh - xt::xtensor coor() const; // nodal positions [nnode, ndim] - xt::xtensor conn() const; // connectivity [nelem, nne] + xt::xtensor coor() const; // nodal positions [nnode, ndim] + xt::xtensor conn() const; // connectivity [nelem, nne] // element sets - xt::xtensor elementsMiddleLayer() const; // elements in the middle (fine) layer + xt::xtensor elementsMiddleLayer() const; // elements in the middle (fine) layer // boundary nodes: planes - xt::xtensor nodesFront() const; - xt::xtensor nodesBack() const; - xt::xtensor nodesLeft() const; - xt::xtensor nodesRight() const; - xt::xtensor nodesBottom() const; - xt::xtensor nodesTop() const; + xt::xtensor nodesFront() const; + xt::xtensor nodesBack() const; + xt::xtensor nodesLeft() const; + xt::xtensor nodesRight() const; + xt::xtensor nodesBottom() const; + xt::xtensor nodesTop() const; // boundary nodes: faces - xt::xtensor nodesFrontFace() const; - xt::xtensor nodesBackFace() const; - xt::xtensor nodesLeftFace() const; - xt::xtensor nodesRightFace() const; - xt::xtensor nodesBottomFace() const; - xt::xtensor nodesTopFace() const; + xt::xtensor nodesFrontFace() const; + xt::xtensor nodesBackFace() const; + xt::xtensor nodesLeftFace() const; + xt::xtensor nodesRightFace() const; + xt::xtensor nodesBottomFace() const; + xt::xtensor nodesTopFace() const; // boundary nodes: edges - xt::xtensor nodesFrontBottomEdge() const; - xt::xtensor nodesFrontTopEdge() const; - xt::xtensor nodesFrontLeftEdge() const; - xt::xtensor nodesFrontRightEdge() const; - xt::xtensor nodesBackBottomEdge() const; - xt::xtensor nodesBackTopEdge() const; - xt::xtensor nodesBackLeftEdge() const; - xt::xtensor nodesBackRightEdge() const; - xt::xtensor nodesBottomLeftEdge() const; - xt::xtensor nodesBottomRightEdge() const; - xt::xtensor nodesTopLeftEdge() const; - xt::xtensor nodesTopRightEdge() const; + xt::xtensor nodesFrontBottomEdge() const; + xt::xtensor nodesFrontTopEdge() const; + xt::xtensor nodesFrontLeftEdge() const; + xt::xtensor nodesFrontRightEdge() const; + xt::xtensor nodesBackBottomEdge() const; + xt::xtensor nodesBackTopEdge() const; + xt::xtensor nodesBackLeftEdge() const; + xt::xtensor nodesBackRightEdge() const; + xt::xtensor nodesBottomLeftEdge() const; + xt::xtensor nodesBottomRightEdge() const; + xt::xtensor nodesTopLeftEdge() const; + xt::xtensor nodesTopRightEdge() const; // boundary nodes: edges (aliases) - xt::xtensor nodesBottomFrontEdge() const; - xt::xtensor nodesBottomBackEdge() const; - xt::xtensor nodesTopFrontEdge() const; - xt::xtensor nodesTopBackEdge() const; - xt::xtensor nodesLeftBottomEdge() const; - xt::xtensor nodesLeftFrontEdge() const; - xt::xtensor nodesLeftBackEdge() const; - xt::xtensor nodesLeftTopEdge() const; - xt::xtensor nodesRightBottomEdge() const; - xt::xtensor nodesRightTopEdge() const; - xt::xtensor nodesRightFrontEdge() const; - xt::xtensor nodesRightBackEdge() const; + xt::xtensor nodesBottomFrontEdge() const; + xt::xtensor nodesBottomBackEdge() const; + xt::xtensor nodesTopFrontEdge() const; + xt::xtensor nodesTopBackEdge() const; + xt::xtensor nodesLeftBottomEdge() const; + xt::xtensor nodesLeftFrontEdge() const; + xt::xtensor nodesLeftBackEdge() const; + xt::xtensor nodesLeftTopEdge() const; + xt::xtensor nodesRightBottomEdge() const; + xt::xtensor nodesRightTopEdge() const; + xt::xtensor nodesRightFrontEdge() const; + xt::xtensor nodesRightBackEdge() const; // boundary nodes: edges, without corners - xt::xtensor nodesFrontBottomOpenEdge() const; - xt::xtensor nodesFrontTopOpenEdge() const; - xt::xtensor nodesFrontLeftOpenEdge() const; - xt::xtensor nodesFrontRightOpenEdge() const; - xt::xtensor nodesBackBottomOpenEdge() const; - xt::xtensor nodesBackTopOpenEdge() const; - xt::xtensor nodesBackLeftOpenEdge() const; - xt::xtensor nodesBackRightOpenEdge() const; - xt::xtensor nodesBottomLeftOpenEdge() const; - xt::xtensor nodesBottomRightOpenEdge() const; - xt::xtensor nodesTopLeftOpenEdge() const; - xt::xtensor nodesTopRightOpenEdge() const; + xt::xtensor nodesFrontBottomOpenEdge() const; + xt::xtensor nodesFrontTopOpenEdge() const; + xt::xtensor nodesFrontLeftOpenEdge() const; + xt::xtensor nodesFrontRightOpenEdge() const; + xt::xtensor nodesBackBottomOpenEdge() const; + xt::xtensor nodesBackTopOpenEdge() const; + xt::xtensor nodesBackLeftOpenEdge() const; + xt::xtensor nodesBackRightOpenEdge() const; + xt::xtensor nodesBottomLeftOpenEdge() const; + xt::xtensor nodesBottomRightOpenEdge() const; + xt::xtensor nodesTopLeftOpenEdge() const; + xt::xtensor nodesTopRightOpenEdge() const; // boundary nodes: edges, without corners (aliases) - xt::xtensor nodesBottomFrontOpenEdge() const; - xt::xtensor nodesBottomBackOpenEdge() const; - xt::xtensor nodesTopFrontOpenEdge() const; - xt::xtensor nodesTopBackOpenEdge() const; - xt::xtensor nodesLeftBottomOpenEdge() const; - xt::xtensor nodesLeftFrontOpenEdge() const; - xt::xtensor nodesLeftBackOpenEdge() const; - xt::xtensor nodesLeftTopOpenEdge() const; - xt::xtensor nodesRightBottomOpenEdge() const; - xt::xtensor nodesRightTopOpenEdge() const; - xt::xtensor nodesRightFrontOpenEdge() const; - xt::xtensor nodesRightBackOpenEdge() const; + xt::xtensor nodesBottomFrontOpenEdge() const; + xt::xtensor nodesBottomBackOpenEdge() const; + xt::xtensor nodesTopFrontOpenEdge() const; + xt::xtensor nodesTopBackOpenEdge() const; + xt::xtensor nodesLeftBottomOpenEdge() const; + xt::xtensor nodesLeftFrontOpenEdge() const; + xt::xtensor nodesLeftBackOpenEdge() const; + xt::xtensor nodesLeftTopOpenEdge() const; + xt::xtensor nodesRightBottomOpenEdge() const; + xt::xtensor nodesRightTopOpenEdge() const; + xt::xtensor nodesRightFrontOpenEdge() const; + xt::xtensor nodesRightBackOpenEdge() const; // boundary nodes: corners size_t nodesFrontBottomLeftCorner() const; size_t nodesFrontBottomRightCorner() const; size_t nodesFrontTopLeftCorner() const; size_t nodesFrontTopRightCorner() const; size_t nodesBackBottomLeftCorner() const; size_t nodesBackBottomRightCorner() const; size_t nodesBackTopLeftCorner() const; size_t nodesBackTopRightCorner() const; // boundary nodes: corners (aliases) size_t nodesFrontLeftBottomCorner() const; size_t nodesBottomFrontLeftCorner() const; size_t nodesBottomLeftFrontCorner() const; size_t nodesLeftFrontBottomCorner() const; size_t nodesLeftBottomFrontCorner() const; size_t nodesFrontRightBottomCorner() const; size_t nodesBottomFrontRightCorner() const; size_t nodesBottomRightFrontCorner() const; size_t nodesRightFrontBottomCorner() const; size_t nodesRightBottomFrontCorner() const; size_t nodesFrontLeftTopCorner() const; size_t nodesTopFrontLeftCorner() const; size_t nodesTopLeftFrontCorner() const; size_t nodesLeftFrontTopCorner() const; size_t nodesLeftTopFrontCorner() const; size_t nodesFrontRightTopCorner() const; size_t nodesTopFrontRightCorner() const; size_t nodesTopRightFrontCorner() const; size_t nodesRightFrontTopCorner() const; size_t nodesRightTopFrontCorner() const; size_t nodesBackLeftBottomCorner() const; size_t nodesBottomBackLeftCorner() const; size_t nodesBottomLeftBackCorner() const; size_t nodesLeftBackBottomCorner() const; size_t nodesLeftBottomBackCorner() const; size_t nodesBackRightBottomCorner() const; size_t nodesBottomBackRightCorner() const; size_t nodesBottomRightBackCorner() const; size_t nodesRightBackBottomCorner() const; size_t nodesRightBottomBackCorner() const; size_t nodesBackLeftTopCorner() const; size_t nodesTopBackLeftCorner() const; size_t nodesTopLeftBackCorner() const; size_t nodesLeftBackTopCorner() const; size_t nodesLeftTopBackCorner() const; size_t nodesBackRightTopCorner() const; size_t nodesTopBackRightCorner() const; size_t nodesTopRightBackCorner() const; size_t nodesRightBackTopCorner() const; size_t nodesRightTopBackCorner() const; // DOF-numbers for each component of each node (sequential) - xt::xtensor dofs() const; + xt::xtensor dofs() const; // DOF-numbers for the case that the periodicity if fully eliminated - xt::xtensor dofsPeriodic() const; + xt::xtensor dofsPeriodic() const; // periodic node pairs [:,2]: (independent, dependent) - xt::xtensor nodesPeriodic() const; + xt::xtensor nodesPeriodic() const; // front-bottom-left node, used as reference for periodicity size_t nodesOrigin() const; private: - double m_h; // elementary element edge-size (in all directions) - double m_Lx; // mesh size in "x" - double m_Lz; // mesh size in "z" - size_t m_nelem; // number of elements - size_t m_nnode; // number of nodes - static const size_t m_nne = 8; // number of nodes-per-element - static const size_t m_ndim = 3; // number of dimensions - xt::xtensor m_nelx; // number of elements in "x" (*) - xt::xtensor m_nelz; // number of elements in "z" (*) - xt::xtensor m_nnd; // number of nodes in the main node layer (**) - xt::xtensor m_nhx; // element size in x-direction (*) - xt::xtensor m_nhy; // element size in y-direction (*) - xt::xtensor m_nhz; // element size in z-direction (*) - xt::xtensor m_refine; // refine direction (-1:no refine, 0:"x", 2:"z") (*) - xt::xtensor m_startElem; // start element (*) - xt::xtensor m_startNode; // start node (**) + double m_h; // elementary element edge-size (in all directions) + double m_Lx; // mesh size in "x" + double m_Lz; // mesh size in "z" + size_t m_nelem; // number of elements + size_t m_nnode; // number of nodes + static const size_t m_nne = 8; // number of nodes-per-element + static const size_t m_ndim = 3; // number of dimensions + xt::xtensor m_nelx; // number of elements in "x" (*) + xt::xtensor m_nelz; // number of elements in "z" (*) + xt::xtensor m_nnd; // number of nodes in the main node layer (**) + xt::xtensor m_nhx; // element size in x-direction (*) + xt::xtensor m_nhy; // element size in y-direction (*) + xt::xtensor m_nhz; // element size in z-direction (*) + xt::xtensor m_refine; // refine direction (-1:no refine, 0:"x", 2:"z") (*) + xt::xtensor m_startElem; // start element (*) + xt::xtensor m_startNode; // start node (**) // (*) per element layer in "y" // (**) per node layer in "y" }; } // namespace Hex8 } // namespace Mesh } // namespace GooseFEM #include "MeshHex8.hpp" #endif diff --git a/include/GooseFEM/MeshHex8.hpp b/include/GooseFEM/MeshHex8.hpp index 7d59c85..3fe02ed 100644 --- a/include/GooseFEM/MeshHex8.hpp +++ b/include/GooseFEM/MeshHex8.hpp @@ -1,3019 +1,3015 @@ /* (c - GPLv3) T.W.J. de Geus (Tom) | tom@geus.me | www.geus.me | github.com/tdegeus/GooseFEM */ #ifndef GOOSEFEM_MESHHEX8_HPP #define GOOSEFEM_MESHHEX8_HPP #include "MeshHex8.h" namespace GooseFEM { namespace Mesh { namespace Hex8 { inline Regular::Regular(size_t nelx, size_t nely, size_t nelz, double h) : m_h(h), m_nelx(nelx), m_nely(nely), m_nelz(nelz) { GOOSEFEM_ASSERT(m_nelx >= 1ul); GOOSEFEM_ASSERT(m_nely >= 1ul); GOOSEFEM_ASSERT(m_nelz >= 1ul); m_nnode = (m_nelx + 1) * (m_nely + 1) * (m_nelz + 1); m_nelem = m_nelx * m_nely * m_nelz; } inline size_t Regular::nelem() const { return m_nelem; } inline size_t Regular::nnode() const { return m_nnode; } inline size_t Regular::nne() const { return m_nne; } inline size_t Regular::ndim() const { return m_ndim; } inline ElementType Regular::getElementType() const { return ElementType::Hex8; } -inline xt::xtensor Regular::coor() const +inline xt::xtensor Regular::coor() const { - xt::xtensor out = xt::empty({m_nnode, m_ndim}); + xt::xtensor out = xt::empty({m_nnode, m_ndim}); - xt::xtensor x = + xt::xtensor x = xt::linspace(0.0, m_h * static_cast(m_nelx), m_nelx + 1); - xt::xtensor y = + xt::xtensor y = xt::linspace(0.0, m_h * static_cast(m_nely), m_nely + 1); - xt::xtensor z = + xt::xtensor z = xt::linspace(0.0, m_h * static_cast(m_nelz), m_nelz + 1); size_t inode = 0; for (size_t iz = 0; iz < m_nelz + 1; ++iz) { for (size_t iy = 0; iy < m_nely + 1; ++iy) { for (size_t ix = 0; ix < m_nelx + 1; ++ix) { out(inode, 0) = x(ix); out(inode, 1) = y(iy); out(inode, 2) = z(iz); ++inode; } } } return out; } -inline xt::xtensor Regular::conn() const +inline xt::xtensor Regular::conn() const { - xt::xtensor out = xt::empty({m_nelem, m_nne}); + xt::xtensor out = xt::empty({m_nelem, m_nne}); size_t ielem = 0; for (size_t iz = 0; iz < m_nelz; ++iz) { for (size_t iy = 0; iy < m_nely; ++iy) { for (size_t ix = 0; ix < m_nelx; ++ix) { - out(ielem, 0) = - iy * (m_nelx + 1) + ix + iz * (m_nely + 1) * (m_nelx + 1); - out(ielem, 1) = - iy * (m_nelx + 1) + (ix + 1) + iz * (m_nely + 1) * (m_nelx + 1); - out(ielem, 3) = - (iy + 1) * (m_nelx + 1) + ix + iz * (m_nely + 1) * (m_nelx + 1); + out(ielem, 0) = iy * (m_nelx + 1) + ix + iz * (m_nely + 1) * (m_nelx + 1); + out(ielem, 1) = iy * (m_nelx + 1) + (ix + 1) + iz * (m_nely + 1) * (m_nelx + 1); + out(ielem, 3) = (iy + 1) * (m_nelx + 1) + ix + iz * (m_nely + 1) * (m_nelx + 1); out(ielem, 2) = (iy + 1) * (m_nelx + 1) + (ix + 1) + iz * (m_nely + 1) * (m_nelx + 1); - out(ielem, 4) = - iy * (m_nelx + 1) + ix + (iz + 1) * (m_nely + 1) * (m_nelx + 1); + out(ielem, 4) = iy * (m_nelx + 1) + ix + (iz + 1) * (m_nely + 1) * (m_nelx + 1); out(ielem, 5) = (iy) * (m_nelx + 1) + (ix + 1) + (iz + 1) * (m_nely + 1) * (m_nelx + 1); out(ielem, 7) = (iy + 1) * (m_nelx + 1) + ix + (iz + 1) * (m_nely + 1) * (m_nelx + 1); out(ielem, 6) = (iy + 1) * (m_nelx + 1) + (ix + 1) + (iz + 1) * (m_nely + 1) * (m_nelx + 1); ++ielem; } } } return out; } -inline xt::xtensor Regular::nodesFront() const +inline xt::xtensor Regular::nodesFront() const { - xt::xtensor out = xt::empty({(m_nelx + 1) * (m_nely + 1)}); + xt::xtensor out = xt::empty({(m_nelx + 1) * (m_nely + 1)}); for (size_t iy = 0; iy < m_nely + 1; ++iy) { for (size_t ix = 0; ix < m_nelx + 1; ++ix) { out(iy * (m_nelx + 1) + ix) = iy * (m_nelx + 1) + ix; } } return out; } -inline xt::xtensor Regular::nodesBack() const +inline xt::xtensor Regular::nodesBack() const { - xt::xtensor out = xt::empty({(m_nelx + 1) * (m_nely + 1)}); + xt::xtensor out = xt::empty({(m_nelx + 1) * (m_nely + 1)}); for (size_t iy = 0; iy < m_nely + 1; ++iy) { for (size_t ix = 0; ix < m_nelx + 1; ++ix) { out(iy * (m_nelx + 1) + ix) = iy * (m_nelx + 1) + ix + m_nelz * (m_nely + 1) * (m_nelx + 1); } } return out; } -inline xt::xtensor Regular::nodesLeft() const +inline xt::xtensor Regular::nodesLeft() const { - xt::xtensor out = xt::empty({(m_nely + 1) * (m_nelz + 1)}); + xt::xtensor out = xt::empty({(m_nely + 1) * (m_nelz + 1)}); for (size_t iz = 0; iz < m_nelz + 1; ++iz) { for (size_t iy = 0; iy < m_nely + 1; ++iy) { out(iz * (m_nely + 1) + iy) = iy * (m_nelx + 1) + iz * (m_nelx + 1) * (m_nely + 1); } } return out; } -inline xt::xtensor Regular::nodesRight() const +inline xt::xtensor Regular::nodesRight() const { - xt::xtensor out = xt::empty({(m_nely + 1) * (m_nelz + 1)}); + xt::xtensor out = xt::empty({(m_nely + 1) * (m_nelz + 1)}); for (size_t iz = 0; iz < m_nelz + 1; ++iz) { for (size_t iy = 0; iy < m_nely + 1; ++iy) { out(iz * (m_nely + 1) + iy) = iy * (m_nelx + 1) + iz * (m_nelx + 1) * (m_nely + 1) + m_nelx; } } return out; } -inline xt::xtensor Regular::nodesBottom() const +inline xt::xtensor Regular::nodesBottom() const { - xt::xtensor out = xt::empty({(m_nelx + 1) * (m_nelz + 1)}); + xt::xtensor out = xt::empty({(m_nelx + 1) * (m_nelz + 1)}); for (size_t iz = 0; iz < m_nelz + 1; ++iz) { for (size_t ix = 0; ix < m_nelx + 1; ++ix) { out(iz * (m_nelx + 1) + ix) = ix + iz * (m_nelx + 1) * (m_nely + 1); } } return out; } -inline xt::xtensor Regular::nodesTop() const +inline xt::xtensor Regular::nodesTop() const { - xt::xtensor out = xt::empty({(m_nelx + 1) * (m_nelz + 1)}); + xt::xtensor out = xt::empty({(m_nelx + 1) * (m_nelz + 1)}); for (size_t iz = 0; iz < m_nelz + 1; ++iz) { for (size_t ix = 0; ix < m_nelx + 1; ++ix) { out(iz * (m_nelx + 1) + ix) = ix + m_nely * (m_nelx + 1) + iz * (m_nelx + 1) * (m_nely + 1); } } return out; } -inline xt::xtensor Regular::nodesFrontFace() const +inline xt::xtensor Regular::nodesFrontFace() const { - xt::xtensor out = xt::empty({(m_nelx - 1) * (m_nely - 1)}); + xt::xtensor out = xt::empty({(m_nelx - 1) * (m_nely - 1)}); for (size_t iy = 1; iy < m_nely; ++iy) { for (size_t ix = 1; ix < m_nelx; ++ix) { out((iy - 1) * (m_nelx - 1) + (ix - 1)) = iy * (m_nelx + 1) + ix; } } return out; } -inline xt::xtensor Regular::nodesBackFace() const +inline xt::xtensor Regular::nodesBackFace() const { - xt::xtensor out = xt::empty({(m_nelx - 1) * (m_nely - 1)}); + xt::xtensor out = xt::empty({(m_nelx - 1) * (m_nely - 1)}); for (size_t iy = 1; iy < m_nely; ++iy) { for (size_t ix = 1; ix < m_nelx; ++ix) { out((iy - 1) * (m_nelx - 1) + (ix - 1)) = iy * (m_nelx + 1) + ix + m_nelz * (m_nely + 1) * (m_nelx + 1); } } return out; } -inline xt::xtensor Regular::nodesLeftFace() const +inline xt::xtensor Regular::nodesLeftFace() const { - xt::xtensor out = xt::empty({(m_nely - 1) * (m_nelz - 1)}); + xt::xtensor out = xt::empty({(m_nely - 1) * (m_nelz - 1)}); for (size_t iz = 1; iz < m_nelz; ++iz) { for (size_t iy = 1; iy < m_nely; ++iy) { out((iz - 1) * (m_nely - 1) + (iy - 1)) = iy * (m_nelx + 1) + iz * (m_nelx + 1) * (m_nely + 1); } } return out; } -inline xt::xtensor Regular::nodesRightFace() const +inline xt::xtensor Regular::nodesRightFace() const { - xt::xtensor out = xt::empty({(m_nely - 1) * (m_nelz - 1)}); + xt::xtensor out = xt::empty({(m_nely - 1) * (m_nelz - 1)}); for (size_t iz = 1; iz < m_nelz; ++iz) { for (size_t iy = 1; iy < m_nely; ++iy) { out((iz - 1) * (m_nely - 1) + (iy - 1)) = iy * (m_nelx + 1) + iz * (m_nelx + 1) * (m_nely + 1) + m_nelx; } } return out; } -inline xt::xtensor Regular::nodesBottomFace() const +inline xt::xtensor Regular::nodesBottomFace() const { - xt::xtensor out = xt::empty({(m_nelx - 1) * (m_nelz - 1)}); + xt::xtensor out = xt::empty({(m_nelx - 1) * (m_nelz - 1)}); for (size_t iz = 1; iz < m_nelz; ++iz) { for (size_t ix = 1; ix < m_nelx; ++ix) { out((iz - 1) * (m_nelx - 1) + (ix - 1)) = ix + iz * (m_nelx + 1) * (m_nely + 1); } } return out; } -inline xt::xtensor Regular::nodesTopFace() const +inline xt::xtensor Regular::nodesTopFace() const { - xt::xtensor out = xt::empty({(m_nelx - 1) * (m_nelz - 1)}); + xt::xtensor out = xt::empty({(m_nelx - 1) * (m_nelz - 1)}); for (size_t iz = 1; iz < m_nelz; ++iz) { for (size_t ix = 1; ix < m_nelx; ++ix) { out((iz - 1) * (m_nelx - 1) + (ix - 1)) = ix + m_nely * (m_nelx + 1) + iz * (m_nelx + 1) * (m_nely + 1); } } return out; } -inline xt::xtensor Regular::nodesFrontBottomEdge() const +inline xt::xtensor Regular::nodesFrontBottomEdge() const { - xt::xtensor out = xt::empty({m_nelx + 1}); + xt::xtensor out = xt::empty({m_nelx + 1}); for (size_t ix = 0; ix < m_nelx + 1; ++ix) { out(ix) = ix; } return out; } -inline xt::xtensor Regular::nodesFrontTopEdge() const +inline xt::xtensor Regular::nodesFrontTopEdge() const { - xt::xtensor out = xt::empty({m_nelx + 1}); + xt::xtensor out = xt::empty({m_nelx + 1}); for (size_t ix = 0; ix < m_nelx + 1; ++ix) { out(ix) = ix + m_nely * (m_nelx + 1); } return out; } -inline xt::xtensor Regular::nodesFrontLeftEdge() const +inline xt::xtensor Regular::nodesFrontLeftEdge() const { - xt::xtensor out = xt::empty({m_nely + 1}); + xt::xtensor out = xt::empty({m_nely + 1}); for (size_t iy = 0; iy < m_nely + 1; ++iy) { out(iy) = iy * (m_nelx + 1); } return out; } -inline xt::xtensor Regular::nodesFrontRightEdge() const +inline xt::xtensor Regular::nodesFrontRightEdge() const { - xt::xtensor out = xt::empty({m_nely + 1}); + xt::xtensor out = xt::empty({m_nely + 1}); for (size_t iy = 0; iy < m_nely + 1; ++iy) { out(iy) = iy * (m_nelx + 1) + m_nelx; } return out; } -inline xt::xtensor Regular::nodesBackBottomEdge() const +inline xt::xtensor Regular::nodesBackBottomEdge() const { - xt::xtensor out = xt::empty({m_nelx + 1}); + xt::xtensor out = xt::empty({m_nelx + 1}); for (size_t ix = 0; ix < m_nelx + 1; ++ix) { out(ix) = ix + m_nelz * (m_nely + 1) * (m_nelx + 1); } return out; } -inline xt::xtensor Regular::nodesBackTopEdge() const +inline xt::xtensor Regular::nodesBackTopEdge() const { - xt::xtensor out = xt::empty({m_nelx + 1}); + xt::xtensor out = xt::empty({m_nelx + 1}); for (size_t ix = 0; ix < m_nelx + 1; ++ix) { out(ix) = m_nely * (m_nelx + 1) + ix + m_nelz * (m_nely + 1) * (m_nelx + 1); } return out; } -inline xt::xtensor Regular::nodesBackLeftEdge() const +inline xt::xtensor Regular::nodesBackLeftEdge() const { - xt::xtensor out = xt::empty({m_nely + 1}); + xt::xtensor out = xt::empty({m_nely + 1}); for (size_t iy = 0; iy < m_nely + 1; ++iy) { out(iy) = iy * (m_nelx + 1) + m_nelz * (m_nelx + 1) * (m_nely + 1); } return out; } -inline xt::xtensor Regular::nodesBackRightEdge() const +inline xt::xtensor Regular::nodesBackRightEdge() const { - xt::xtensor out = xt::empty({m_nely + 1}); + xt::xtensor out = xt::empty({m_nely + 1}); for (size_t iy = 0; iy < m_nely + 1; ++iy) { out(iy) = iy * (m_nelx + 1) + m_nelz * (m_nelx + 1) * (m_nely + 1) + m_nelx; } return out; } -inline xt::xtensor Regular::nodesBottomLeftEdge() const +inline xt::xtensor Regular::nodesBottomLeftEdge() const { - xt::xtensor out = xt::empty({m_nelz + 1}); + xt::xtensor out = xt::empty({m_nelz + 1}); for (size_t iz = 0; iz < m_nelz + 1; ++iz) { out(iz) = iz * (m_nelx + 1) * (m_nely + 1); } return out; } -inline xt::xtensor Regular::nodesBottomRightEdge() const +inline xt::xtensor Regular::nodesBottomRightEdge() const { - xt::xtensor out = xt::empty({m_nelz + 1}); + xt::xtensor out = xt::empty({m_nelz + 1}); for (size_t iz = 0; iz < m_nelz + 1; ++iz) { out(iz) = iz * (m_nelx + 1) * (m_nely + 1) + m_nelx; } return out; } -inline xt::xtensor Regular::nodesTopLeftEdge() const +inline xt::xtensor Regular::nodesTopLeftEdge() const { - xt::xtensor out = xt::empty({m_nelz + 1}); + xt::xtensor out = xt::empty({m_nelz + 1}); for (size_t iz = 0; iz < m_nelz + 1; ++iz) { out(iz) = m_nely * (m_nelx + 1) + iz * (m_nelx + 1) * (m_nely + 1); } return out; } -inline xt::xtensor Regular::nodesTopRightEdge() const +inline xt::xtensor Regular::nodesTopRightEdge() const { - xt::xtensor out = xt::empty({m_nelz + 1}); + xt::xtensor out = xt::empty({m_nelz + 1}); for (size_t iz = 0; iz < m_nelz + 1; ++iz) { out(iz) = m_nely * (m_nelx + 1) + iz * (m_nelx + 1) * (m_nely + 1) + m_nelx; } return out; } -inline xt::xtensor Regular::nodesBottomFrontEdge() const +inline xt::xtensor Regular::nodesBottomFrontEdge() const { return nodesFrontBottomEdge(); } -inline xt::xtensor Regular::nodesBottomBackEdge() const +inline xt::xtensor Regular::nodesBottomBackEdge() const { return nodesBackBottomEdge(); } -inline xt::xtensor Regular::nodesTopFrontEdge() const +inline xt::xtensor Regular::nodesTopFrontEdge() const { return nodesFrontTopEdge(); } -inline xt::xtensor Regular::nodesTopBackEdge() const +inline xt::xtensor Regular::nodesTopBackEdge() const { return nodesBackTopEdge(); } -inline xt::xtensor Regular::nodesLeftBottomEdge() const +inline xt::xtensor Regular::nodesLeftBottomEdge() const { return nodesBottomLeftEdge(); } -inline xt::xtensor Regular::nodesLeftFrontEdge() const +inline xt::xtensor Regular::nodesLeftFrontEdge() const { return nodesFrontLeftEdge(); } -inline xt::xtensor Regular::nodesLeftBackEdge() const +inline xt::xtensor Regular::nodesLeftBackEdge() const { return nodesBackLeftEdge(); } -inline xt::xtensor Regular::nodesLeftTopEdge() const +inline xt::xtensor Regular::nodesLeftTopEdge() const { return nodesTopLeftEdge(); } -inline xt::xtensor Regular::nodesRightBottomEdge() const +inline xt::xtensor Regular::nodesRightBottomEdge() const { return nodesBottomRightEdge(); } -inline xt::xtensor Regular::nodesRightTopEdge() const +inline xt::xtensor Regular::nodesRightTopEdge() const { return nodesTopRightEdge(); } -inline xt::xtensor Regular::nodesRightFrontEdge() const +inline xt::xtensor Regular::nodesRightFrontEdge() const { return nodesFrontRightEdge(); } -inline xt::xtensor Regular::nodesRightBackEdge() const +inline xt::xtensor Regular::nodesRightBackEdge() const { return nodesBackRightEdge(); } -inline xt::xtensor Regular::nodesFrontBottomOpenEdge() const +inline xt::xtensor Regular::nodesFrontBottomOpenEdge() const { - xt::xtensor out = xt::empty({m_nelx - 1}); + xt::xtensor out = xt::empty({m_nelx - 1}); for (size_t ix = 1; ix < m_nelx; ++ix) { out(ix - 1) = ix; } return out; } -inline xt::xtensor Regular::nodesFrontTopOpenEdge() const +inline xt::xtensor Regular::nodesFrontTopOpenEdge() const { - xt::xtensor out = xt::empty({m_nelx - 1}); + xt::xtensor out = xt::empty({m_nelx - 1}); for (size_t ix = 1; ix < m_nelx; ++ix) { out(ix - 1) = ix + m_nely * (m_nelx + 1); } return out; } -inline xt::xtensor Regular::nodesFrontLeftOpenEdge() const +inline xt::xtensor Regular::nodesFrontLeftOpenEdge() const { - xt::xtensor out = xt::empty({m_nely - 1}); + xt::xtensor out = xt::empty({m_nely - 1}); for (size_t iy = 1; iy < m_nely; ++iy) { out(iy - 1) = iy * (m_nelx + 1); } return out; } -inline xt::xtensor Regular::nodesFrontRightOpenEdge() const +inline xt::xtensor Regular::nodesFrontRightOpenEdge() const { - xt::xtensor out = xt::empty({m_nely - 1}); + xt::xtensor out = xt::empty({m_nely - 1}); for (size_t iy = 1; iy < m_nely; ++iy) { out(iy - 1) = iy * (m_nelx + 1) + m_nelx; } return out; } -inline xt::xtensor Regular::nodesBackBottomOpenEdge() const +inline xt::xtensor Regular::nodesBackBottomOpenEdge() const { - xt::xtensor out = xt::empty({m_nelx - 1}); + xt::xtensor out = xt::empty({m_nelx - 1}); for (size_t ix = 1; ix < m_nelx; ++ix) { out(ix - 1) = ix + m_nelz * (m_nely + 1) * (m_nelx + 1); } return out; } -inline xt::xtensor Regular::nodesBackTopOpenEdge() const +inline xt::xtensor Regular::nodesBackTopOpenEdge() const { - xt::xtensor out = xt::empty({m_nelx - 1}); + xt::xtensor out = xt::empty({m_nelx - 1}); for (size_t ix = 1; ix < m_nelx; ++ix) { out(ix - 1) = m_nely * (m_nelx + 1) + ix + m_nelz * (m_nely + 1) * (m_nelx + 1); } return out; } -inline xt::xtensor Regular::nodesBackLeftOpenEdge() const +inline xt::xtensor Regular::nodesBackLeftOpenEdge() const { - xt::xtensor out = xt::empty({m_nely - 1}); + xt::xtensor out = xt::empty({m_nely - 1}); for (size_t iy = 1; iy < m_nely; ++iy) { out(iy - 1) = iy * (m_nelx + 1) + m_nelz * (m_nelx + 1) * (m_nely + 1); } return out; } -inline xt::xtensor Regular::nodesBackRightOpenEdge() const +inline xt::xtensor Regular::nodesBackRightOpenEdge() const { - xt::xtensor out = xt::empty({m_nely - 1}); + xt::xtensor out = xt::empty({m_nely - 1}); for (size_t iy = 1; iy < m_nely; ++iy) { out(iy - 1) = iy * (m_nelx + 1) + m_nelz * (m_nelx + 1) * (m_nely + 1) + m_nelx; } return out; } -inline xt::xtensor Regular::nodesBottomLeftOpenEdge() const +inline xt::xtensor Regular::nodesBottomLeftOpenEdge() const { - xt::xtensor out = xt::empty({m_nelz - 1}); + xt::xtensor out = xt::empty({m_nelz - 1}); for (size_t iz = 1; iz < m_nelz; ++iz) { out(iz - 1) = iz * (m_nelx + 1) * (m_nely + 1); } return out; } -inline xt::xtensor Regular::nodesBottomRightOpenEdge() const +inline xt::xtensor Regular::nodesBottomRightOpenEdge() const { - xt::xtensor out = xt::empty({m_nelz - 1}); + xt::xtensor out = xt::empty({m_nelz - 1}); for (size_t iz = 1; iz < m_nelz; ++iz) { out(iz - 1) = iz * (m_nelx + 1) * (m_nely + 1) + m_nelx; } return out; } -inline xt::xtensor Regular::nodesTopLeftOpenEdge() const +inline xt::xtensor Regular::nodesTopLeftOpenEdge() const { - xt::xtensor out = xt::empty({m_nelz - 1}); + xt::xtensor out = xt::empty({m_nelz - 1}); for (size_t iz = 1; iz < m_nelz; ++iz) { out(iz - 1) = m_nely * (m_nelx + 1) + iz * (m_nelx + 1) * (m_nely + 1); } return out; } -inline xt::xtensor Regular::nodesTopRightOpenEdge() const +inline xt::xtensor Regular::nodesTopRightOpenEdge() const { - xt::xtensor out = xt::empty({m_nelz - 1}); + xt::xtensor out = xt::empty({m_nelz - 1}); for (size_t iz = 1; iz < m_nelz; ++iz) { out(iz - 1) = m_nely * (m_nelx + 1) + iz * (m_nelx + 1) * (m_nely + 1) + m_nelx; } return out; } -inline xt::xtensor Regular::nodesBottomFrontOpenEdge() const +inline xt::xtensor Regular::nodesBottomFrontOpenEdge() const { return nodesFrontBottomOpenEdge(); } -inline xt::xtensor Regular::nodesBottomBackOpenEdge() const +inline xt::xtensor Regular::nodesBottomBackOpenEdge() const { return nodesBackBottomOpenEdge(); } -inline xt::xtensor Regular::nodesTopFrontOpenEdge() const +inline xt::xtensor Regular::nodesTopFrontOpenEdge() const { return nodesFrontTopOpenEdge(); } -inline xt::xtensor Regular::nodesTopBackOpenEdge() const +inline xt::xtensor Regular::nodesTopBackOpenEdge() const { return nodesBackTopOpenEdge(); } -inline xt::xtensor Regular::nodesLeftBottomOpenEdge() const +inline xt::xtensor Regular::nodesLeftBottomOpenEdge() const { return nodesBottomLeftOpenEdge(); } -inline xt::xtensor Regular::nodesLeftFrontOpenEdge() const +inline xt::xtensor Regular::nodesLeftFrontOpenEdge() const { return nodesFrontLeftOpenEdge(); } -inline xt::xtensor Regular::nodesLeftBackOpenEdge() const +inline xt::xtensor Regular::nodesLeftBackOpenEdge() const { return nodesBackLeftOpenEdge(); } -inline xt::xtensor Regular::nodesLeftTopOpenEdge() const +inline xt::xtensor Regular::nodesLeftTopOpenEdge() const { return nodesTopLeftOpenEdge(); } -inline xt::xtensor Regular::nodesRightBottomOpenEdge() const +inline xt::xtensor Regular::nodesRightBottomOpenEdge() const { return nodesBottomRightOpenEdge(); } -inline xt::xtensor Regular::nodesRightTopOpenEdge() const +inline xt::xtensor Regular::nodesRightTopOpenEdge() const { return nodesTopRightOpenEdge(); } -inline xt::xtensor Regular::nodesRightFrontOpenEdge() const +inline xt::xtensor Regular::nodesRightFrontOpenEdge() const { return nodesFrontRightOpenEdge(); } -inline xt::xtensor Regular::nodesRightBackOpenEdge() const +inline xt::xtensor Regular::nodesRightBackOpenEdge() const { return nodesBackRightOpenEdge(); } inline size_t Regular::nodesFrontBottomLeftCorner() const { return 0; } inline size_t Regular::nodesFrontBottomRightCorner() const { return m_nelx; } inline size_t Regular::nodesFrontTopLeftCorner() const { return m_nely * (m_nelx + 1); } inline size_t Regular::nodesFrontTopRightCorner() const { return m_nely * (m_nelx + 1) + m_nelx; } inline size_t Regular::nodesBackBottomLeftCorner() const { return m_nelz * (m_nely + 1) * (m_nelx + 1); } inline size_t Regular::nodesBackBottomRightCorner() const { return m_nelx + m_nelz * (m_nely + 1) * (m_nelx + 1); } inline size_t Regular::nodesBackTopLeftCorner() const { return m_nely * (m_nelx + 1) + m_nelz * (m_nely + 1) * (m_nelx + 1); } inline size_t Regular::nodesBackTopRightCorner() const { return m_nely * (m_nelx + 1) + m_nelx + m_nelz * (m_nely + 1) * (m_nelx + 1); } inline size_t Regular::nodesFrontLeftBottomCorner() const { return nodesFrontBottomLeftCorner(); } inline size_t Regular::nodesBottomFrontLeftCorner() const { return nodesFrontBottomLeftCorner(); } inline size_t Regular::nodesBottomLeftFrontCorner() const { return nodesFrontBottomLeftCorner(); } inline size_t Regular::nodesLeftFrontBottomCorner() const { return nodesFrontBottomLeftCorner(); } inline size_t Regular::nodesLeftBottomFrontCorner() const { return nodesFrontBottomLeftCorner(); } inline size_t Regular::nodesFrontRightBottomCorner() const { return nodesFrontBottomRightCorner(); } inline size_t Regular::nodesBottomFrontRightCorner() const { return nodesFrontBottomRightCorner(); } inline size_t Regular::nodesBottomRightFrontCorner() const { return nodesFrontBottomRightCorner(); } inline size_t Regular::nodesRightFrontBottomCorner() const { return nodesFrontBottomRightCorner(); } inline size_t Regular::nodesRightBottomFrontCorner() const { return nodesFrontBottomRightCorner(); } inline size_t Regular::nodesFrontLeftTopCorner() const { return nodesFrontTopLeftCorner(); } inline size_t Regular::nodesTopFrontLeftCorner() const { return nodesFrontTopLeftCorner(); } inline size_t Regular::nodesTopLeftFrontCorner() const { return nodesFrontTopLeftCorner(); } inline size_t Regular::nodesLeftFrontTopCorner() const { return nodesFrontTopLeftCorner(); } inline size_t Regular::nodesLeftTopFrontCorner() const { return nodesFrontTopLeftCorner(); } inline size_t Regular::nodesFrontRightTopCorner() const { return nodesFrontTopRightCorner(); } inline size_t Regular::nodesTopFrontRightCorner() const { return nodesFrontTopRightCorner(); } inline size_t Regular::nodesTopRightFrontCorner() const { return nodesFrontTopRightCorner(); } inline size_t Regular::nodesRightFrontTopCorner() const { return nodesFrontTopRightCorner(); } inline size_t Regular::nodesRightTopFrontCorner() const { return nodesFrontTopRightCorner(); } inline size_t Regular::nodesBackLeftBottomCorner() const { return nodesBackBottomLeftCorner(); } inline size_t Regular::nodesBottomBackLeftCorner() const { return nodesBackBottomLeftCorner(); } inline size_t Regular::nodesBottomLeftBackCorner() const { return nodesBackBottomLeftCorner(); } inline size_t Regular::nodesLeftBackBottomCorner() const { return nodesBackBottomLeftCorner(); } inline size_t Regular::nodesLeftBottomBackCorner() const { return nodesBackBottomLeftCorner(); } inline size_t Regular::nodesBackRightBottomCorner() const { return nodesBackBottomRightCorner(); } inline size_t Regular::nodesBottomBackRightCorner() const { return nodesBackBottomRightCorner(); } inline size_t Regular::nodesBottomRightBackCorner() const { return nodesBackBottomRightCorner(); } inline size_t Regular::nodesRightBackBottomCorner() const { return nodesBackBottomRightCorner(); } inline size_t Regular::nodesRightBottomBackCorner() const { return nodesBackBottomRightCorner(); } inline size_t Regular::nodesBackLeftTopCorner() const { return nodesBackTopLeftCorner(); } inline size_t Regular::nodesTopBackLeftCorner() const { return nodesBackTopLeftCorner(); } inline size_t Regular::nodesTopLeftBackCorner() const { return nodesBackTopLeftCorner(); } inline size_t Regular::nodesLeftBackTopCorner() const { return nodesBackTopLeftCorner(); } inline size_t Regular::nodesLeftTopBackCorner() const { return nodesBackTopLeftCorner(); } inline size_t Regular::nodesBackRightTopCorner() const { return nodesBackTopRightCorner(); } inline size_t Regular::nodesTopBackRightCorner() const { return nodesBackTopRightCorner(); } inline size_t Regular::nodesTopRightBackCorner() const { return nodesBackTopRightCorner(); } inline size_t Regular::nodesRightBackTopCorner() const { return nodesBackTopRightCorner(); } inline size_t Regular::nodesRightTopBackCorner() const { return nodesBackTopRightCorner(); } -inline xt::xtensor Regular::nodesPeriodic() const -{ - xt::xtensor fro = nodesFrontFace(); - xt::xtensor bck = nodesBackFace(); - xt::xtensor lft = nodesLeftFace(); - xt::xtensor rgt = nodesRightFace(); - xt::xtensor bot = nodesBottomFace(); - xt::xtensor top = nodesTopFace(); - - xt::xtensor froBot = nodesFrontBottomOpenEdge(); - xt::xtensor froTop = nodesFrontTopOpenEdge(); - xt::xtensor froLft = nodesFrontLeftOpenEdge(); - xt::xtensor froRgt = nodesFrontRightOpenEdge(); - xt::xtensor bckBot = nodesBackBottomOpenEdge(); - xt::xtensor bckTop = nodesBackTopOpenEdge(); - xt::xtensor bckLft = nodesBackLeftOpenEdge(); - xt::xtensor bckRgt = nodesBackRightOpenEdge(); - xt::xtensor botLft = nodesBottomLeftOpenEdge(); - xt::xtensor botRgt = nodesBottomRightOpenEdge(); - xt::xtensor topLft = nodesTopLeftOpenEdge(); - xt::xtensor topRgt = nodesTopRightOpenEdge(); +inline xt::xtensor Regular::nodesPeriodic() const +{ + xt::xtensor fro = nodesFrontFace(); + xt::xtensor bck = nodesBackFace(); + xt::xtensor lft = nodesLeftFace(); + xt::xtensor rgt = nodesRightFace(); + xt::xtensor bot = nodesBottomFace(); + xt::xtensor top = nodesTopFace(); + + xt::xtensor froBot = nodesFrontBottomOpenEdge(); + xt::xtensor froTop = nodesFrontTopOpenEdge(); + xt::xtensor froLft = nodesFrontLeftOpenEdge(); + xt::xtensor froRgt = nodesFrontRightOpenEdge(); + xt::xtensor bckBot = nodesBackBottomOpenEdge(); + xt::xtensor bckTop = nodesBackTopOpenEdge(); + xt::xtensor bckLft = nodesBackLeftOpenEdge(); + xt::xtensor bckRgt = nodesBackRightOpenEdge(); + xt::xtensor botLft = nodesBottomLeftOpenEdge(); + xt::xtensor botRgt = nodesBottomRightOpenEdge(); + xt::xtensor topLft = nodesTopLeftOpenEdge(); + xt::xtensor topRgt = nodesTopRightOpenEdge(); size_t tface = fro.size() + lft.size() + bot.size(); size_t tedge = 3 * froBot.size() + 3 * froLft.size() + 3 * botLft.size(); size_t tnode = 7; - xt::xtensor out = xt::empty({tface + tedge + tnode, std::size_t(2)}); + xt::xtensor out = xt::empty({tface + tedge + tnode, std::size_t(2)}); size_t i = 0; out(i, 0) = nodesFrontBottomLeftCorner(); out(i, 1) = nodesFrontBottomRightCorner(); ++i; out(i, 0) = nodesFrontBottomLeftCorner(); out(i, 1) = nodesBackBottomRightCorner(); ++i; out(i, 0) = nodesFrontBottomLeftCorner(); out(i, 1) = nodesBackBottomLeftCorner(); ++i; out(i, 0) = nodesFrontBottomLeftCorner(); out(i, 1) = nodesFrontTopLeftCorner(); ++i; out(i, 0) = nodesFrontBottomLeftCorner(); out(i, 1) = nodesFrontTopRightCorner(); ++i; out(i, 0) = nodesFrontBottomLeftCorner(); out(i, 1) = nodesBackTopRightCorner(); ++i; out(i, 0) = nodesFrontBottomLeftCorner(); out(i, 1) = nodesBackTopLeftCorner(); ++i; for (size_t j = 0; j < froBot.size(); ++j) { out(i, 0) = froBot(j); out(i, 1) = bckBot(j); ++i; } for (size_t j = 0; j < froBot.size(); ++j) { out(i, 0) = froBot(j); out(i, 1) = bckTop(j); ++i; } for (size_t j = 0; j < froBot.size(); ++j) { out(i, 0) = froBot(j); out(i, 1) = froTop(j); ++i; } for (size_t j = 0; j < botLft.size(); ++j) { out(i, 0) = botLft(j); out(i, 1) = botRgt(j); ++i; } for (size_t j = 0; j < botLft.size(); ++j) { out(i, 0) = botLft(j); out(i, 1) = topRgt(j); ++i; } for (size_t j = 0; j < botLft.size(); ++j) { out(i, 0) = botLft(j); out(i, 1) = topLft(j); ++i; } for (size_t j = 0; j < froLft.size(); ++j) { out(i, 0) = froLft(j); out(i, 1) = froRgt(j); ++i; } for (size_t j = 0; j < froLft.size(); ++j) { out(i, 0) = froLft(j); out(i, 1) = bckRgt(j); ++i; } for (size_t j = 0; j < froLft.size(); ++j) { out(i, 0) = froLft(j); out(i, 1) = bckLft(j); ++i; } for (size_t j = 0; j < fro.size(); ++j) { out(i, 0) = fro(j); out(i, 1) = bck(j); ++i; } for (size_t j = 0; j < lft.size(); ++j) { out(i, 0) = lft(j); out(i, 1) = rgt(j); ++i; } for (size_t j = 0; j < bot.size(); ++j) { out(i, 0) = bot(j); out(i, 1) = top(j); ++i; } return out; } inline size_t Regular::nodesOrigin() const { return nodesFrontBottomLeftCorner(); } -inline xt::xtensor Regular::dofs() const +inline xt::xtensor Regular::dofs() const { return GooseFEM::Mesh::dofs(m_nnode, m_ndim); } -inline xt::xtensor Regular::dofsPeriodic() const +inline xt::xtensor Regular::dofsPeriodic() const { - xt::xtensor out = GooseFEM::Mesh::dofs(m_nnode, m_ndim); - xt::xtensor nodePer = nodesPeriodic(); + xt::xtensor out = GooseFEM::Mesh::dofs(m_nnode, m_ndim); + xt::xtensor nodePer = nodesPeriodic(); for (size_t i = 0; i < nodePer.shape(0); ++i) { for (size_t j = 0; j < m_ndim; ++j) { out(nodePer(i, 1), j) = out(nodePer(i, 0), j); } } return GooseFEM::Mesh::renumber(out); } inline FineLayer::FineLayer(size_t nelx, size_t nely, size_t nelz, double h, size_t nfine) : m_h(h) { // basic assumptions GOOSEFEM_ASSERT(nelx >= 1ul); GOOSEFEM_ASSERT(nely >= 1ul); GOOSEFEM_ASSERT(nelz >= 1ul); // store basic info m_Lx = m_h * static_cast(nelx); m_Lz = m_h * static_cast(nelz); // compute element size in y-direction (use symmetry, compute upper half) // temporary variables size_t nmin, ntot; - xt::xtensor nhx = xt::ones({nely}); - xt::xtensor nhy = xt::ones({nely}); - xt::xtensor nhz = xt::ones({nely}); - xt::xtensor refine = -1 * xt::ones({nely}); + xt::xtensor nhx = xt::ones({nely}); + xt::xtensor nhy = xt::ones({nely}); + xt::xtensor nhz = xt::ones({nely}); + xt::xtensor refine = -1 * xt::ones({nely}); // minimum height in y-direction (half of the height because of symmetry) if (nely % 2 == 0) { nmin = nely / 2; } else { nmin = (nely + 1) / 2; } // minimum number of fine layers in y-direction (minimum 1, middle layer part of this half) if (nfine % 2 == 0) { nfine = nfine / 2 + 1; } else { nfine = (nfine + 1) / 2; } if (nfine < 1) { nfine = 1; } if (nfine > nmin) { nfine = nmin; } // loop over element layers in y-direction, try to coarsen using these rules: // (1) element size in y-direction <= distance to origin in y-direction // (2) element size in x-(z-)direction should fit the total number of elements in // x-(z-)direction (3) a certain number of layers have the minimum size "1" (are fine) for (size_t iy = nfine;;) { // initialize current size in y-direction if (iy == nfine) { ntot = nfine; } // check to stop if (iy >= nely || ntot >= nmin) { nely = iy; break; } // rules (1,2) satisfied: coarsen in x-direction (and z-direction) if (3 * nhy(iy) <= ntot && nelx % (3 * nhx(iy)) == 0 && ntot + nhy(iy) < nmin) { // - process refinement in x-direction refine(iy) = 0; nhy(iy) *= 2; auto vnhy = xt::view(nhy, xt::range(iy + 1, _)); auto vnhx = xt::view(nhx, xt::range(iy, _)); vnhy *= 3; vnhx *= 3; // - rule (2) satisfied: coarsen next element layer in z-direction if (iy + 1 < nely && ntot + 2 * nhy(iy) < nmin) { if (nelz % (3 * nhz(iy + 1)) == 0) { // - update the number of elements in y-direction ntot += nhy(iy); // - proceed to next element layer in y-direction ++iy; // - process refinement in z-direction refine(iy) = 2; nhy(iy) = nhy(iy - 1); auto vnhz = xt::view(nhz, xt::range(iy, _)); vnhz *= 3; } } } // rules (1,2) satisfied: coarse in z-direction else if (3 * nhy(iy) <= ntot && nelz % (3 * nhz(iy)) == 0 && ntot + nhy(iy) < nmin) { // - process refinement in z-direction refine(iy) = 2; nhy(iy) *= 2; auto vnhy = xt::view(nhy, xt::range(iy + 1, _)); auto vnhz = xt::view(nhz, xt::range(iy, _)); vnhy *= 3; vnhz *= 3; } // update the number of elements in y-direction ntot += nhy(iy); // proceed to next element layer in y-direction ++iy; // check to stop if (iy >= nely || ntot >= nmin) { nely = iy; break; } } // symmetrize, compute full information // allocate mesh constructor parameters m_nhx = xt::empty({nely * 2 - 1}); m_nhy = xt::empty({nely * 2 - 1}); m_nhz = xt::empty({nely * 2 - 1}); m_refine = xt::empty({nely * 2 - 1}); m_nelx = xt::empty({nely * 2 - 1}); m_nelz = xt::empty({nely * 2 - 1}); m_nnd = xt::empty({nely * 2}); m_startElem = xt::empty({nely * 2 - 1}); m_startNode = xt::empty({nely * 2}); // fill // - lower half for (size_t iy = 0; iy < nely; ++iy) { m_nhx(iy) = nhx(nely - iy - 1); m_nhy(iy) = nhy(nely - iy - 1); m_nhz(iy) = nhz(nely - iy - 1); m_refine(iy) = refine(nely - iy - 1); } // - upper half for (size_t iy = 0; iy < nely - 1; ++iy) { m_nhx(iy + nely) = nhx(iy + 1); m_nhy(iy + nely) = nhy(iy + 1); m_nhz(iy + nely) = nhz(iy + 1); m_refine(iy + nely) = refine(iy + 1); } // update size nely = m_nhx.size(); // compute the number of elements per element layer in y-direction for (size_t iy = 0; iy < nely; ++iy) { m_nelx(iy) = nelx / m_nhx(iy); m_nelz(iy) = nelz / m_nhz(iy); } // compute the number of nodes per node layer in y-direction // - bottom half for (size_t iy = 0; iy < (nely + 1) / 2; ++iy) m_nnd(iy) = (m_nelx(iy) + 1) * (m_nelz(iy) + 1); // - top half for (size_t iy = (nely - 1) / 2; iy < nely; ++iy) m_nnd(iy + 1) = (m_nelx(iy) + 1) * (m_nelz(iy) + 1); // compute mesh dimensions // initialize m_nnode = 0; m_nelem = 0; m_startNode(0) = 0; // loop over element layers (bottom -> middle, elements become finer) for (size_t i = 0; i < (nely - 1) / 2; ++i) { // - store the first element of the layer m_startElem(i) = m_nelem; // - add the nodes of this layer if (m_refine(i) == 0) { m_nnode += (3 * m_nelx(i) + 1) * (m_nelz(i) + 1); } else if (m_refine(i) == 2) { m_nnode += (m_nelx(i) + 1) * (3 * m_nelz(i) + 1); } else { m_nnode += (m_nelx(i) + 1) * (m_nelz(i) + 1); } // - add the elements of this layer if (m_refine(i) == 0) { m_nelem += (4 * m_nelx(i)) * (m_nelz(i)); } else if (m_refine(i) == 2) { m_nelem += (m_nelx(i)) * (4 * m_nelz(i)); } else { m_nelem += (m_nelx(i)) * (m_nelz(i)); } // - store the starting node of the next layer m_startNode(i + 1) = m_nnode; } // loop over element layers (middle -> top, elements become coarser) for (size_t i = (nely - 1) / 2; i < nely; ++i) { // - store the first element of the layer m_startElem(i) = m_nelem; // - add the nodes of this layer if (m_refine(i) == 0) { m_nnode += (5 * m_nelx(i) + 1) * (m_nelz(i) + 1); } else if (m_refine(i) == 2) { m_nnode += (m_nelx(i) + 1) * (5 * m_nelz(i) + 1); } else { m_nnode += (m_nelx(i) + 1) * (m_nelz(i) + 1); } // - add the elements of this layer if (m_refine(i) == 0) { m_nelem += (4 * m_nelx(i)) * (m_nelz(i)); } else if (m_refine(i) == 2) { m_nelem += (m_nelx(i)) * (4 * m_nelz(i)); } else { m_nelem += (m_nelx(i)) * (m_nelz(i)); } // - store the starting node of the next layer m_startNode(i + 1) = m_nnode; } // - add the top row of nodes m_nnode += (m_nelx(nely - 1) + 1) * (m_nelz(nely - 1) + 1); } inline size_t FineLayer::nelem() const { return m_nelem; } inline size_t FineLayer::nnode() const { return m_nnode; } inline size_t FineLayer::nne() const { return m_nne; } inline size_t FineLayer::ndim() const { return m_ndim; } inline size_t FineLayer::nelx() const { return xt::amax(m_nelx)[0]; } inline size_t FineLayer::nely() const { return xt::sum(m_nhy)[0]; } inline size_t FineLayer::nelz() const { return xt::amax(m_nelz)[0]; } inline ElementType FineLayer::getElementType() const { return ElementType::Hex8; } -inline xt::xtensor FineLayer::coor() const +inline xt::xtensor FineLayer::coor() const { // allocate output - xt::xtensor out = xt::empty({m_nnode, m_ndim}); + xt::xtensor out = xt::empty({m_nnode, m_ndim}); // current node, number of element layers size_t inode = 0; size_t nely = static_cast(m_nhy.size()); // y-position of each main node layer (i.e. excluding node layers for refinement/coarsening) // - allocate - xt::xtensor y = xt::empty({nely + 1}); + xt::xtensor y = xt::empty({nely + 1}); // - initialize y(0) = 0.0; // - compute for (size_t iy = 1; iy < nely + 1; ++iy) { y(iy) = y(iy - 1) + m_nhy(iy - 1) * m_h; } // loop over element layers (bottom -> middle) : add bottom layer (+ refinement layer) of nodes for (size_t iy = 0;; ++iy) { // get positions along the x- and z-axis - xt::xtensor x = xt::linspace(0.0, m_Lx, m_nelx(iy) + 1); - xt::xtensor z = xt::linspace(0.0, m_Lz, m_nelz(iy) + 1); + xt::xtensor x = xt::linspace(0.0, m_Lx, m_nelx(iy) + 1); + xt::xtensor z = xt::linspace(0.0, m_Lz, m_nelz(iy) + 1); // add nodes of the bottom layer of this element for (size_t iz = 0; iz < m_nelz(iy) + 1; ++iz) { for (size_t ix = 0; ix < m_nelx(iy) + 1; ++ix) { out(inode, 0) = x(ix); out(inode, 1) = y(iy); out(inode, 2) = z(iz); ++inode; } } // stop at middle layer if (iy == (nely - 1) / 2) { break; } // add extra nodes of the intermediate layer, for refinement in x-direction if (m_refine(iy) == 0) { // - get position offset in x- and y-direction double dx = m_h * static_cast(m_nhx(iy) / 3); double dy = m_h * static_cast(m_nhy(iy) / 2); // - add nodes of the intermediate layer for (size_t iz = 0; iz < m_nelz(iy) + 1; ++iz) { for (size_t ix = 0; ix < m_nelx(iy); ++ix) { for (size_t j = 0; j < 2; ++j) { out(inode, 0) = x(ix) + dx * static_cast(j + 1); out(inode, 1) = y(iy) + dy; out(inode, 2) = z(iz); ++inode; } } } } // add extra nodes of the intermediate layer, for refinement in z-direction else if (m_refine(iy) == 2) { // - get position offset in y- and z-direction double dz = m_h * static_cast(m_nhz(iy) / 3); double dy = m_h * static_cast(m_nhy(iy) / 2); // - add nodes of the intermediate layer for (size_t iz = 0; iz < m_nelz(iy); ++iz) { for (size_t j = 0; j < 2; ++j) { for (size_t ix = 0; ix < m_nelx(iy) + 1; ++ix) { out(inode, 0) = x(ix); out(inode, 1) = y(iy) + dy; out(inode, 2) = z(iz) + dz * static_cast(j + 1); ++inode; } } } } } // loop over element layers (middle -> top) : add (refinement layer +) top layer of nodes for (size_t iy = (nely - 1) / 2; iy < nely; ++iy) { // get positions along the x- and z-axis - xt::xtensor x = xt::linspace(0.0, m_Lx, m_nelx(iy) + 1); - xt::xtensor z = xt::linspace(0.0, m_Lz, m_nelz(iy) + 1); + xt::xtensor x = xt::linspace(0.0, m_Lx, m_nelx(iy) + 1); + xt::xtensor z = xt::linspace(0.0, m_Lz, m_nelz(iy) + 1); // add extra nodes of the intermediate layer, for refinement in x-direction if (m_refine(iy) == 0) { // - get position offset in x- and y-direction double dx = m_h * static_cast(m_nhx(iy) / 3); double dy = m_h * static_cast(m_nhy(iy) / 2); // - add nodes of the intermediate layer for (size_t iz = 0; iz < m_nelz(iy) + 1; ++iz) { for (size_t ix = 0; ix < m_nelx(iy); ++ix) { for (size_t j = 0; j < 2; ++j) { out(inode, 0) = x(ix) + dx * static_cast(j + 1); out(inode, 1) = y(iy) + dy; out(inode, 2) = z(iz); ++inode; } } } } // add extra nodes of the intermediate layer, for refinement in z-direction else if (m_refine(iy) == 2) { // - get position offset in y- and z-direction double dz = m_h * static_cast(m_nhz(iy) / 3); double dy = m_h * static_cast(m_nhy(iy) / 2); // - add nodes of the intermediate layer for (size_t iz = 0; iz < m_nelz(iy); ++iz) { for (size_t j = 0; j < 2; ++j) { for (size_t ix = 0; ix < m_nelx(iy) + 1; ++ix) { out(inode, 0) = x(ix); out(inode, 1) = y(iy) + dy; out(inode, 2) = z(iz) + dz * static_cast(j + 1); ++inode; } } } } // add nodes of the top layer of this element for (size_t iz = 0; iz < m_nelz(iy) + 1; ++iz) { for (size_t ix = 0; ix < m_nelx(iy) + 1; ++ix) { out(inode, 0) = x(ix); out(inode, 1) = y(iy + 1); out(inode, 2) = z(iz); ++inode; } } } return out; } -inline xt::xtensor FineLayer::conn() const +inline xt::xtensor FineLayer::conn() const { // allocate output - xt::xtensor out = xt::empty({m_nelem, m_nne}); + xt::xtensor out = xt::empty({m_nelem, m_nne}); // current element, number of element layers, starting nodes of each node layer size_t ielem = 0; size_t nely = static_cast(m_nhy.size()); size_t bot, mid, top; // loop over all element layers for (size_t iy = 0; iy < nely; ++iy) { // - get: starting nodes of bottom(, middle) and top layer bot = m_startNode(iy); mid = m_startNode(iy) + m_nnd(iy); top = m_startNode(iy + 1); // - define connectivity: no coarsening/refinement if (m_refine(iy) == -1) { for (size_t iz = 0; iz < m_nelz(iy); ++iz) { for (size_t ix = 0; ix < m_nelx(iy); ++ix) { out(ielem, 0) = bot + ix + iz * (m_nelx(iy) + 1); out(ielem, 1) = bot + (ix + 1) + iz * (m_nelx(iy) + 1); out(ielem, 2) = top + (ix + 1) + iz * (m_nelx(iy) + 1); out(ielem, 3) = top + ix + iz * (m_nelx(iy) + 1); out(ielem, 4) = bot + ix + (iz + 1) * (m_nelx(iy) + 1); out(ielem, 5) = bot + (ix + 1) + (iz + 1) * (m_nelx(iy) + 1); out(ielem, 6) = top + (ix + 1) + (iz + 1) * (m_nelx(iy) + 1); out(ielem, 7) = top + ix + (iz + 1) * (m_nelx(iy) + 1); ielem++; } } } // - define connectivity: refinement along the x-direction (below the middle layer) else if (m_refine(iy) == 0 && iy <= (nely - 1) / 2) { for (size_t iz = 0; iz < m_nelz(iy); ++iz) { for (size_t ix = 0; ix < m_nelx(iy); ++ix) { // -- bottom element out(ielem, 0) = bot + ix + iz * (m_nelx(iy) + 1); out(ielem, 1) = bot + (ix + 1) + iz * (m_nelx(iy) + 1); out(ielem, 2) = mid + (2 * ix + 1) + iz * (2 * m_nelx(iy)); out(ielem, 3) = mid + (2 * ix) + iz * (2 * m_nelx(iy)); out(ielem, 4) = bot + ix + (iz + 1) * (m_nelx(iy) + 1); out(ielem, 5) = bot + (ix + 1) + (iz + 1) * (m_nelx(iy) + 1); out(ielem, 6) = mid + (2 * ix + 1) + (iz + 1) * (2 * m_nelx(iy)); out(ielem, 7) = mid + (2 * ix) + (iz + 1) * (2 * m_nelx(iy)); ielem++; // -- top-right element out(ielem, 0) = bot + (ix + 1) + iz * (m_nelx(iy) + 1); out(ielem, 1) = top + (3 * ix + 3) + iz * (3 * m_nelx(iy) + 1); out(ielem, 2) = top + (3 * ix + 2) + iz * (3 * m_nelx(iy) + 1); out(ielem, 3) = mid + (2 * ix + 1) + iz * (2 * m_nelx(iy)); out(ielem, 4) = bot + (ix + 1) + (iz + 1) * (m_nelx(iy) + 1); out(ielem, 5) = top + (3 * ix + 3) + (iz + 1) * (3 * m_nelx(iy) + 1); out(ielem, 6) = top + (3 * ix + 2) + (iz + 1) * (3 * m_nelx(iy) + 1); out(ielem, 7) = mid + (2 * ix + 1) + (iz + 1) * (2 * m_nelx(iy)); ielem++; // -- top-center element out(ielem, 0) = mid + (2 * ix) + iz * (2 * m_nelx(iy)); out(ielem, 1) = mid + (2 * ix + 1) + iz * (2 * m_nelx(iy)); out(ielem, 2) = top + (3 * ix + 2) + iz * (3 * m_nelx(iy) + 1); out(ielem, 3) = top + (3 * ix + 1) + iz * (3 * m_nelx(iy) + 1); out(ielem, 4) = mid + (2 * ix) + (iz + 1) * (2 * m_nelx(iy)); out(ielem, 5) = mid + (2 * ix + 1) + (iz + 1) * (2 * m_nelx(iy)); out(ielem, 6) = top + (3 * ix + 2) + (iz + 1) * (3 * m_nelx(iy) + 1); out(ielem, 7) = top + (3 * ix + 1) + (iz + 1) * (3 * m_nelx(iy) + 1); ielem++; // -- top-left element out(ielem, 0) = bot + ix + iz * (m_nelx(iy) + 1); out(ielem, 1) = mid + (2 * ix) + iz * (2 * m_nelx(iy)); out(ielem, 2) = top + (3 * ix + 1) + iz * (3 * m_nelx(iy) + 1); out(ielem, 3) = top + (3 * ix) + iz * (3 * m_nelx(iy) + 1); out(ielem, 4) = bot + ix + (iz + 1) * (m_nelx(iy) + 1); out(ielem, 5) = mid + (2 * ix) + (iz + 1) * (2 * m_nelx(iy)); out(ielem, 6) = top + (3 * ix + 1) + (iz + 1) * (3 * m_nelx(iy) + 1); out(ielem, 7) = top + (3 * ix) + (iz + 1) * (3 * m_nelx(iy) + 1); ielem++; } } } // - define connectivity: coarsening along the x-direction (above the middle layer) else if (m_refine(iy) == 0 && iy > (nely - 1) / 2) { for (size_t iz = 0; iz < m_nelz(iy); ++iz) { for (size_t ix = 0; ix < m_nelx(iy); ++ix) { // -- lower-left element out(ielem, 0) = bot + (3 * ix) + iz * (3 * m_nelx(iy) + 1); out(ielem, 1) = bot + (3 * ix + 1) + iz * (3 * m_nelx(iy) + 1); out(ielem, 2) = mid + (2 * ix) + iz * (2 * m_nelx(iy)); out(ielem, 3) = top + ix + iz * (m_nelx(iy) + 1); out(ielem, 4) = bot + (3 * ix) + (iz + 1) * (3 * m_nelx(iy) + 1); out(ielem, 5) = bot + (3 * ix + 1) + (iz + 1) * (3 * m_nelx(iy) + 1); out(ielem, 6) = mid + (2 * ix) + (iz + 1) * (2 * m_nelx(iy)); out(ielem, 7) = top + ix + (iz + 1) * (m_nelx(iy) + 1); ielem++; // -- lower-center element out(ielem, 0) = bot + (3 * ix + 1) + iz * (3 * m_nelx(iy) + 1); out(ielem, 1) = bot + (3 * ix + 2) + iz * (3 * m_nelx(iy) + 1); out(ielem, 2) = mid + (2 * ix + 1) + iz * (2 * m_nelx(iy)); out(ielem, 3) = mid + (2 * ix) + iz * (2 * m_nelx(iy)); out(ielem, 4) = bot + (3 * ix + 1) + (iz + 1) * (3 * m_nelx(iy) + 1); out(ielem, 5) = bot + (3 * ix + 2) + (iz + 1) * (3 * m_nelx(iy) + 1); out(ielem, 6) = mid + (2 * ix + 1) + (iz + 1) * (2 * m_nelx(iy)); out(ielem, 7) = mid + (2 * ix) + (iz + 1) * (2 * m_nelx(iy)); ielem++; // -- lower-right element out(ielem, 0) = bot + (3 * ix + 2) + iz * (3 * m_nelx(iy) + 1); out(ielem, 1) = bot + (3 * ix + 3) + iz * (3 * m_nelx(iy) + 1); out(ielem, 2) = top + (ix + 1) + iz * (m_nelx(iy) + 1); out(ielem, 3) = mid + (2 * ix + 1) + iz * (2 * m_nelx(iy)); out(ielem, 4) = bot + (3 * ix + 2) + (iz + 1) * (3 * m_nelx(iy) + 1); out(ielem, 5) = bot + (3 * ix + 3) + (iz + 1) * (3 * m_nelx(iy) + 1); out(ielem, 6) = top + (ix + 1) + (iz + 1) * (m_nelx(iy) + 1); out(ielem, 7) = mid + (2 * ix + 1) + (iz + 1) * (2 * m_nelx(iy)); ielem++; // -- upper element out(ielem, 0) = mid + (2 * ix) + iz * (2 * m_nelx(iy)); out(ielem, 1) = mid + (2 * ix + 1) + iz * (2 * m_nelx(iy)); out(ielem, 2) = top + (ix + 1) + iz * (m_nelx(iy) + 1); out(ielem, 3) = top + ix + iz * (m_nelx(iy) + 1); out(ielem, 4) = mid + (2 * ix) + (iz + 1) * (2 * m_nelx(iy)); out(ielem, 5) = mid + (2 * ix + 1) + (iz + 1) * (2 * m_nelx(iy)); out(ielem, 6) = top + (ix + 1) + (iz + 1) * (m_nelx(iy) + 1); out(ielem, 7) = top + ix + (iz + 1) * (m_nelx(iy) + 1); ielem++; } } } // - define connectivity: refinement along the z-direction (below the middle layer) else if (m_refine(iy) == 2 && iy <= (nely - 1) / 2) { for (size_t iz = 0; iz < m_nelz(iy); ++iz) { for (size_t ix = 0; ix < m_nelx(iy); ++ix) { // -- bottom element out(ielem, 0) = bot + ix + iz * (m_nelx(iy) + 1); out(ielem, 1) = bot + ix + (iz + 1) * (m_nelx(iy) + 1); out(ielem, 2) = bot + (ix + 1) + (iz + 1) * (m_nelx(iy) + 1); out(ielem, 3) = bot + (ix + 1) + iz * (m_nelx(iy) + 1); out(ielem, 4) = mid + ix + 2 * iz * (m_nelx(iy) + 1); out(ielem, 5) = mid + ix + (2 * iz + 1) * (m_nelx(iy) + 1); out(ielem, 6) = mid + (ix + 1) + (2 * iz + 1) * (m_nelx(iy) + 1); out(ielem, 7) = mid + (ix + 1) + 2 * iz * (m_nelx(iy) + 1); ielem++; // -- top-back element out(ielem, 0) = mid + ix + (2 * iz + 1) * (m_nelx(iy) + 1); out(ielem, 1) = mid + (ix + 1) + (2 * iz + 1) * (m_nelx(iy) + 1); out(ielem, 2) = top + (ix + 1) + (3 * iz + 2) * (m_nelx(iy) + 1); out(ielem, 3) = top + ix + (3 * iz + 2) * (m_nelx(iy) + 1); out(ielem, 4) = bot + ix + (iz + 1) * (m_nelx(iy) + 1); out(ielem, 5) = bot + (ix + 1) + (iz + 1) * (m_nelx(iy) + 1); out(ielem, 6) = top + (ix + 1) + (3 * iz + 3) * (m_nelx(iy) + 1); out(ielem, 7) = top + ix + (3 * iz + 3) * (m_nelx(iy) + 1); ielem++; // -- top-center element out(ielem, 0) = mid + ix + (2 * iz) * (m_nelx(iy) + 1); out(ielem, 1) = mid + (ix + 1) + (2 * iz) * (m_nelx(iy) + 1); out(ielem, 2) = top + (ix + 1) + (3 * iz + 1) * (m_nelx(iy) + 1); out(ielem, 3) = top + ix + (3 * iz + 1) * (m_nelx(iy) + 1); out(ielem, 4) = mid + ix + (2 * iz + 1) * (m_nelx(iy) + 1); out(ielem, 5) = mid + (ix + 1) + (2 * iz + 1) * (m_nelx(iy) + 1); out(ielem, 6) = top + (ix + 1) + (3 * iz + 2) * (m_nelx(iy) + 1); out(ielem, 7) = top + ix + (3 * iz + 2) * (m_nelx(iy) + 1); ielem++; // -- top-front element out(ielem, 0) = bot + ix + iz * (m_nelx(iy) + 1); out(ielem, 1) = bot + (ix + 1) + iz * (m_nelx(iy) + 1); out(ielem, 2) = top + (ix + 1) + (3 * iz) * (m_nelx(iy) + 1); out(ielem, 3) = top + ix + (3 * iz) * (m_nelx(iy) + 1); out(ielem, 4) = mid + ix + (2 * iz) * (m_nelx(iy) + 1); out(ielem, 5) = mid + (ix + 1) + (2 * iz) * (m_nelx(iy) + 1); out(ielem, 6) = top + (ix + 1) + (3 * iz + 1) * (m_nelx(iy) + 1); out(ielem, 7) = top + ix + (3 * iz + 1) * (m_nelx(iy) + 1); ielem++; } } } // - define connectivity: coarsening along the z-direction (above the middle layer) else if (m_refine(iy) == 2 && iy > (nely - 1) / 2) { for (size_t iz = 0; iz < m_nelz(iy); ++iz) { for (size_t ix = 0; ix < m_nelx(iy); ++ix) { // -- bottom-front element out(ielem, 0) = bot + ix + (3 * iz) * (m_nelx(iy) + 1); out(ielem, 1) = bot + (ix + 1) + (3 * iz) * (m_nelx(iy) + 1); out(ielem, 2) = top + (ix + 1) + iz * (m_nelx(iy) + 1); out(ielem, 3) = top + ix + iz * (m_nelx(iy) + 1); out(ielem, 4) = bot + ix + (3 * iz + 1) * (m_nelx(iy) + 1); out(ielem, 5) = bot + (ix + 1) + (3 * iz + 1) * (m_nelx(iy) + 1); out(ielem, 6) = mid + (ix + 1) + (2 * iz) * (m_nelx(iy) + 1); out(ielem, 7) = mid + ix + (2 * iz) * (m_nelx(iy) + 1); ielem++; // -- bottom-center element out(ielem, 0) = bot + ix + (3 * iz + 1) * (m_nelx(iy) + 1); out(ielem, 1) = bot + (ix + 1) + (3 * iz + 1) * (m_nelx(iy) + 1); out(ielem, 2) = mid + (ix + 1) + (2 * iz) * (m_nelx(iy) + 1); out(ielem, 3) = mid + ix + (2 * iz) * (m_nelx(iy) + 1); out(ielem, 4) = bot + ix + (3 * iz + 2) * (m_nelx(iy) + 1); out(ielem, 5) = bot + (ix + 1) + (3 * iz + 2) * (m_nelx(iy) + 1); out(ielem, 6) = mid + (ix + 1) + (2 * iz + 1) * (m_nelx(iy) + 1); out(ielem, 7) = mid + ix + (2 * iz + 1) * (m_nelx(iy) + 1); ielem++; // -- bottom-back element out(ielem, 0) = bot + ix + (3 * iz + 2) * (m_nelx(iy) + 1); out(ielem, 1) = bot + (ix + 1) + (3 * iz + 2) * (m_nelx(iy) + 1); out(ielem, 2) = mid + (ix + 1) + (2 * iz + 1) * (m_nelx(iy) + 1); out(ielem, 3) = mid + ix + (2 * iz + 1) * (m_nelx(iy) + 1); out(ielem, 4) = bot + ix + (3 * iz + 3) * (m_nelx(iy) + 1); out(ielem, 5) = bot + (ix + 1) + (3 * iz + 3) * (m_nelx(iy) + 1); out(ielem, 6) = top + (ix + 1) + (iz + 1) * (m_nelx(iy) + 1); out(ielem, 7) = top + ix + (iz + 1) * (m_nelx(iy) + 1); ielem++; // -- top element out(ielem, 0) = mid + ix + (2 * iz) * (m_nelx(iy) + 1); out(ielem, 1) = mid + (ix + 1) + (2 * iz) * (m_nelx(iy) + 1); out(ielem, 2) = top + (ix + 1) + iz * (m_nelx(iy) + 1); out(ielem, 3) = top + ix + iz * (m_nelx(iy) + 1); out(ielem, 4) = mid + ix + (2 * iz + 1) * (m_nelx(iy) + 1); out(ielem, 5) = mid + (ix + 1) + (2 * iz + 1) * (m_nelx(iy) + 1); out(ielem, 6) = top + (ix + 1) + (iz + 1) * (m_nelx(iy) + 1); out(ielem, 7) = top + ix + (iz + 1) * (m_nelx(iy) + 1); ielem++; } } } } return out; } -inline xt::xtensor FineLayer::elementsMiddleLayer() const +inline xt::xtensor FineLayer::elementsMiddleLayer() const { size_t nely = static_cast(m_nhy.size()); size_t iy = (nely - 1) / 2; - xt::xtensor out = xt::empty({m_nelx(iy) * m_nelz(iy)}); + xt::xtensor out = xt::empty({m_nelx(iy) * m_nelz(iy)}); for (size_t ix = 0; ix < m_nelx(iy); ++ix) { for (size_t iz = 0; iz < m_nelz(iy); ++iz) { out(ix + iz * m_nelx(iy)) = m_startElem(iy) + ix + iz * m_nelx(iy); } } return out; } -inline xt::xtensor FineLayer::nodesFront() const +inline xt::xtensor FineLayer::nodesFront() const { // number of element layers in y-direction size_t nely = static_cast(m_nhy.size()); // number of boundary nodes // - initialize size_t n = 0; // - bottom half: bottom node layer (+ middle node layer) for (size_t iy = 0; iy < (nely + 1) / 2; ++iy) { if (m_refine(iy) == 0) { n += m_nelx(iy) * 3 + 1; } else { n += m_nelx(iy) + 1; } } // - top half: (middle node layer +) top node layer for (size_t iy = (nely - 1) / 2; iy < nely; ++iy) { if (m_refine(iy) == 0) { n += m_nelx(iy) * 3 + 1; } else { n += m_nelx(iy) + 1; } } // allocate node-list - xt::xtensor out = xt::empty({n}); + xt::xtensor out = xt::empty({n}); // initialize counter: current index in the node-list "out" size_t j = 0; // bottom half: bottom node layer (+ middle node layer) for (size_t iy = 0; iy < (nely + 1) / 2; ++iy) { // -- bottom node layer for (size_t ix = 0; ix < m_nelx(iy) + 1; ++ix) { out(j) = m_startNode(iy) + ix; ++j; } // -- refinement layer if (m_refine(iy) == 0) { for (size_t ix = 0; ix < 2 * m_nelx(iy); ++ix) { out(j) = m_startNode(iy) + ix + m_nnd(iy); ++j; } } } // top half: (middle node layer +) top node layer for (size_t iy = (nely - 1) / 2; iy < nely; ++iy) { // -- refinement layer if (m_refine(iy) == 0) { for (size_t ix = 0; ix < 2 * m_nelx(iy); ++ix) { out(j) = m_startNode(iy) + ix + m_nnd(iy); ++j; } } // -- top node layer for (size_t ix = 0; ix < m_nelx(iy) + 1; ++ix) { out(j) = m_startNode(iy + 1) + ix; ++j; } } return out; } -inline xt::xtensor FineLayer::nodesBack() const +inline xt::xtensor FineLayer::nodesBack() const { // number of element layers in y-direction size_t nely = static_cast(m_nhy.size()); // number of boundary nodes // - initialize size_t n = 0; // - bottom half: bottom node layer (+ middle node layer) for (size_t iy = 0; iy < (nely + 1) / 2; ++iy) { if (m_refine(iy) == 0) { n += m_nelx(iy) * 3 + 1; } else { n += m_nelx(iy) + 1; } } // - top half: (middle node layer +) top node layer for (size_t iy = (nely - 1) / 2; iy < nely; ++iy) { if (m_refine(iy) == 0) { n += m_nelx(iy) * 3 + 1; } else { n += m_nelx(iy) + 1; } } // allocate node-list - xt::xtensor out = xt::empty({n}); + xt::xtensor out = xt::empty({n}); // initialize counter: current index in the node-list "out" size_t j = 0; // bottom half: bottom node layer (+ middle node layer) for (size_t iy = 0; iy < (nely + 1) / 2; ++iy) { // -- bottom node layer for (size_t ix = 0; ix < m_nelx(iy) + 1; ++ix) { out(j) = m_startNode(iy) + ix + (m_nelx(iy) + 1) * m_nelz(iy); ++j; } // -- refinement layer if (m_refine(iy) == 0) { for (size_t ix = 0; ix < 2 * m_nelx(iy); ++ix) { out(j) = m_startNode(iy) + ix + m_nnd(iy) + 2 * m_nelx(iy) * m_nelz(iy); ++j; } } } // top half: (middle node layer +) top node layer for (size_t iy = (nely - 1) / 2; iy < nely; ++iy) { // -- refinement layer if (m_refine(iy) == 0) { for (size_t ix = 0; ix < 2 * m_nelx(iy); ++ix) { out(j) = m_startNode(iy) + ix + m_nnd(iy) + 2 * m_nelx(iy) * m_nelz(iy); ++j; } } // -- top node layer for (size_t ix = 0; ix < m_nelx(iy) + 1; ++ix) { out(j) = m_startNode(iy + 1) + ix + (m_nelx(iy) + 1) * m_nelz(iy); ++j; } } return out; } -inline xt::xtensor FineLayer::nodesLeft() const +inline xt::xtensor FineLayer::nodesLeft() const { // number of element layers in y-direction size_t nely = static_cast(m_nhy.size()); // number of boundary nodes // - initialize size_t n = 0; // - bottom half: bottom node layer (+ middle node layer) for (size_t iy = 0; iy < (nely + 1) / 2; ++iy) { if (m_refine(iy) == 2) { n += m_nelz(iy) * 3 + 1; } else { n += m_nelz(iy) + 1; } } // - top half: (middle node layer +) top node layer for (size_t iy = (nely - 1) / 2; iy < nely; ++iy) { if (m_refine(iy) == 2) { n += m_nelz(iy) * 3 + 1; } else { n += m_nelz(iy) + 1; } } // allocate node-list - xt::xtensor out = xt::empty({n}); + xt::xtensor out = xt::empty({n}); // initialize counter: current index in the node-list "out" size_t j = 0; // bottom half: bottom node layer (+ middle node layer) for (size_t iy = 0; iy < (nely + 1) / 2; ++iy) { // -- bottom node layer for (size_t iz = 0; iz < m_nelz(iy) + 1; ++iz) { out(j) = m_startNode(iy) + iz * (m_nelx(iy) + 1); ++j; } // -- refinement layer if (m_refine(iy) == 2) { for (size_t iz = 0; iz < 2 * m_nelz(iy); ++iz) { out(j) = m_startNode(iy) + iz * (m_nelx(iy) + 1) + m_nnd(iy); ++j; } } } // top half: (middle node layer +) top node layer for (size_t iy = (nely - 1) / 2; iy < nely; ++iy) { // -- refinement layer if (m_refine(iy) == 2) { for (size_t iz = 0; iz < 2 * m_nelz(iy); ++iz) { out(j) = m_startNode(iy) + iz * (m_nelx(iy) + 1) + m_nnd(iy); ++j; } } // -- top node layer for (size_t iz = 0; iz < m_nelz(iy) + 1; ++iz) { out(j) = m_startNode(iy + 1) + iz * (m_nelx(iy) + 1); ++j; } } return out; } -inline xt::xtensor FineLayer::nodesRight() const +inline xt::xtensor FineLayer::nodesRight() const { // number of element layers in y-direction size_t nely = static_cast(m_nhy.size()); // number of boundary nodes // - initialize size_t n = 0; // - bottom half: bottom node layer (+ middle node layer) for (size_t iy = 0; iy < (nely + 1) / 2; ++iy) { if (m_refine(iy) == 2) n += m_nelz(iy) * 3 + 1; else n += m_nelz(iy) + 1; } // - top half: (middle node layer +) top node layer for (size_t iy = (nely - 1) / 2; iy < nely; ++iy) { if (m_refine(iy) == 2) n += m_nelz(iy) * 3 + 1; else n += m_nelz(iy) + 1; } // allocate node-list - xt::xtensor out = xt::empty({n}); + xt::xtensor out = xt::empty({n}); // initialize counter: current index in the node-list "out" size_t j = 0; // bottom half: bottom node layer (+ middle node layer) for (size_t iy = 0; iy < (nely + 1) / 2; ++iy) { // -- bottom node layer for (size_t iz = 0; iz < m_nelz(iy) + 1; ++iz) { out(j) = m_startNode(iy) + iz * (m_nelx(iy) + 1) + m_nelx(iy); ++j; } // -- refinement layer if (m_refine(iy) == 2) { for (size_t iz = 0; iz < 2 * m_nelz(iy); ++iz) { out(j) = m_startNode(iy) + m_nnd(iy) + iz * (m_nelx(iy) + 1) + m_nelx(iy); ++j; } } } // top half: (middle node layer +) top node layer for (size_t iy = (nely - 1) / 2; iy < nely; ++iy) { // -- refinement layer if (m_refine(iy) == 2) { for (size_t iz = 0; iz < 2 * m_nelz(iy); ++iz) { out(j) = m_startNode(iy) + m_nnd(iy) + iz * (m_nelx(iy) + 1) + m_nelx(iy); ++j; } } // -- top node layer for (size_t iz = 0; iz < m_nelz(iy) + 1; ++iz) { out(j) = m_startNode(iy + 1) + iz * (m_nelx(iy) + 1) + m_nelx(iy); ++j; } } return out; } -inline xt::xtensor FineLayer::nodesBottom() const +inline xt::xtensor FineLayer::nodesBottom() const { // number of element layers in y-direction size_t nely = static_cast(m_nhy.size()); // allocate node list - xt::xtensor out = xt::empty({m_nnd(nely)}); + xt::xtensor out = xt::empty({m_nnd(nely)}); // counter size_t j = 0; // fill node list for (size_t ix = 0; ix < m_nelx(0) + 1; ++ix) { for (size_t iz = 0; iz < m_nelz(0) + 1; ++iz) { out(j) = m_startNode(0) + ix + iz * (m_nelx(0) + 1); ++j; } } return out; } -inline xt::xtensor FineLayer::nodesTop() const +inline xt::xtensor FineLayer::nodesTop() const { // number of element layers in y-direction size_t nely = static_cast(m_nhy.size()); // allocate node list - xt::xtensor out = xt::empty({m_nnd(nely)}); + xt::xtensor out = xt::empty({m_nnd(nely)}); // counter size_t j = 0; // fill node list for (size_t ix = 0; ix < m_nelx(nely - 1) + 1; ++ix) { for (size_t iz = 0; iz < m_nelz(nely - 1) + 1; ++iz) { out(j) = m_startNode(nely) + ix + iz * (m_nelx(nely - 1) + 1); ++j; } } return out; } -inline xt::xtensor FineLayer::nodesFrontFace() const +inline xt::xtensor FineLayer::nodesFrontFace() const { // number of element layers in y-direction size_t nely = static_cast(m_nhy.size()); // number of boundary nodes // - initialize size_t n = 0; // - bottom half: bottom node layer (+ middle node layer) for (size_t iy = 1; iy < (nely + 1) / 2; ++iy) { if (m_refine(iy) == 0) { n += m_nelx(iy) * 3 - 1; } else { n += m_nelx(iy) - 1; } } // - top half: (middle node layer +) top node layer for (size_t iy = (nely - 1) / 2; iy < nely - 1; ++iy) { if (m_refine(iy) == 0) { n += m_nelx(iy) * 3 - 1; } else { n += m_nelx(iy) - 1; } } // allocate node-list - xt::xtensor out = xt::empty({n}); + xt::xtensor out = xt::empty({n}); // initialize counter: current index in the node-list "out" size_t j = 0; // bottom half: bottom node layer (+ middle node layer) for (size_t iy = 1; iy < (nely + 1) / 2; ++iy) { // -- bottom node layer for (size_t ix = 1; ix < m_nelx(iy); ++ix) { out(j) = m_startNode(iy) + ix; ++j; } // -- refinement layer if (m_refine(iy) == 0) { for (size_t ix = 0; ix < 2 * m_nelx(iy); ++ix) { out(j) = m_startNode(iy) + ix + m_nnd(iy); ++j; } } } // top half: (middle node layer +) top node layer for (size_t iy = (nely - 1) / 2; iy < nely - 1; ++iy) { // -- refinement layer if (m_refine(iy) == 0) { for (size_t ix = 0; ix < 2 * m_nelx(iy); ++ix) { out(j) = m_startNode(iy) + ix + m_nnd(iy); ++j; } } // -- top node layer for (size_t ix = 1; ix < m_nelx(iy); ++ix) { out(j) = m_startNode(iy + 1) + ix; ++j; } } return out; } -inline xt::xtensor FineLayer::nodesBackFace() const +inline xt::xtensor FineLayer::nodesBackFace() const { // number of element layers in y-direction size_t nely = static_cast(m_nhy.size()); // number of boundary nodes // - initialize size_t n = 0; // - bottom half: bottom node layer (+ middle node layer) for (size_t iy = 1; iy < (nely + 1) / 2; ++iy) { if (m_refine(iy) == 0) { n += m_nelx(iy) * 3 - 1; } else { n += m_nelx(iy) - 1; } } // - top half: (middle node layer +) top node layer for (size_t iy = (nely - 1) / 2; iy < nely - 1; ++iy) { if (m_refine(iy) == 0) { n += m_nelx(iy) * 3 - 1; } else { n += m_nelx(iy) - 1; } } // allocate node-list - xt::xtensor out = xt::empty({n}); + xt::xtensor out = xt::empty({n}); // initialize counter: current index in the node-list "out" size_t j = 0; // bottom half: bottom node layer (+ middle node layer) for (size_t iy = 1; iy < (nely + 1) / 2; ++iy) { // -- bottom node layer for (size_t ix = 1; ix < m_nelx(iy); ++ix) { out(j) = m_startNode(iy) + ix + (m_nelx(iy) + 1) * m_nelz(iy); ++j; } // -- refinement layer if (m_refine(iy) == 0) { for (size_t ix = 0; ix < 2 * m_nelx(iy); ++ix) { out(j) = m_startNode(iy) + ix + m_nnd(iy) + 2 * m_nelx(iy) * m_nelz(iy); ++j; } } } // top half: (middle node layer +) top node layer for (size_t iy = (nely - 1) / 2; iy < nely - 1; ++iy) { // -- refinement layer if (m_refine(iy) == 0) { for (size_t ix = 0; ix < 2 * m_nelx(iy); ++ix) { out(j) = m_startNode(iy) + ix + m_nnd(iy) + 2 * m_nelx(iy) * m_nelz(iy); ++j; } } // -- top node layer for (size_t ix = 1; ix < m_nelx(iy); ++ix) { out(j) = m_startNode(iy + 1) + ix + (m_nelx(iy) + 1) * m_nelz(iy); ++j; } } return out; } -inline xt::xtensor FineLayer::nodesLeftFace() const +inline xt::xtensor FineLayer::nodesLeftFace() const { // number of element layers in y-direction size_t nely = static_cast(m_nhy.size()); // number of boundary nodes // - initialize size_t n = 0; // - bottom half: bottom node layer (+ middle node layer) for (size_t iy = 1; iy < (nely + 1) / 2; ++iy) { if (m_refine(iy) == 2) { n += m_nelz(iy) * 3 - 1; } else { n += m_nelz(iy) - 1; } } // - top half: (middle node layer +) top node layer for (size_t iy = (nely - 1) / 2; iy < nely - 1; ++iy) { if (m_refine(iy) == 2) { n += m_nelz(iy) * 3 - 1; } else { n += m_nelz(iy) - 1; } } // allocate node-list - xt::xtensor out = xt::empty({n}); + xt::xtensor out = xt::empty({n}); // initialize counter: current index in the node-list "out" size_t j = 0; // bottom half: bottom node layer (+ middle node layer) for (size_t iy = 1; iy < (nely + 1) / 2; ++iy) { // -- bottom node layer for (size_t iz = 1; iz < m_nelz(iy); ++iz) { out(j) = m_startNode(iy) + iz * (m_nelx(iy) + 1); ++j; } // -- refinement layer if (m_refine(iy) == 2) { for (size_t iz = 0; iz < 2 * m_nelz(iy); ++iz) { out(j) = m_startNode(iy) + iz * (m_nelx(iy) + 1) + m_nnd(iy); ++j; } } } // top half: (middle node layer +) top node layer for (size_t iy = (nely - 1) / 2; iy < nely - 1; ++iy) { // -- refinement layer if (m_refine(iy) == 2) { for (size_t iz = 0; iz < 2 * m_nelz(iy); ++iz) { out(j) = m_startNode(iy) + iz * (m_nelx(iy) + 1) + m_nnd(iy); ++j; } } // -- top node layer for (size_t iz = 1; iz < m_nelz(iy); ++iz) { out(j) = m_startNode(iy + 1) + iz * (m_nelx(iy) + 1); ++j; } } return out; } -inline xt::xtensor FineLayer::nodesRightFace() const +inline xt::xtensor FineLayer::nodesRightFace() const { // number of element layers in y-direction size_t nely = static_cast(m_nhy.size()); // number of boundary nodes // - initialize size_t n = 0; // - bottom half: bottom node layer (+ middle node layer) for (size_t iy = 1; iy < (nely + 1) / 2; ++iy) { if (m_refine(iy) == 2) { n += m_nelz(iy) * 3 - 1; } else { n += m_nelz(iy) - 1; } } // - top half: (middle node layer +) top node layer for (size_t iy = (nely - 1) / 2; iy < nely - 1; ++iy) { if (m_refine(iy) == 2) { n += m_nelz(iy) * 3 - 1; } else { n += m_nelz(iy) - 1; } } // allocate node-list - xt::xtensor out = xt::empty({n}); + xt::xtensor out = xt::empty({n}); // initialize counter: current index in the node-list "out" size_t j = 0; // bottom half: bottom node layer (+ middle node layer) for (size_t iy = 1; iy < (nely + 1) / 2; ++iy) { // -- bottom node layer for (size_t iz = 1; iz < m_nelz(iy); ++iz) { out(j) = m_startNode(iy) + iz * (m_nelx(iy) + 1) + m_nelx(iy); ++j; } // -- refinement layer if (m_refine(iy) == 2) { for (size_t iz = 0; iz < 2 * m_nelz(iy); ++iz) { out(j) = m_startNode(iy) + m_nnd(iy) + iz * (m_nelx(iy) + 1) + m_nelx(iy); ++j; } } } // top half: (middle node layer +) top node layer for (size_t iy = (nely - 1) / 2; iy < nely - 1; ++iy) { // -- refinement layer if (m_refine(iy) == 2) { for (size_t iz = 0; iz < 2 * m_nelz(iy); ++iz) { out(j) = m_startNode(iy) + m_nnd(iy) + iz * (m_nelx(iy) + 1) + m_nelx(iy); ++j; } } // -- top node layer for (size_t iz = 1; iz < m_nelz(iy); ++iz) { out(j) = m_startNode(iy + 1) + iz * (m_nelx(iy) + 1) + m_nelx(iy); ++j; } } return out; } -inline xt::xtensor FineLayer::nodesBottomFace() const +inline xt::xtensor FineLayer::nodesBottomFace() const { // allocate node list - xt::xtensor out = xt::empty({(m_nelx(0) - 1) * (m_nelz(0) - 1)}); + xt::xtensor out = xt::empty({(m_nelx(0) - 1) * (m_nelz(0) - 1)}); // counter size_t j = 0; // fill node list for (size_t ix = 1; ix < m_nelx(0); ++ix) { for (size_t iz = 1; iz < m_nelz(0); ++iz) { out(j) = m_startNode(0) + ix + iz * (m_nelx(0) + 1); ++j; } } return out; } -inline xt::xtensor FineLayer::nodesTopFace() const +inline xt::xtensor FineLayer::nodesTopFace() const { // number of element layers in y-direction size_t nely = static_cast(m_nhy.size()); // allocate node list - xt::xtensor out = + xt::xtensor out = xt::empty({(m_nelx(nely - 1) - 1) * (m_nelz(nely - 1) - 1)}); // counter size_t j = 0; // fill node list for (size_t ix = 1; ix < m_nelx(nely - 1); ++ix) { for (size_t iz = 1; iz < m_nelz(nely - 1); ++iz) { out(j) = m_startNode(nely) + ix + iz * (m_nelx(nely - 1) + 1); ++j; } } return out; } -inline xt::xtensor FineLayer::nodesFrontBottomEdge() const +inline xt::xtensor FineLayer::nodesFrontBottomEdge() const { - xt::xtensor out = xt::empty({m_nelx(0) + 1}); + xt::xtensor out = xt::empty({m_nelx(0) + 1}); for (size_t ix = 0; ix < m_nelx(0) + 1; ++ix) { out(ix) = m_startNode(0) + ix; } return out; } -inline xt::xtensor FineLayer::nodesFrontTopEdge() const +inline xt::xtensor FineLayer::nodesFrontTopEdge() const { size_t nely = static_cast(m_nhy.size()); - xt::xtensor out = xt::empty({m_nelx(nely - 1) + 1}); + xt::xtensor out = xt::empty({m_nelx(nely - 1) + 1}); for (size_t ix = 0; ix < m_nelx(nely - 1) + 1; ++ix) { out(ix) = m_startNode(nely) + ix; } return out; } -inline xt::xtensor FineLayer::nodesFrontLeftEdge() const +inline xt::xtensor FineLayer::nodesFrontLeftEdge() const { size_t nely = static_cast(m_nhy.size()); - xt::xtensor out = xt::empty({nely + 1}); + xt::xtensor out = xt::empty({nely + 1}); for (size_t iy = 0; iy < (nely + 1) / 2; ++iy) { out(iy) = m_startNode(iy); } for (size_t iy = (nely - 1) / 2; iy < nely; ++iy) { out(iy + 1) = m_startNode(iy + 1); } return out; } -inline xt::xtensor FineLayer::nodesFrontRightEdge() const +inline xt::xtensor FineLayer::nodesFrontRightEdge() const { size_t nely = static_cast(m_nhy.size()); - xt::xtensor out = xt::empty({nely + 1}); + xt::xtensor out = xt::empty({nely + 1}); for (size_t iy = 0; iy < (nely + 1) / 2; ++iy) { out(iy) = m_startNode(iy) + m_nelx(iy); } for (size_t iy = (nely - 1) / 2; iy < nely; ++iy) { out(iy + 1) = m_startNode(iy + 1) + m_nelx(iy); } return out; } -inline xt::xtensor FineLayer::nodesBackBottomEdge() const +inline xt::xtensor FineLayer::nodesBackBottomEdge() const { - xt::xtensor out = xt::empty({m_nelx(0) + 1}); + xt::xtensor out = xt::empty({m_nelx(0) + 1}); for (size_t ix = 0; ix < m_nelx(0) + 1; ++ix) { out(ix) = m_startNode(0) + ix + (m_nelx(0) + 1) * (m_nelz(0)); } return out; } -inline xt::xtensor FineLayer::nodesBackTopEdge() const +inline xt::xtensor FineLayer::nodesBackTopEdge() const { size_t nely = static_cast(m_nhy.size()); - xt::xtensor out = xt::empty({m_nelx(nely - 1) + 1}); + xt::xtensor out = xt::empty({m_nelx(nely - 1) + 1}); for (size_t ix = 0; ix < m_nelx(nely - 1) + 1; ++ix) { out(ix) = m_startNode(nely) + ix + (m_nelx(nely - 1) + 1) * (m_nelz(nely - 1)); } return out; } -inline xt::xtensor FineLayer::nodesBackLeftEdge() const +inline xt::xtensor FineLayer::nodesBackLeftEdge() const { size_t nely = static_cast(m_nhy.size()); - xt::xtensor out = xt::empty({nely + 1}); + xt::xtensor out = xt::empty({nely + 1}); for (size_t iy = 0; iy < (nely + 1) / 2; ++iy) { out(iy) = m_startNode(iy) + (m_nelx(iy) + 1) * (m_nelz(iy)); } for (size_t iy = (nely - 1) / 2; iy < nely; ++iy) { out(iy + 1) = m_startNode(iy + 1) + (m_nelx(iy) + 1) * (m_nelz(iy)); } return out; } -inline xt::xtensor FineLayer::nodesBackRightEdge() const +inline xt::xtensor FineLayer::nodesBackRightEdge() const { size_t nely = static_cast(m_nhy.size()); - xt::xtensor out = xt::empty({nely + 1}); + xt::xtensor out = xt::empty({nely + 1}); for (size_t iy = 0; iy < (nely + 1) / 2; ++iy) { out(iy) = m_startNode(iy) + m_nelx(iy) + (m_nelx(iy) + 1) * (m_nelz(iy)); } for (size_t iy = (nely - 1) / 2; iy < nely; ++iy) { out(iy + 1) = m_startNode(iy + 1) + m_nelx(iy) + (m_nelx(iy) + 1) * (m_nelz(iy)); } return out; } -inline xt::xtensor FineLayer::nodesBottomLeftEdge() const +inline xt::xtensor FineLayer::nodesBottomLeftEdge() const { - xt::xtensor out = xt::empty({m_nelz(0) + 1}); + xt::xtensor out = xt::empty({m_nelz(0) + 1}); for (size_t iz = 0; iz < m_nelz(0) + 1; ++iz) { out(iz) = m_startNode(0) + iz * (m_nelx(0) + 1); } return out; } -inline xt::xtensor FineLayer::nodesBottomRightEdge() const +inline xt::xtensor FineLayer::nodesBottomRightEdge() const { - xt::xtensor out = xt::empty({m_nelz(0) + 1}); + xt::xtensor out = xt::empty({m_nelz(0) + 1}); for (size_t iz = 0; iz < m_nelz(0) + 1; ++iz) { out(iz) = m_startNode(0) + m_nelx(0) + iz * (m_nelx(0) + 1); } return out; } -inline xt::xtensor FineLayer::nodesTopLeftEdge() const +inline xt::xtensor FineLayer::nodesTopLeftEdge() const { size_t nely = static_cast(m_nhy.size()); - xt::xtensor out = xt::empty({m_nelz(nely - 1) + 1}); + xt::xtensor out = xt::empty({m_nelz(nely - 1) + 1}); for (size_t iz = 0; iz < m_nelz(nely - 1) + 1; ++iz) { out(iz) = m_startNode(nely) + iz * (m_nelx(nely - 1) + 1); } return out; } -inline xt::xtensor FineLayer::nodesTopRightEdge() const +inline xt::xtensor FineLayer::nodesTopRightEdge() const { size_t nely = static_cast(m_nhy.size()); - xt::xtensor out = xt::empty({m_nelz(nely - 1) + 1}); + xt::xtensor out = xt::empty({m_nelz(nely - 1) + 1}); for (size_t iz = 0; iz < m_nelz(nely - 1) + 1; ++iz) { out(iz) = m_startNode(nely) + m_nelx(nely - 1) + iz * (m_nelx(nely - 1) + 1); } return out; } -inline xt::xtensor FineLayer::nodesBottomFrontEdge() const +inline xt::xtensor FineLayer::nodesBottomFrontEdge() const { return nodesFrontBottomEdge(); } -inline xt::xtensor FineLayer::nodesBottomBackEdge() const +inline xt::xtensor FineLayer::nodesBottomBackEdge() const { return nodesBackBottomEdge(); } -inline xt::xtensor FineLayer::nodesTopFrontEdge() const +inline xt::xtensor FineLayer::nodesTopFrontEdge() const { return nodesFrontTopEdge(); } -inline xt::xtensor FineLayer::nodesTopBackEdge() const +inline xt::xtensor FineLayer::nodesTopBackEdge() const { return nodesBackTopEdge(); } -inline xt::xtensor FineLayer::nodesLeftBottomEdge() const +inline xt::xtensor FineLayer::nodesLeftBottomEdge() const { return nodesBottomLeftEdge(); } -inline xt::xtensor FineLayer::nodesLeftFrontEdge() const +inline xt::xtensor FineLayer::nodesLeftFrontEdge() const { return nodesFrontLeftEdge(); } -inline xt::xtensor FineLayer::nodesLeftBackEdge() const +inline xt::xtensor FineLayer::nodesLeftBackEdge() const { return nodesBackLeftEdge(); } -inline xt::xtensor FineLayer::nodesLeftTopEdge() const +inline xt::xtensor FineLayer::nodesLeftTopEdge() const { return nodesTopLeftEdge(); } -inline xt::xtensor FineLayer::nodesRightBottomEdge() const +inline xt::xtensor FineLayer::nodesRightBottomEdge() const { return nodesBottomRightEdge(); } -inline xt::xtensor FineLayer::nodesRightTopEdge() const +inline xt::xtensor FineLayer::nodesRightTopEdge() const { return nodesTopRightEdge(); } -inline xt::xtensor FineLayer::nodesRightFrontEdge() const +inline xt::xtensor FineLayer::nodesRightFrontEdge() const { return nodesFrontRightEdge(); } -inline xt::xtensor FineLayer::nodesRightBackEdge() const +inline xt::xtensor FineLayer::nodesRightBackEdge() const { return nodesBackRightEdge(); } -inline xt::xtensor FineLayer::nodesFrontBottomOpenEdge() const +inline xt::xtensor FineLayer::nodesFrontBottomOpenEdge() const { - xt::xtensor out = xt::empty({m_nelx(0) - 1}); + xt::xtensor out = xt::empty({m_nelx(0) - 1}); for (size_t ix = 1; ix < m_nelx(0); ++ix) { out(ix - 1) = m_startNode(0) + ix; } return out; } -inline xt::xtensor FineLayer::nodesFrontTopOpenEdge() const +inline xt::xtensor FineLayer::nodesFrontTopOpenEdge() const { size_t nely = static_cast(m_nhy.size()); - xt::xtensor out = xt::empty({m_nelx(nely - 1) - 1}); + xt::xtensor out = xt::empty({m_nelx(nely - 1) - 1}); for (size_t ix = 1; ix < m_nelx(nely - 1); ++ix) { out(ix - 1) = m_startNode(nely) + ix; } return out; } -inline xt::xtensor FineLayer::nodesFrontLeftOpenEdge() const +inline xt::xtensor FineLayer::nodesFrontLeftOpenEdge() const { size_t nely = static_cast(m_nhy.size()); - xt::xtensor out = xt::empty({nely - 1}); + xt::xtensor out = xt::empty({nely - 1}); for (size_t iy = 1; iy < (nely + 1) / 2; ++iy) { out(iy - 1) = m_startNode(iy); } for (size_t iy = (nely - 1) / 2; iy < nely - 1; ++iy) { out(iy) = m_startNode(iy + 1); } return out; } -inline xt::xtensor FineLayer::nodesFrontRightOpenEdge() const +inline xt::xtensor FineLayer::nodesFrontRightOpenEdge() const { size_t nely = static_cast(m_nhy.size()); - xt::xtensor out = xt::empty({nely - 1}); + xt::xtensor out = xt::empty({nely - 1}); for (size_t iy = 1; iy < (nely + 1) / 2; ++iy) { out(iy - 1) = m_startNode(iy) + m_nelx(iy); } for (size_t iy = (nely - 1) / 2; iy < nely - 1; ++iy) { out(iy) = m_startNode(iy + 1) + m_nelx(iy); } return out; } -inline xt::xtensor FineLayer::nodesBackBottomOpenEdge() const +inline xt::xtensor FineLayer::nodesBackBottomOpenEdge() const { - xt::xtensor out = xt::empty({m_nelx(0) - 1}); + xt::xtensor out = xt::empty({m_nelx(0) - 1}); for (size_t ix = 1; ix < m_nelx(0); ++ix) { out(ix - 1) = m_startNode(0) + ix + (m_nelx(0) + 1) * (m_nelz(0)); } return out; } -inline xt::xtensor FineLayer::nodesBackTopOpenEdge() const +inline xt::xtensor FineLayer::nodesBackTopOpenEdge() const { size_t nely = static_cast(m_nhy.size()); - xt::xtensor out = xt::empty({m_nelx(nely - 1) - 1}); + xt::xtensor out = xt::empty({m_nelx(nely - 1) - 1}); for (size_t ix = 1; ix < m_nelx(nely - 1); ++ix) { out(ix - 1) = m_startNode(nely) + ix + (m_nelx(nely - 1) + 1) * (m_nelz(nely - 1)); } return out; } -inline xt::xtensor FineLayer::nodesBackLeftOpenEdge() const +inline xt::xtensor FineLayer::nodesBackLeftOpenEdge() const { size_t nely = static_cast(m_nhy.size()); - xt::xtensor out = xt::empty({nely - 1}); + xt::xtensor out = xt::empty({nely - 1}); for (size_t iy = 1; iy < (nely + 1) / 2; ++iy) { out(iy - 1) = m_startNode(iy) + (m_nelx(iy) + 1) * (m_nelz(iy)); } for (size_t iy = (nely - 1) / 2; iy < nely - 1; ++iy) { out(iy) = m_startNode(iy + 1) + (m_nelx(iy) + 1) * (m_nelz(iy)); } return out; } -inline xt::xtensor FineLayer::nodesBackRightOpenEdge() const +inline xt::xtensor FineLayer::nodesBackRightOpenEdge() const { size_t nely = static_cast(m_nhy.size()); - xt::xtensor out = xt::empty({nely - 1}); + xt::xtensor out = xt::empty({nely - 1}); for (size_t iy = 1; iy < (nely + 1) / 2; ++iy) { out(iy - 1) = m_startNode(iy) + m_nelx(iy) + (m_nelx(iy) + 1) * (m_nelz(iy)); } for (size_t iy = (nely - 1) / 2; iy < nely - 1; ++iy) { out(iy) = m_startNode(iy + 1) + m_nelx(iy) + (m_nelx(iy) + 1) * (m_nelz(iy)); } return out; } -inline xt::xtensor FineLayer::nodesBottomLeftOpenEdge() const +inline xt::xtensor FineLayer::nodesBottomLeftOpenEdge() const { - xt::xtensor out = xt::empty({m_nelz(0) - 1}); + xt::xtensor out = xt::empty({m_nelz(0) - 1}); for (size_t iz = 1; iz < m_nelz(0); ++iz) { out(iz - 1) = m_startNode(0) + iz * (m_nelx(0) + 1); } return out; } -inline xt::xtensor FineLayer::nodesBottomRightOpenEdge() const +inline xt::xtensor FineLayer::nodesBottomRightOpenEdge() const { - xt::xtensor out = xt::empty({m_nelz(0) - 1}); + xt::xtensor out = xt::empty({m_nelz(0) - 1}); for (size_t iz = 1; iz < m_nelz(0); ++iz) { out(iz - 1) = m_startNode(0) + m_nelx(0) + iz * (m_nelx(0) + 1); } return out; } -inline xt::xtensor FineLayer::nodesTopLeftOpenEdge() const +inline xt::xtensor FineLayer::nodesTopLeftOpenEdge() const { size_t nely = static_cast(m_nhy.size()); - xt::xtensor out = xt::empty({m_nelz(nely - 1) - 1}); + xt::xtensor out = xt::empty({m_nelz(nely - 1) - 1}); for (size_t iz = 1; iz < m_nelz(nely - 1); ++iz) { out(iz - 1) = m_startNode(nely) + iz * (m_nelx(nely - 1) + 1); } return out; } -inline xt::xtensor FineLayer::nodesTopRightOpenEdge() const +inline xt::xtensor FineLayer::nodesTopRightOpenEdge() const { size_t nely = static_cast(m_nhy.size()); - xt::xtensor out = xt::empty({m_nelz(nely - 1) - 1}); + xt::xtensor out = xt::empty({m_nelz(nely - 1) - 1}); for (size_t iz = 1; iz < m_nelz(nely - 1); ++iz) { out(iz - 1) = m_startNode(nely) + m_nelx(nely - 1) + iz * (m_nelx(nely - 1) + 1); } return out; } -inline xt::xtensor FineLayer::nodesBottomFrontOpenEdge() const +inline xt::xtensor FineLayer::nodesBottomFrontOpenEdge() const { return nodesFrontBottomOpenEdge(); } -inline xt::xtensor FineLayer::nodesBottomBackOpenEdge() const +inline xt::xtensor FineLayer::nodesBottomBackOpenEdge() const { return nodesBackBottomOpenEdge(); } -inline xt::xtensor FineLayer::nodesTopFrontOpenEdge() const +inline xt::xtensor FineLayer::nodesTopFrontOpenEdge() const { return nodesFrontTopOpenEdge(); } -inline xt::xtensor FineLayer::nodesTopBackOpenEdge() const +inline xt::xtensor FineLayer::nodesTopBackOpenEdge() const { return nodesBackTopOpenEdge(); } -inline xt::xtensor FineLayer::nodesLeftBottomOpenEdge() const +inline xt::xtensor FineLayer::nodesLeftBottomOpenEdge() const { return nodesBottomLeftOpenEdge(); } -inline xt::xtensor FineLayer::nodesLeftFrontOpenEdge() const +inline xt::xtensor FineLayer::nodesLeftFrontOpenEdge() const { return nodesFrontLeftOpenEdge(); } -inline xt::xtensor FineLayer::nodesLeftBackOpenEdge() const +inline xt::xtensor FineLayer::nodesLeftBackOpenEdge() const { return nodesBackLeftOpenEdge(); } -inline xt::xtensor FineLayer::nodesLeftTopOpenEdge() const +inline xt::xtensor FineLayer::nodesLeftTopOpenEdge() const { return nodesTopLeftOpenEdge(); } -inline xt::xtensor FineLayer::nodesRightBottomOpenEdge() const +inline xt::xtensor FineLayer::nodesRightBottomOpenEdge() const { return nodesBottomRightOpenEdge(); } -inline xt::xtensor FineLayer::nodesRightTopOpenEdge() const +inline xt::xtensor FineLayer::nodesRightTopOpenEdge() const { return nodesTopRightOpenEdge(); } -inline xt::xtensor FineLayer::nodesRightFrontOpenEdge() const +inline xt::xtensor FineLayer::nodesRightFrontOpenEdge() const { return nodesFrontRightOpenEdge(); } -inline xt::xtensor FineLayer::nodesRightBackOpenEdge() const +inline xt::xtensor FineLayer::nodesRightBackOpenEdge() const { return nodesBackRightOpenEdge(); } inline size_t FineLayer::nodesFrontBottomLeftCorner() const { return m_startNode(0); } inline size_t FineLayer::nodesFrontBottomRightCorner() const { return m_startNode(0) + m_nelx(0); } inline size_t FineLayer::nodesFrontTopLeftCorner() const { size_t nely = static_cast(m_nhy.size()); return m_startNode(nely); } inline size_t FineLayer::nodesFrontTopRightCorner() const { size_t nely = static_cast(m_nhy.size()); return m_startNode(nely) + m_nelx(nely - 1); } inline size_t FineLayer::nodesBackBottomLeftCorner() const { return m_startNode(0) + (m_nelx(0) + 1) * (m_nelz(0)); } inline size_t FineLayer::nodesBackBottomRightCorner() const { return m_startNode(0) + m_nelx(0) + (m_nelx(0) + 1) * (m_nelz(0)); } inline size_t FineLayer::nodesBackTopLeftCorner() const { size_t nely = static_cast(m_nhy.size()); return m_startNode(nely) + (m_nelx(nely - 1) + 1) * (m_nelz(nely - 1)); } inline size_t FineLayer::nodesBackTopRightCorner() const { size_t nely = static_cast(m_nhy.size()); return m_startNode(nely) + m_nelx(nely - 1) + (m_nelx(nely - 1) + 1) * (m_nelz(nely - 1)); } inline size_t FineLayer::nodesFrontLeftBottomCorner() const { return nodesFrontBottomLeftCorner(); } inline size_t FineLayer::nodesBottomFrontLeftCorner() const { return nodesFrontBottomLeftCorner(); } inline size_t FineLayer::nodesBottomLeftFrontCorner() const { return nodesFrontBottomLeftCorner(); } inline size_t FineLayer::nodesLeftFrontBottomCorner() const { return nodesFrontBottomLeftCorner(); } inline size_t FineLayer::nodesLeftBottomFrontCorner() const { return nodesFrontBottomLeftCorner(); } inline size_t FineLayer::nodesFrontRightBottomCorner() const { return nodesFrontBottomRightCorner(); } inline size_t FineLayer::nodesBottomFrontRightCorner() const { return nodesFrontBottomRightCorner(); } inline size_t FineLayer::nodesBottomRightFrontCorner() const { return nodesFrontBottomRightCorner(); } inline size_t FineLayer::nodesRightFrontBottomCorner() const { return nodesFrontBottomRightCorner(); } inline size_t FineLayer::nodesRightBottomFrontCorner() const { return nodesFrontBottomRightCorner(); } inline size_t FineLayer::nodesFrontLeftTopCorner() const { return nodesFrontTopLeftCorner(); } inline size_t FineLayer::nodesTopFrontLeftCorner() const { return nodesFrontTopLeftCorner(); } inline size_t FineLayer::nodesTopLeftFrontCorner() const { return nodesFrontTopLeftCorner(); } inline size_t FineLayer::nodesLeftFrontTopCorner() const { return nodesFrontTopLeftCorner(); } inline size_t FineLayer::nodesLeftTopFrontCorner() const { return nodesFrontTopLeftCorner(); } inline size_t FineLayer::nodesFrontRightTopCorner() const { return nodesFrontTopRightCorner(); } inline size_t FineLayer::nodesTopFrontRightCorner() const { return nodesFrontTopRightCorner(); } inline size_t FineLayer::nodesTopRightFrontCorner() const { return nodesFrontTopRightCorner(); } inline size_t FineLayer::nodesRightFrontTopCorner() const { return nodesFrontTopRightCorner(); } inline size_t FineLayer::nodesRightTopFrontCorner() const { return nodesFrontTopRightCorner(); } inline size_t FineLayer::nodesBackLeftBottomCorner() const { return nodesBackBottomLeftCorner(); } inline size_t FineLayer::nodesBottomBackLeftCorner() const { return nodesBackBottomLeftCorner(); } inline size_t FineLayer::nodesBottomLeftBackCorner() const { return nodesBackBottomLeftCorner(); } inline size_t FineLayer::nodesLeftBackBottomCorner() const { return nodesBackBottomLeftCorner(); } inline size_t FineLayer::nodesLeftBottomBackCorner() const { return nodesBackBottomLeftCorner(); } inline size_t FineLayer::nodesBackRightBottomCorner() const { return nodesBackBottomRightCorner(); } inline size_t FineLayer::nodesBottomBackRightCorner() const { return nodesBackBottomRightCorner(); } inline size_t FineLayer::nodesBottomRightBackCorner() const { return nodesBackBottomRightCorner(); } inline size_t FineLayer::nodesRightBackBottomCorner() const { return nodesBackBottomRightCorner(); } inline size_t FineLayer::nodesRightBottomBackCorner() const { return nodesBackBottomRightCorner(); } inline size_t FineLayer::nodesBackLeftTopCorner() const { return nodesBackTopLeftCorner(); } inline size_t FineLayer::nodesTopBackLeftCorner() const { return nodesBackTopLeftCorner(); } inline size_t FineLayer::nodesTopLeftBackCorner() const { return nodesBackTopLeftCorner(); } inline size_t FineLayer::nodesLeftBackTopCorner() const { return nodesBackTopLeftCorner(); } inline size_t FineLayer::nodesLeftTopBackCorner() const { return nodesBackTopLeftCorner(); } inline size_t FineLayer::nodesBackRightTopCorner() const { return nodesBackTopRightCorner(); } inline size_t FineLayer::nodesTopBackRightCorner() const { return nodesBackTopRightCorner(); } inline size_t FineLayer::nodesTopRightBackCorner() const { return nodesBackTopRightCorner(); } inline size_t FineLayer::nodesRightBackTopCorner() const { return nodesBackTopRightCorner(); } inline size_t FineLayer::nodesRightTopBackCorner() const { return nodesBackTopRightCorner(); } -inline xt::xtensor FineLayer::nodesPeriodic() const -{ - xt::xtensor fro = nodesFrontFace(); - xt::xtensor bck = nodesBackFace(); - xt::xtensor lft = nodesLeftFace(); - xt::xtensor rgt = nodesRightFace(); - xt::xtensor bot = nodesBottomFace(); - xt::xtensor top = nodesTopFace(); - - xt::xtensor froBot = nodesFrontBottomOpenEdge(); - xt::xtensor froTop = nodesFrontTopOpenEdge(); - xt::xtensor froLft = nodesFrontLeftOpenEdge(); - xt::xtensor froRgt = nodesFrontRightOpenEdge(); - xt::xtensor bckBot = nodesBackBottomOpenEdge(); - xt::xtensor bckTop = nodesBackTopOpenEdge(); - xt::xtensor bckLft = nodesBackLeftOpenEdge(); - xt::xtensor bckRgt = nodesBackRightOpenEdge(); - xt::xtensor botLft = nodesBottomLeftOpenEdge(); - xt::xtensor botRgt = nodesBottomRightOpenEdge(); - xt::xtensor topLft = nodesTopLeftOpenEdge(); - xt::xtensor topRgt = nodesTopRightOpenEdge(); +inline xt::xtensor FineLayer::nodesPeriodic() const +{ + xt::xtensor fro = nodesFrontFace(); + xt::xtensor bck = nodesBackFace(); + xt::xtensor lft = nodesLeftFace(); + xt::xtensor rgt = nodesRightFace(); + xt::xtensor bot = nodesBottomFace(); + xt::xtensor top = nodesTopFace(); + + xt::xtensor froBot = nodesFrontBottomOpenEdge(); + xt::xtensor froTop = nodesFrontTopOpenEdge(); + xt::xtensor froLft = nodesFrontLeftOpenEdge(); + xt::xtensor froRgt = nodesFrontRightOpenEdge(); + xt::xtensor bckBot = nodesBackBottomOpenEdge(); + xt::xtensor bckTop = nodesBackTopOpenEdge(); + xt::xtensor bckLft = nodesBackLeftOpenEdge(); + xt::xtensor bckRgt = nodesBackRightOpenEdge(); + xt::xtensor botLft = nodesBottomLeftOpenEdge(); + xt::xtensor botRgt = nodesBottomRightOpenEdge(); + xt::xtensor topLft = nodesTopLeftOpenEdge(); + xt::xtensor topRgt = nodesTopRightOpenEdge(); size_t tface = fro.size() + lft.size() + bot.size(); size_t tedge = 3 * froBot.size() + 3 * froLft.size() + 3 * botLft.size(); size_t tnode = 7; - xt::xtensor out = xt::empty({tface + tedge + tnode, std::size_t(2)}); + xt::xtensor out = xt::empty({tface + tedge + tnode, std::size_t(2)}); size_t i = 0; out(i, 0) = nodesFrontBottomLeftCorner(); out(i, 1) = nodesFrontBottomRightCorner(); ++i; out(i, 0) = nodesFrontBottomLeftCorner(); out(i, 1) = nodesBackBottomRightCorner(); ++i; out(i, 0) = nodesFrontBottomLeftCorner(); out(i, 1) = nodesBackBottomLeftCorner(); ++i; out(i, 0) = nodesFrontBottomLeftCorner(); out(i, 1) = nodesFrontTopLeftCorner(); ++i; out(i, 0) = nodesFrontBottomLeftCorner(); out(i, 1) = nodesFrontTopRightCorner(); ++i; out(i, 0) = nodesFrontBottomLeftCorner(); out(i, 1) = nodesBackTopRightCorner(); ++i; out(i, 0) = nodesFrontBottomLeftCorner(); out(i, 1) = nodesBackTopLeftCorner(); ++i; for (size_t j = 0; j < froBot.size(); ++j) { out(i, 0) = froBot(j); out(i, 1) = bckBot(j); ++i; } for (size_t j = 0; j < froBot.size(); ++j) { out(i, 0) = froBot(j); out(i, 1) = bckTop(j); ++i; } for (size_t j = 0; j < froBot.size(); ++j) { out(i, 0) = froBot(j); out(i, 1) = froTop(j); ++i; } for (size_t j = 0; j < botLft.size(); ++j) { out(i, 0) = botLft(j); out(i, 1) = botRgt(j); ++i; } for (size_t j = 0; j < botLft.size(); ++j) { out(i, 0) = botLft(j); out(i, 1) = topRgt(j); ++i; } for (size_t j = 0; j < botLft.size(); ++j) { out(i, 0) = botLft(j); out(i, 1) = topLft(j); ++i; } for (size_t j = 0; j < froLft.size(); ++j) { out(i, 0) = froLft(j); out(i, 1) = froRgt(j); ++i; } for (size_t j = 0; j < froLft.size(); ++j) { out(i, 0) = froLft(j); out(i, 1) = bckRgt(j); ++i; } for (size_t j = 0; j < froLft.size(); ++j) { out(i, 0) = froLft(j); out(i, 1) = bckLft(j); ++i; } for (size_t j = 0; j < fro.size(); ++j) { out(i, 0) = fro(j); out(i, 1) = bck(j); ++i; } for (size_t j = 0; j < lft.size(); ++j) { out(i, 0) = lft(j); out(i, 1) = rgt(j); ++i; } for (size_t j = 0; j < bot.size(); ++j) { out(i, 0) = bot(j); out(i, 1) = top(j); ++i; } return out; } inline size_t FineLayer::nodesOrigin() const { return nodesFrontBottomLeftCorner(); } -inline xt::xtensor FineLayer::dofs() const +inline xt::xtensor FineLayer::dofs() const { return GooseFEM::Mesh::dofs(m_nnode, m_ndim); } -inline xt::xtensor FineLayer::dofsPeriodic() const +inline xt::xtensor FineLayer::dofsPeriodic() const { - xt::xtensor out = GooseFEM::Mesh::dofs(m_nnode, m_ndim); - xt::xtensor nodePer = nodesPeriodic(); + xt::xtensor out = GooseFEM::Mesh::dofs(m_nnode, m_ndim); + xt::xtensor nodePer = nodesPeriodic(); for (size_t i = 0; i < nodePer.shape(0); ++i) { for (size_t j = 0; j < m_ndim; ++j) { out(nodePer(i, 1), j) = out(nodePer(i, 0), j); } } return GooseFEM::Mesh::renumber(out); } } // namespace Hex8 } // namespace Mesh } // namespace GooseFEM #endif diff --git a/include/GooseFEM/MeshQuad4.h b/include/GooseFEM/MeshQuad4.h index 01492b7..1aafc67 100644 --- a/include/GooseFEM/MeshQuad4.h +++ b/include/GooseFEM/MeshQuad4.h @@ -1,265 +1,265 @@ /* (c - GPLv3) T.W.J. de Geus (Tom) | tom@geus.me | www.geus.me | github.com/tdegeus/GooseFEM */ #ifndef GOOSEFEM_MESHQUAD4_H #define GOOSEFEM_MESHQUAD4_H #include "config.h" namespace GooseFEM { namespace Mesh { namespace Quad4 { namespace Map { class FineLayer2Regular; } } // namespace Quad4 } // namespace Mesh } // namespace GooseFEM namespace GooseFEM { namespace Mesh { namespace Quad4 { class Regular { public: Regular() = default; Regular(size_t nelx, size_t nely, double h = 1.0); // size size_t nelem() const; // number of elements size_t nnode() const; // number of nodes size_t nne() const; // number of nodes-per-element size_t ndim() const; // number of dimensions size_t nelx() const; // number of elements in x-direction size_t nely() const; // number of elements in y-direction double h() const; // edge size // type ElementType getElementType() const; // mesh - xt::xtensor coor() const; // nodal positions [nnode, ndim] - xt::xtensor conn() const; // connectivity [nelem, nne] + xt::xtensor coor() const; // nodal positions [nnode, ndim] + xt::xtensor conn() const; // connectivity [nelem, nne] // boundary nodes: edges - xt::xtensor nodesBottomEdge() const; - xt::xtensor nodesTopEdge() const; - xt::xtensor nodesLeftEdge() const; - xt::xtensor nodesRightEdge() const; + xt::xtensor nodesBottomEdge() const; + xt::xtensor nodesTopEdge() const; + xt::xtensor nodesLeftEdge() const; + xt::xtensor nodesRightEdge() const; // boundary nodes: edges, without corners - xt::xtensor nodesBottomOpenEdge() const; - xt::xtensor nodesTopOpenEdge() const; - xt::xtensor nodesLeftOpenEdge() const; - xt::xtensor nodesRightOpenEdge() const; + xt::xtensor nodesBottomOpenEdge() const; + xt::xtensor nodesTopOpenEdge() const; + xt::xtensor nodesLeftOpenEdge() const; + xt::xtensor nodesRightOpenEdge() const; // boundary nodes: corners (including aliases) size_t nodesBottomLeftCorner() const; size_t nodesBottomRightCorner() const; size_t nodesTopLeftCorner() const; size_t nodesTopRightCorner() const; size_t nodesLeftBottomCorner() const; size_t nodesLeftTopCorner() const; size_t nodesRightBottomCorner() const; size_t nodesRightTopCorner() const; // DOF-numbers for each component of each node (sequential) - xt::xtensor dofs() const; + xt::xtensor dofs() const; // DOF-numbers for the case that the periodicity if fully eliminated - xt::xtensor dofsPeriodic() const; + xt::xtensor dofsPeriodic() const; // periodic node pairs [:,2]: (independent, dependent) - xt::xtensor nodesPeriodic() const; + xt::xtensor nodesPeriodic() const; // front-bottom-left node, used as reference for periodicity size_t nodesOrigin() const; // element numbers as matrix - xt::xtensor elementMatrix() const; + xt::xtensor elementMatrix() const; private: double m_h; // elementary element edge-size (in all directions) size_t m_nelx; // number of elements in x-direction (length == "m_nelx * m_h") size_t m_nely; // number of elements in y-direction (length == "m_nely * m_h") size_t m_nelem; // number of elements size_t m_nnode; // number of nodes static const size_t m_nne = 4; // number of nodes-per-element static const size_t m_ndim = 2; // number of dimensions }; } // namespace Quad4 } // namespace Mesh } // namespace GooseFEM namespace GooseFEM { namespace Mesh { namespace Quad4 { class FineLayer { public: FineLayer() = default; FineLayer(size_t nelx, size_t nely, double h = 1.0, size_t nfine = 1); // size size_t nelem() const; // number of elements size_t nnode() const; // number of nodes size_t nne() const; // number of nodes-per-element size_t ndim() const; // number of dimensions size_t nelx() const; // number of elements in x-direction size_t nely() const; // number of elements in y-direction double h() const; // edge size // type ElementType getElementType() const; // mesh - xt::xtensor coor() const; // nodal positions [nnode, ndim] - xt::xtensor conn() const; // connectivity [nelem, nne] + xt::xtensor coor() const; // nodal positions [nnode, ndim] + xt::xtensor conn() const; // connectivity [nelem, nne] // element sets - xt::xtensor elementsMiddleLayer() const; // elements in the middle (fine) layer + xt::xtensor elementsMiddleLayer() const; // elements in the middle (fine) layer // boundary nodes: edges - xt::xtensor nodesBottomEdge() const; - xt::xtensor nodesTopEdge() const; - xt::xtensor nodesLeftEdge() const; - xt::xtensor nodesRightEdge() const; + xt::xtensor nodesBottomEdge() const; + xt::xtensor nodesTopEdge() const; + xt::xtensor nodesLeftEdge() const; + xt::xtensor nodesRightEdge() const; // boundary nodes: edges, without corners - xt::xtensor nodesBottomOpenEdge() const; - xt::xtensor nodesTopOpenEdge() const; - xt::xtensor nodesLeftOpenEdge() const; - xt::xtensor nodesRightOpenEdge() const; + xt::xtensor nodesBottomOpenEdge() const; + xt::xtensor nodesTopOpenEdge() const; + xt::xtensor nodesLeftOpenEdge() const; + xt::xtensor nodesRightOpenEdge() const; // boundary nodes: corners (including aliases) size_t nodesBottomLeftCorner() const; size_t nodesBottomRightCorner() const; size_t nodesTopLeftCorner() const; size_t nodesTopRightCorner() const; size_t nodesLeftBottomCorner() const; size_t nodesLeftTopCorner() const; size_t nodesRightBottomCorner() const; size_t nodesRightTopCorner() const; // DOF-numbers for each component of each node (sequential) - xt::xtensor dofs() const; + xt::xtensor dofs() const; // DOF-numbers for the case that the periodicity if fully eliminated - xt::xtensor dofsPeriodic() const; + xt::xtensor dofsPeriodic() const; // periodic node pairs [:,2]: (independent, dependent) - xt::xtensor nodesPeriodic() const; + xt::xtensor nodesPeriodic() const; // front-bottom-left node, used as reference for periodicity size_t nodesOrigin() const; private: - double m_h; // elementary element edge-size (in all directions) - double m_Lx; // mesh size in "x" - size_t m_nelem; // number of elements - size_t m_nnode; // number of nodes - static const size_t m_nne = 4; // number of nodes-per-element - static const size_t m_ndim = 2; // number of dimensions - xt::xtensor m_nelx; // number of elements in "x" (*) - xt::xtensor m_nnd; // total number of nodes in the main node layer (**) - xt::xtensor m_nhx; // element size in x-direction (*) - xt::xtensor m_nhy; // element size in y-direction (*) - xt::xtensor m_refine; // refine direction (-1:no refine, 0:"x" (*) - xt::xtensor m_startElem; // start element (*) - xt::xtensor m_startNode; // start node (**) + double m_h; // elementary element edge-size (in all directions) + double m_Lx; // mesh size in "x" + size_t m_nelem; // number of elements + size_t m_nnode; // number of nodes + static const size_t m_nne = 4; // number of nodes-per-element + static const size_t m_ndim = 2; // number of dimensions + xt::xtensor m_nelx; // number of elements in "x" (*) + xt::xtensor m_nnd; // total number of nodes in the main node layer (**) + xt::xtensor m_nhx; // element size in x-direction (*) + xt::xtensor m_nhy; // element size in y-direction (*) + xt::xtensor m_refine; // refine direction (-1:no refine, 0:"x" (*) + xt::xtensor m_startElem; // start element (*) + xt::xtensor m_startNode; // start node (**) // (*) per element layer in "y" // (**) per node layer in "y" friend class GooseFEM::Mesh::Quad4::Map::FineLayer2Regular; }; } // namespace Quad4 } // namespace Mesh } // namespace GooseFEM namespace GooseFEM { namespace Mesh { namespace Quad4 { namespace Map { class RefineRegular { public: // constructor RefineRegular() = default; RefineRegular(const GooseFEM::Mesh::Quad4::Regular& mesh, size_t nx, size_t ny); // return the one of the two meshes GooseFEM::Mesh::Quad4::Regular getCoarseMesh() const; GooseFEM::Mesh::Quad4::Regular getFineMesh() const; // elements of the Fine mesh per element of the Coarse mesh - xt::xtensor getMap() const; + xt::xtensor getMap() const; // map field - xt::xtensor mapToCoarse(const xt::xtensor& data) const; // scalar per el - xt::xtensor mapToCoarse(const xt::xtensor& data) const; // scalar per intpnt - xt::xtensor mapToCoarse(const xt::xtensor& data) const; // tensor per intpnt + xt::xtensor mapToCoarse(const xt::xtensor& data) const; // scalar per el + xt::xtensor mapToCoarse(const xt::xtensor& data) const; // scalar per intpnt + xt::xtensor mapToCoarse(const xt::xtensor& data) const; // tensor per intpnt // map field - xt::xtensor mapToFine(const xt::xtensor& data) const; // scalar per el - xt::xtensor mapToFine(const xt::xtensor& data) const; // scalar per intpnt - xt::xtensor mapToFine(const xt::xtensor& data) const; // tensor per intpnt + xt::xtensor mapToFine(const xt::xtensor& data) const; // scalar per el + xt::xtensor mapToFine(const xt::xtensor& data) const; // scalar per intpnt + xt::xtensor mapToFine(const xt::xtensor& data) const; // tensor per intpnt private: // the meshes GooseFEM::Mesh::Quad4::Regular m_coarse; GooseFEM::Mesh::Quad4::Regular m_fine; // mapping - xt::xtensor m_fine2coarse; - xt::xtensor m_fine2coarse_index; - xt::xtensor m_coarse2fine; + xt::xtensor m_fine2coarse; + xt::xtensor m_fine2coarse_index; + xt::xtensor m_coarse2fine; }; } // namespace Map } // namespace Quad4 } // namespace Mesh } // namespace GooseFEM namespace GooseFEM { namespace Mesh { namespace Quad4 { namespace Map { class FineLayer2Regular { public: // constructor FineLayer2Regular() = default; FineLayer2Regular(const GooseFEM::Mesh::Quad4::FineLayer& mesh); // return either of the meshes GooseFEM::Mesh::Quad4::Regular getRegularMesh() const; GooseFEM::Mesh::Quad4::FineLayer getFineLayerMesh() const; // elements of the Regular mesh per element of the FineLayer mesh // and the fraction by which the overlap is std::vector> getMap() const; std::vector> getMapFraction() const; // map field - xt::xtensor mapToRegular(const xt::xtensor& data) const; // scalar per el - xt::xtensor mapToRegular(const xt::xtensor& data) const; // scalar per intpnt - xt::xtensor mapToRegular(const xt::xtensor& data) const; // tensor per intpnt + xt::xtensor mapToRegular(const xt::xtensor& data) const; // scalar per el + xt::xtensor mapToRegular(const xt::xtensor& data) const; // scalar per intpnt + xt::xtensor mapToRegular(const xt::xtensor& data) const; // tensor per intpnt private: // the "FineLayer" mesh to map GooseFEM::Mesh::Quad4::FineLayer m_finelayer; // the new "Regular" mesh to which to map GooseFEM::Mesh::Quad4::Regular m_regular; // mapping std::vector> m_elem_regular; std::vector> m_frac_regular; }; } // namespace Map } // namespace Quad4 } // namespace Mesh } // namespace GooseFEM #include "MeshQuad4.hpp" #endif diff --git a/include/GooseFEM/MeshQuad4.hpp b/include/GooseFEM/MeshQuad4.hpp index bdc19da..3f3d8a7 100644 --- a/include/GooseFEM/MeshQuad4.hpp +++ b/include/GooseFEM/MeshQuad4.hpp @@ -1,1325 +1,1325 @@ /* (c - GPLv3) T.W.J. de Geus (Tom) | tom@geus.me | www.geus.me | github.com/tdegeus/GooseFEM */ #ifndef GOOSEFEM_MESHQUAD4_HPP #define GOOSEFEM_MESHQUAD4_HPP #include "MeshQuad4.h" namespace GooseFEM { namespace Mesh { namespace Quad4 { inline Regular::Regular(size_t nelx, size_t nely, double h) : m_h(h), m_nelx(nelx), m_nely(nely) { GOOSEFEM_ASSERT(m_nelx >= 1ul); GOOSEFEM_ASSERT(m_nely >= 1ul); m_nnode = (m_nelx + 1) * (m_nely + 1); m_nelem = m_nelx * m_nely; } inline size_t Regular::nelem() const { return m_nelem; } inline size_t Regular::nnode() const { return m_nnode; } inline size_t Regular::nne() const { return m_nne; } inline size_t Regular::ndim() const { return m_ndim; } inline size_t Regular::nelx() const { return m_nelx; } inline size_t Regular::nely() const { return m_nely; } inline double Regular::h() const { return m_h; } inline ElementType Regular::getElementType() const { return ElementType::Quad4; } -inline xt::xtensor Regular::coor() const +inline xt::xtensor Regular::coor() const { - xt::xtensor out = xt::empty({m_nnode, m_ndim}); + xt::xtensor out = xt::empty({m_nnode, m_ndim}); - xt::xtensor x = + xt::xtensor x = xt::linspace(0.0, m_h * static_cast(m_nelx), m_nelx + 1); - xt::xtensor y = + xt::xtensor y = xt::linspace(0.0, m_h * static_cast(m_nely), m_nely + 1); size_t inode = 0; for (size_t iy = 0; iy < m_nely + 1; ++iy) { for (size_t ix = 0; ix < m_nelx + 1; ++ix) { out(inode, 0) = x(ix); out(inode, 1) = y(iy); ++inode; } } return out; } -inline xt::xtensor Regular::conn() const +inline xt::xtensor Regular::conn() const { - xt::xtensor out = xt::empty({m_nelem, m_nne}); + xt::xtensor out = xt::empty({m_nelem, m_nne}); size_t ielem = 0; for (size_t iy = 0; iy < m_nely; ++iy) { for (size_t ix = 0; ix < m_nelx; ++ix) { out(ielem, 0) = (iy) * (m_nelx + 1) + (ix); out(ielem, 1) = (iy) * (m_nelx + 1) + (ix + 1); out(ielem, 3) = (iy + 1) * (m_nelx + 1) + (ix); out(ielem, 2) = (iy + 1) * (m_nelx + 1) + (ix + 1); ++ielem; } } return out; } -inline xt::xtensor Regular::nodesBottomEdge() const +inline xt::xtensor Regular::nodesBottomEdge() const { return xt::arange(m_nelx + 1); } -inline xt::xtensor Regular::nodesTopEdge() const +inline xt::xtensor Regular::nodesTopEdge() const { return xt::arange(m_nelx + 1) + m_nely * (m_nelx + 1); } -inline xt::xtensor Regular::nodesLeftEdge() const +inline xt::xtensor Regular::nodesLeftEdge() const { return xt::arange(m_nely + 1) * (m_nelx + 1); } -inline xt::xtensor Regular::nodesRightEdge() const +inline xt::xtensor Regular::nodesRightEdge() const { return xt::arange(m_nely + 1) * (m_nelx + 1) + m_nelx; } -inline xt::xtensor Regular::nodesBottomOpenEdge() const +inline xt::xtensor Regular::nodesBottomOpenEdge() const { return xt::arange(1, m_nelx); } -inline xt::xtensor Regular::nodesTopOpenEdge() const +inline xt::xtensor Regular::nodesTopOpenEdge() const { return xt::arange(1, m_nelx) + m_nely * (m_nelx + 1); } -inline xt::xtensor Regular::nodesLeftOpenEdge() const +inline xt::xtensor Regular::nodesLeftOpenEdge() const { return xt::arange(1, m_nely) * (m_nelx + 1); } -inline xt::xtensor Regular::nodesRightOpenEdge() const +inline xt::xtensor Regular::nodesRightOpenEdge() const { return xt::arange(1, m_nely) * (m_nelx + 1) + m_nelx; } inline size_t Regular::nodesBottomLeftCorner() const { return 0; } inline size_t Regular::nodesBottomRightCorner() const { return m_nelx; } inline size_t Regular::nodesTopLeftCorner() const { return m_nely * (m_nelx + 1); } inline size_t Regular::nodesTopRightCorner() const { return m_nely * (m_nelx + 1) + m_nelx; } inline size_t Regular::nodesLeftBottomCorner() const { return nodesBottomLeftCorner(); } inline size_t Regular::nodesLeftTopCorner() const { return nodesTopLeftCorner(); } inline size_t Regular::nodesRightBottomCorner() const { return nodesBottomRightCorner(); } inline size_t Regular::nodesRightTopCorner() const { return nodesTopRightCorner(); } -inline xt::xtensor Regular::nodesPeriodic() const +inline xt::xtensor Regular::nodesPeriodic() const { - xt::xtensor bot = nodesBottomOpenEdge(); - xt::xtensor top = nodesTopOpenEdge(); - xt::xtensor lft = nodesLeftOpenEdge(); - xt::xtensor rgt = nodesRightOpenEdge(); + xt::xtensor bot = nodesBottomOpenEdge(); + xt::xtensor top = nodesTopOpenEdge(); + xt::xtensor lft = nodesLeftOpenEdge(); + xt::xtensor rgt = nodesRightOpenEdge(); - xt::xtensor out = xt::empty({bot.size() + lft.size() + 3ul, 2ul}); + xt::xtensor out = xt::empty({bot.size() + lft.size() + 3ul, 2ul}); out(0, 0) = nodesBottomLeftCorner(); out(0, 1) = nodesBottomRightCorner(); out(1, 0) = nodesBottomLeftCorner(); out(1, 1) = nodesTopRightCorner(); out(2, 0) = nodesBottomLeftCorner(); out(2, 1) = nodesTopLeftCorner(); size_t i = 3; xt::view(out, xt::range(i, i + bot.size()), 0) = bot; xt::view(out, xt::range(i, i + bot.size()), 1) = top; i += bot.size(); xt::view(out, xt::range(i, i + lft.size()), 0) = lft; xt::view(out, xt::range(i, i + lft.size()), 1) = rgt; return out; } inline size_t Regular::nodesOrigin() const { return nodesBottomLeftCorner(); } -inline xt::xtensor Regular::dofs() const +inline xt::xtensor Regular::dofs() const { return GooseFEM::Mesh::dofs(m_nnode, m_ndim); } -inline xt::xtensor Regular::dofsPeriodic() const +inline xt::xtensor Regular::dofsPeriodic() const { - xt::xtensor out = GooseFEM::Mesh::dofs(m_nnode, m_ndim); - xt::xtensor nodePer = nodesPeriodic(); - xt::xtensor independent = xt::view(nodePer, xt::all(), 0); - xt::xtensor dependent = xt::view(nodePer, xt::all(), 1); + xt::xtensor out = GooseFEM::Mesh::dofs(m_nnode, m_ndim); + xt::xtensor nodePer = nodesPeriodic(); + xt::xtensor independent = xt::view(nodePer, xt::all(), 0); + xt::xtensor dependent = xt::view(nodePer, xt::all(), 1); for (size_t j = 0; j < m_ndim; ++j) { xt::view(out, xt::keep(dependent), j) = xt::view(out, xt::keep(independent), j); } return GooseFEM::Mesh::renumber(out); } -inline xt::xtensor Regular::elementMatrix() const +inline xt::xtensor Regular::elementMatrix() const { return xt::arange(m_nelem).reshape({m_nely, m_nelx}); } inline FineLayer::FineLayer(size_t nelx, size_t nely, double h, size_t nfine) : m_h(h) { GOOSEFEM_ASSERT(nelx >= 1ul); GOOSEFEM_ASSERT(nely >= 1ul); m_Lx = m_h * static_cast(nelx); // compute element size in y-direction (use symmetry, compute upper half) // temporary variables size_t nmin, ntot; - xt::xtensor nhx = xt::ones({nely}); - xt::xtensor nhy = xt::ones({nely}); - xt::xtensor refine = -1 * xt::ones({nely}); + xt::xtensor nhx = xt::ones({nely}); + xt::xtensor nhy = xt::ones({nely}); + xt::xtensor refine = -1 * xt::ones({nely}); // minimum height in y-direction (half of the height because of symmetry) if (nely % 2 == 0) { nmin = nely / 2; } else { nmin = (nely + 1) / 2; } // minimum number of fine layers in y-direction (minimum 1, middle layer part of this half) if (nfine % 2 == 0) { nfine = nfine / 2 + 1; } else { nfine = (nfine + 1) / 2; } if (nfine < 1) { nfine = 1; } if (nfine > nmin) { nfine = nmin; } // loop over element layers in y-direction, try to coarsen using these rules: // (1) element size in y-direction <= distance to origin in y-direction // (2) element size in x-direction should fit the total number of elements in x-direction // (3) a certain number of layers have the minimum size "1" (are fine) for (size_t iy = nfine;;) { // initialize current size in y-direction if (iy == nfine) { ntot = nfine; } // check to stop if (iy >= nely || ntot >= nmin) { nely = iy; break; } // rules (1,2) satisfied: coarsen in x-direction if (3 * nhy(iy) <= ntot && nelx % (3 * nhx(iy)) == 0 && ntot + nhy(iy) < nmin) { refine(iy) = 0; nhy(iy) *= 2; auto vnhy = xt::view(nhy, xt::range(iy + 1, _)); auto vnhx = xt::view(nhx, xt::range(iy, _)); vnhy *= 3; vnhx *= 3; } // update the number of elements in y-direction ntot += nhy(iy); // proceed to next element layer in y-direction ++iy; // check to stop if (iy >= nely || ntot >= nmin) { nely = iy; break; } } // symmetrize, compute full information // allocate mesh constructor parameters m_nhx = xt::empty({nely * 2 - 1}); m_nhy = xt::empty({nely * 2 - 1}); m_refine = xt::empty({nely * 2 - 1}); m_nelx = xt::empty({nely * 2 - 1}); m_nnd = xt::empty({nely * 2}); m_startElem = xt::empty({nely * 2 - 1}); m_startNode = xt::empty({nely * 2}); // fill // - lower half for (size_t iy = 0; iy < nely; ++iy) { m_nhx(iy) = nhx(nely - iy - 1); m_nhy(iy) = nhy(nely - iy - 1); m_refine(iy) = refine(nely - iy - 1); } // - upper half for (size_t iy = 0; iy < nely - 1; ++iy) { m_nhx(iy + nely) = nhx(iy + 1); m_nhy(iy + nely) = nhy(iy + 1); m_refine(iy + nely) = refine(iy + 1); } // update size nely = m_nhx.size(); // compute the number of elements per element layer in y-direction for (size_t iy = 0; iy < nely; ++iy) { m_nelx(iy) = nelx / m_nhx(iy); } // compute the number of nodes per node layer in y-direction for (size_t iy = 0; iy < (nely + 1) / 2; ++iy) { m_nnd(iy) = m_nelx(iy) + 1; } for (size_t iy = (nely - 1) / 2; iy < nely; ++iy) { m_nnd(iy + 1) = m_nelx(iy) + 1; } // compute mesh dimensions // initialize m_nnode = 0; m_nelem = 0; m_startNode(0) = 0; // loop over element layers (bottom -> middle, elements become finer) for (size_t i = 0; i < (nely - 1) / 2; ++i) { // - store the first element of the layer m_startElem(i) = m_nelem; // - add the nodes of this layer if (m_refine(i) == 0) { m_nnode += (3 * m_nelx(i) + 1); } else { m_nnode += (m_nelx(i) + 1); } // - add the elements of this layer if (m_refine(i) == 0) { m_nelem += (4 * m_nelx(i)); } else { m_nelem += (m_nelx(i)); } // - store the starting node of the next layer m_startNode(i + 1) = m_nnode; } // loop over element layers (middle -> top, elements become coarser) for (size_t i = (nely - 1) / 2; i < nely; ++i) { // - store the first element of the layer m_startElem(i) = m_nelem; // - add the nodes of this layer if (m_refine(i) == 0) { m_nnode += (5 * m_nelx(i) + 1); } else { m_nnode += (m_nelx(i) + 1); } // - add the elements of this layer if (m_refine(i) == 0) { m_nelem += (4 * m_nelx(i)); } else { m_nelem += (m_nelx(i)); } // - store the starting node of the next layer m_startNode(i + 1) = m_nnode; } // - add the top row of nodes m_nnode += m_nelx(nely - 1) + 1; } inline size_t FineLayer::nelem() const { return m_nelem; } inline size_t FineLayer::nnode() const { return m_nnode; } inline size_t FineLayer::nne() const { return m_nne; } inline size_t FineLayer::ndim() const { return m_ndim; } inline size_t FineLayer::nelx() const { return xt::amax(m_nelx)[0]; } inline size_t FineLayer::nely() const { return xt::sum(m_nhy)[0]; } inline double FineLayer::h() const { return m_h; } inline ElementType FineLayer::getElementType() const { return ElementType::Quad4; } -inline xt::xtensor FineLayer::coor() const +inline xt::xtensor FineLayer::coor() const { // allocate output - xt::xtensor out = xt::empty({m_nnode, m_ndim}); + xt::xtensor out = xt::empty({m_nnode, m_ndim}); // current node, number of element layers size_t inode = 0; size_t nely = static_cast(m_nhy.size()); // y-position of each main node layer (i.e. excluding node layers for refinement/coarsening) // - allocate - xt::xtensor y = xt::empty({nely + 1}); + xt::xtensor y = xt::empty({nely + 1}); // - initialize y(0) = 0.0; // - compute for (size_t iy = 1; iy < nely + 1; ++iy) { y(iy) = y(iy - 1) + m_nhy(iy - 1) * m_h; } // loop over element layers (bottom -> middle) : add bottom layer (+ refinement layer) of nodes for (size_t iy = 0;; ++iy) { // get positions along the x- and z-axis - xt::xtensor x = xt::linspace(0.0, m_Lx, m_nelx(iy) + 1); + xt::xtensor x = xt::linspace(0.0, m_Lx, m_nelx(iy) + 1); // add nodes of the bottom layer of this element for (size_t ix = 0; ix < m_nelx(iy) + 1; ++ix) { out(inode, 0) = x(ix); out(inode, 1) = y(iy); ++inode; } // stop at middle layer if (iy == (nely - 1) / 2) { break; } // add extra nodes of the intermediate layer, for refinement in x-direction if (m_refine(iy) == 0) { // - get position offset in x- and y-direction double dx = m_h * static_cast(m_nhx(iy) / 3); double dy = m_h * static_cast(m_nhy(iy) / 2); // - add nodes of the intermediate layer for (size_t ix = 0; ix < m_nelx(iy); ++ix) { for (size_t j = 0; j < 2; ++j) { out(inode, 0) = x(ix) + dx * static_cast(j + 1); out(inode, 1) = y(iy) + dy; ++inode; } } } } // loop over element layers (middle -> top) : add (refinement layer +) top layer of nodes for (size_t iy = (nely - 1) / 2; iy < nely; ++iy) { // get positions along the x- and z-axis - xt::xtensor x = xt::linspace(0.0, m_Lx, m_nelx(iy) + 1); + xt::xtensor x = xt::linspace(0.0, m_Lx, m_nelx(iy) + 1); // add extra nodes of the intermediate layer, for refinement in x-direction if (m_refine(iy) == 0) { // - get position offset in x- and y-direction double dx = m_h * static_cast(m_nhx(iy) / 3); double dy = m_h * static_cast(m_nhy(iy) / 2); // - add nodes of the intermediate layer for (size_t ix = 0; ix < m_nelx(iy); ++ix) { for (size_t j = 0; j < 2; ++j) { out(inode, 0) = x(ix) + dx * static_cast(j + 1); out(inode, 1) = y(iy) + dy; ++inode; } } } // add nodes of the top layer of this element for (size_t ix = 0; ix < m_nelx(iy) + 1; ++ix) { out(inode, 0) = x(ix); out(inode, 1) = y(iy + 1); ++inode; } } return out; } -inline xt::xtensor FineLayer::conn() const +inline xt::xtensor FineLayer::conn() const { // allocate output - xt::xtensor out = xt::empty({m_nelem, m_nne}); + xt::xtensor out = xt::empty({m_nelem, m_nne}); // current element, number of element layers, starting nodes of each node layer size_t ielem = 0; size_t nely = static_cast(m_nhy.size()); size_t bot, mid, top; // loop over all element layers for (size_t iy = 0; iy < nely; ++iy) { // - get: starting nodes of bottom(, middle) and top layer bot = m_startNode(iy); mid = m_startNode(iy) + m_nnd(iy); top = m_startNode(iy + 1); // - define connectivity: no coarsening/refinement if (m_refine(iy) == -1) { for (size_t ix = 0; ix < m_nelx(iy); ++ix) { out(ielem, 0) = bot + (ix); out(ielem, 1) = bot + (ix + 1); out(ielem, 2) = top + (ix + 1); out(ielem, 3) = top + (ix); ielem++; } } // - define connectivity: refinement along the x-direction (below the middle layer) else if (m_refine(iy) == 0 && iy <= (nely - 1) / 2) { for (size_t ix = 0; ix < m_nelx(iy); ++ix) { // -- bottom element out(ielem, 0) = bot + (ix); out(ielem, 1) = bot + (ix + 1); out(ielem, 2) = mid + (2 * ix + 1); out(ielem, 3) = mid + (2 * ix); ielem++; // -- top-right element out(ielem, 0) = bot + (ix + 1); out(ielem, 1) = top + (3 * ix + 3); out(ielem, 2) = top + (3 * ix + 2); out(ielem, 3) = mid + (2 * ix + 1); ielem++; // -- top-center element out(ielem, 0) = mid + (2 * ix); out(ielem, 1) = mid + (2 * ix + 1); out(ielem, 2) = top + (3 * ix + 2); out(ielem, 3) = top + (3 * ix + 1); ielem++; // -- top-left element out(ielem, 0) = bot + (ix); out(ielem, 1) = mid + (2 * ix); out(ielem, 2) = top + (3 * ix + 1); out(ielem, 3) = top + (3 * ix); ielem++; } } // - define connectivity: coarsening along the x-direction (above the middle layer) else if (m_refine(iy) == 0 && iy > (nely - 1) / 2) { for (size_t ix = 0; ix < m_nelx(iy); ++ix) { // -- lower-left element out(ielem, 0) = bot + (3 * ix); out(ielem, 1) = bot + (3 * ix + 1); out(ielem, 2) = mid + (2 * ix); out(ielem, 3) = top + (ix); ielem++; // -- lower-center element out(ielem, 0) = bot + (3 * ix + 1); out(ielem, 1) = bot + (3 * ix + 2); out(ielem, 2) = mid + (2 * ix + 1); out(ielem, 3) = mid + (2 * ix); ielem++; // -- lower-right element out(ielem, 0) = bot + (3 * ix + 2); out(ielem, 1) = bot + (3 * ix + 3); out(ielem, 2) = top + (ix + 1); out(ielem, 3) = mid + (2 * ix + 1); ielem++; // -- upper element out(ielem, 0) = mid + (2 * ix); out(ielem, 1) = mid + (2 * ix + 1); out(ielem, 2) = top + (ix + 1); out(ielem, 3) = top + (ix); ielem++; } } } return out; } -inline xt::xtensor FineLayer::elementsMiddleLayer() const +inline xt::xtensor FineLayer::elementsMiddleLayer() const { size_t nely = m_nhy.size(); size_t iy = (nely - 1) / 2; return m_startElem(iy) + xt::arange(m_nelx(iy)); } -inline xt::xtensor FineLayer::nodesBottomEdge() const +inline xt::xtensor FineLayer::nodesBottomEdge() const { return m_startNode(0) + xt::arange(m_nelx(0) + 1); } -inline xt::xtensor FineLayer::nodesTopEdge() const +inline xt::xtensor FineLayer::nodesTopEdge() const { size_t nely = m_nhy.size(); return m_startNode(nely) + xt::arange(m_nelx(nely - 1) + 1); } -inline xt::xtensor FineLayer::nodesLeftEdge() const +inline xt::xtensor FineLayer::nodesLeftEdge() const { size_t nely = m_nhy.size(); - xt::xtensor out = xt::empty({nely + 1}); + xt::xtensor out = xt::empty({nely + 1}); size_t i = 0; size_t j = (nely + 1) / 2; size_t k = (nely - 1) / 2; size_t l = nely; xt::view(out, xt::range(i, j)) = xt::view(m_startNode, xt::range(i, j)); xt::view(out, xt::range(k + 1, l + 1)) = xt::view(m_startNode, xt::range(k + 1, l + 1)); return out; } -inline xt::xtensor FineLayer::nodesRightEdge() const +inline xt::xtensor FineLayer::nodesRightEdge() const { size_t nely = m_nhy.size(); - xt::xtensor out = xt::empty({nely + 1}); + xt::xtensor out = xt::empty({nely + 1}); size_t i = 0; size_t j = (nely + 1) / 2; size_t k = (nely - 1) / 2; size_t l = nely; xt::view(out, xt::range(i, j)) = xt::view(m_startNode, xt::range(i, j)) + xt::view(m_nelx, xt::range(i, j)); xt::view(out, xt::range(k + 1, l + 1)) = xt::view(m_startNode, xt::range(k + 1, l + 1)) + xt::view(m_nelx, xt::range(k, l)); return out; } -inline xt::xtensor FineLayer::nodesBottomOpenEdge() const +inline xt::xtensor FineLayer::nodesBottomOpenEdge() const { return m_startNode(0) + xt::arange(1, m_nelx(0)); } -inline xt::xtensor FineLayer::nodesTopOpenEdge() const +inline xt::xtensor FineLayer::nodesTopOpenEdge() const { size_t nely = m_nhy.size(); return m_startNode(nely) + xt::arange(1, m_nelx(nely - 1)); } -inline xt::xtensor FineLayer::nodesLeftOpenEdge() const +inline xt::xtensor FineLayer::nodesLeftOpenEdge() const { size_t nely = m_nhy.size(); - xt::xtensor out = xt::empty({nely - 1}); + xt::xtensor out = xt::empty({nely - 1}); size_t i = 0; size_t j = (nely + 1) / 2; size_t k = (nely - 1) / 2; size_t l = nely; xt::view(out, xt::range(i, j - 1)) = xt::view(m_startNode, xt::range(i + 1, j)); xt::view(out, xt::range(k, l - 1)) = xt::view(m_startNode, xt::range(k + 1, l)); return out; } -inline xt::xtensor FineLayer::nodesRightOpenEdge() const +inline xt::xtensor FineLayer::nodesRightOpenEdge() const { size_t nely = m_nhy.size(); - xt::xtensor out = xt::empty({nely - 1}); + xt::xtensor out = xt::empty({nely - 1}); size_t i = 0; size_t j = (nely + 1) / 2; size_t k = (nely - 1) / 2; size_t l = nely; xt::view(out, xt::range(i, j - 1)) = xt::view(m_startNode, xt::range(i + 1, j)) + xt::view(m_nelx, xt::range(i + 1, j)); xt::view(out, xt::range(k, l - 1)) = xt::view(m_startNode, xt::range(k + 1, l)) + xt::view(m_nelx, xt::range(k, l - 1)); return out; } inline size_t FineLayer::nodesBottomLeftCorner() const { return m_startNode(0); } inline size_t FineLayer::nodesBottomRightCorner() const { return m_startNode(0) + m_nelx(0); } inline size_t FineLayer::nodesTopLeftCorner() const { size_t nely = m_nhy.size(); return m_startNode(nely); } inline size_t FineLayer::nodesTopRightCorner() const { size_t nely = m_nhy.size(); return m_startNode(nely) + m_nelx(nely - 1); } inline size_t FineLayer::nodesLeftBottomCorner() const { return nodesBottomLeftCorner(); } inline size_t FineLayer::nodesRightBottomCorner() const { return nodesBottomRightCorner(); } inline size_t FineLayer::nodesLeftTopCorner() const { return nodesTopLeftCorner(); } inline size_t FineLayer::nodesRightTopCorner() const { return nodesTopRightCorner(); } -inline xt::xtensor FineLayer::nodesPeriodic() const +inline xt::xtensor FineLayer::nodesPeriodic() const { - xt::xtensor bot = nodesBottomOpenEdge(); - xt::xtensor top = nodesTopOpenEdge(); - xt::xtensor lft = nodesLeftOpenEdge(); - xt::xtensor rgt = nodesRightOpenEdge(); + xt::xtensor bot = nodesBottomOpenEdge(); + xt::xtensor top = nodesTopOpenEdge(); + xt::xtensor lft = nodesLeftOpenEdge(); + xt::xtensor rgt = nodesRightOpenEdge(); - xt::xtensor out = xt::empty({bot.size() + lft.size() + 3ul, 2ul}); + xt::xtensor out = xt::empty({bot.size() + lft.size() + 3ul, 2ul}); out(0, 0) = nodesBottomLeftCorner(); out(0, 1) = nodesBottomRightCorner(); out(1, 0) = nodesBottomLeftCorner(); out(1, 1) = nodesTopRightCorner(); out(2, 0) = nodesBottomLeftCorner(); out(2, 1) = nodesTopLeftCorner(); size_t i = 3; xt::view(out, xt::range(i, i + bot.size()), 0) = bot; xt::view(out, xt::range(i, i + bot.size()), 1) = top; i += bot.size(); xt::view(out, xt::range(i, i + lft.size()), 0) = lft; xt::view(out, xt::range(i, i + lft.size()), 1) = rgt; return out; } inline size_t FineLayer::nodesOrigin() const { return nodesBottomLeftCorner(); } -inline xt::xtensor FineLayer::dofs() const +inline xt::xtensor FineLayer::dofs() const { return GooseFEM::Mesh::dofs(m_nnode, m_ndim); } -inline xt::xtensor FineLayer::dofsPeriodic() const +inline xt::xtensor FineLayer::dofsPeriodic() const { - xt::xtensor out = GooseFEM::Mesh::dofs(m_nnode, m_ndim); - xt::xtensor nodePer = nodesPeriodic(); - xt::xtensor independent = xt::view(nodePer, xt::all(), 0); - xt::xtensor dependent = xt::view(nodePer, xt::all(), 1); + xt::xtensor out = GooseFEM::Mesh::dofs(m_nnode, m_ndim); + xt::xtensor nodePer = nodesPeriodic(); + xt::xtensor independent = xt::view(nodePer, xt::all(), 0); + xt::xtensor dependent = xt::view(nodePer, xt::all(), 1); for (size_t j = 0; j < m_ndim; ++j) { xt::view(out, xt::keep(dependent), j) = xt::view(out, xt::keep(independent), j); } return GooseFEM::Mesh::renumber(out); } namespace Map { inline RefineRegular::RefineRegular( const GooseFEM::Mesh::Quad4::Regular& mesh, size_t nx, size_t ny) : m_coarse(mesh) { m_fine = Regular(nx * m_coarse.nelx(), ny * m_coarse.nely(), m_coarse.h()); - xt::xtensor elmat_coarse = m_coarse.elementMatrix(); - xt::xtensor elmat_fine = m_fine.elementMatrix(); + xt::xtensor elmat_coarse = m_coarse.elementMatrix(); + xt::xtensor elmat_fine = m_fine.elementMatrix(); m_coarse2fine = xt::empty({m_coarse.nelem(), nx * ny}); for (size_t i = 0; i < elmat_coarse.shape(0); ++i) { for (size_t j = 0; j < elmat_coarse.shape(1); ++j) { xt::view(m_coarse2fine, elmat_coarse(i, j), xt::all()) = xt::flatten(xt::view( elmat_fine, xt::range(i * ny, (i + 1) * ny), xt::range(j * nx, (j + 1) * nx))); } } } inline GooseFEM::Mesh::Quad4::Regular RefineRegular::getCoarseMesh() const { return m_coarse; } inline GooseFEM::Mesh::Quad4::Regular RefineRegular::getFineMesh() const { return m_fine; } -inline xt::xtensor RefineRegular::getMap() const +inline xt::xtensor RefineRegular::getMap() const { return m_coarse2fine; } -inline xt::xtensor RefineRegular::mapToCoarse(const xt::xtensor& data) const +inline xt::xtensor RefineRegular::mapToCoarse(const xt::xtensor& data) const { GOOSEFEM_ASSERT(data.shape(0) == m_coarse2fine.size()); size_t m = m_coarse2fine.shape(0); size_t n = m_coarse2fine.shape(1); - xt::xtensor out = xt::empty({m, n}); + xt::xtensor out = xt::empty({m, n}); for (size_t i = 0; i < m; ++i) { auto e = xt::view(m_coarse2fine, i, xt::all()); xt::view(out, i) = xt::view(data, xt::keep(e)); } return out; } -inline xt::xtensor RefineRegular::mapToCoarse(const xt::xtensor& data) const +inline xt::xtensor RefineRegular::mapToCoarse(const xt::xtensor& data) const { GOOSEFEM_ASSERT(data.shape(0) == m_coarse2fine.size()); size_t m = m_coarse2fine.shape(0); size_t n = m_coarse2fine.shape(1); size_t N = data.shape(1); - xt::xtensor out = xt::empty({m, n * N}); + xt::xtensor out = xt::empty({m, n * N}); for (size_t i = 0; i < m; ++i) { auto e = xt::view(m_coarse2fine, i, xt::all()); for (size_t q = 0; q < data.shape(1); ++q) { xt::view(out, i, xt::range(q + 0, q + n * N, N)) = xt::view(data, xt::keep(e), q); } } return out; } -inline xt::xtensor RefineRegular::mapToCoarse(const xt::xtensor& data) const +inline xt::xtensor RefineRegular::mapToCoarse(const xt::xtensor& data) const { GOOSEFEM_ASSERT(data.shape(0) == m_coarse2fine.size()); size_t m = m_coarse2fine.shape(0); size_t n = m_coarse2fine.shape(1); size_t N = data.shape(1); - xt::xtensor out = xt::empty({m, n * N, data.shape(2), data.shape(3)}); + xt::xtensor out = xt::empty({m, n * N, data.shape(2), data.shape(3)}); for (size_t i = 0; i < m; ++i) { auto e = xt::view(m_coarse2fine, i, xt::all()); for (size_t q = 0; q < data.shape(1); ++q) { xt::view(out, i, xt::range(q + 0, q + n * N, N)) = xt::view(data, xt::keep(e), q); } } return out; } -inline xt::xtensor RefineRegular::mapToFine(const xt::xtensor& data) const +inline xt::xtensor RefineRegular::mapToFine(const xt::xtensor& data) const { GOOSEFEM_ASSERT(data.shape(0) == m_coarse2fine.shape(0)); - xt::xtensor out = xt::empty({m_coarse2fine.size()}); + xt::xtensor out = xt::empty({m_coarse2fine.size()}); for (size_t i = 0; i < m_coarse2fine.shape(0); ++i) { auto e = xt::view(m_coarse2fine, i, xt::all()); xt::view(out, xt::keep(e)) = data(i); } return out; } -inline xt::xtensor RefineRegular::mapToFine(const xt::xtensor& data) const +inline xt::xtensor RefineRegular::mapToFine(const xt::xtensor& data) const { GOOSEFEM_ASSERT(data.shape(0) == m_coarse2fine.shape(0)); - xt::xtensor out = xt::empty({m_coarse2fine.size(), data.shape(1)}); + xt::xtensor out = xt::empty({m_coarse2fine.size(), data.shape(1)}); for (size_t i = 0; i < m_coarse2fine.shape(0); ++i) { auto e = xt::view(m_coarse2fine, i, xt::all()); xt::view(out, xt::keep(e)) = xt::view(data, i); } return out; } -inline xt::xtensor RefineRegular::mapToFine(const xt::xtensor& data) const +inline xt::xtensor RefineRegular::mapToFine(const xt::xtensor& data) const { GOOSEFEM_ASSERT(data.shape(0) == m_coarse2fine.shape(0)); - xt::xtensor out = + xt::xtensor out = xt::empty({m_coarse2fine.size(), data.shape(1), data.shape(2), data.shape(3)}); for (size_t i = 0; i < m_coarse2fine.shape(0); ++i) { auto e = xt::view(m_coarse2fine, i, xt::all()); xt::view(out, xt::keep(e)) = xt::view(data, i); } return out; } inline FineLayer2Regular::FineLayer2Regular(const GooseFEM::Mesh::Quad4::FineLayer& mesh) : m_finelayer(mesh) { // ------------ // Regular-mesh // ------------ m_regular = GooseFEM::Mesh::Quad4::Regular( xt::amax(m_finelayer.m_nelx)[0], xt::sum(m_finelayer.m_nhy)[0], m_finelayer.m_h); // ------- // mapping // ------- // allocate mapping m_elem_regular.resize(m_finelayer.m_nelem); m_frac_regular.resize(m_finelayer.m_nelem); // alias - xt::xtensor nhx = m_finelayer.m_nhx; - xt::xtensor nhy = m_finelayer.m_nhy; - xt::xtensor nelx = m_finelayer.m_nelx; - xt::xtensor start = m_finelayer.m_startElem; + xt::xtensor nhx = m_finelayer.m_nhx; + xt::xtensor nhy = m_finelayer.m_nhy; + xt::xtensor nelx = m_finelayer.m_nelx; + xt::xtensor start = m_finelayer.m_startElem; // 'matrix' of element numbers of the Regular-mesh - xt::xtensor elementMatrix = m_regular.elementMatrix(); + xt::xtensor elementMatrix = m_regular.elementMatrix(); // cumulative number of element-rows of the Regular-mesh per layer of the FineLayer-mesh - xt::xtensor cum_nhy = + xt::xtensor cum_nhy = xt::concatenate(xt::xtuple(xt::zeros({1}), xt::cumsum(nhy))); // number of element layers in y-direction of the FineLayer-mesh size_t nely = nhy.size(); // loop over layers of the FineLayer-mesh for (size_t iy = 0; iy < nely; ++iy) { // element numbers of the Regular-mesh along this layer of the FineLayer-mesh auto el_new = xt::view(elementMatrix, xt::range(cum_nhy(iy), cum_nhy(iy + 1)), xt::all()); // no coarsening/refinement // ------------------------ if (m_finelayer.m_refine(iy) == -1) { // element numbers of the FineLayer-mesh along this layer - xt::xtensor el_old = start(iy) + xt::arange(nelx(iy)); + xt::xtensor el_old = start(iy) + xt::arange(nelx(iy)); // loop along this layer of the FineLayer-mesh for (size_t ix = 0; ix < nelx(iy); ++ix) { // get the element numbers of the Regular-mesh for this element of the // FineLayer-mesh auto block = xt::view(el_new, xt::all(), xt::range(ix * nhx(iy), (ix + 1) * nhx(iy))); // write to mapping for (auto& i : block) { m_elem_regular[el_old(ix)].push_back(i); m_frac_regular[el_old(ix)].push_back(1.0); } } } // refinement along the x-direction (below the middle layer) // --------------------------------------------------------- else if (m_finelayer.m_refine(iy) == 0 && iy <= (nely - 1) / 2) { // element numbers of the FineLayer-mesh along this layer // rows: coarse block, columns element numbers per block - xt::xtensor el_old = + xt::xtensor el_old = start(iy) + xt::arange(nelx(iy) * 4ul).reshape({-1, 4}); // loop along this layer of the FineLayer-mesh for (size_t ix = 0; ix < nelx(iy); ++ix) { // get the element numbers of the Regular-mesh for this block of the FineLayer-mesh auto block = xt::view(el_new, xt::all(), xt::range(ix * nhx(iy), (ix + 1) * nhx(iy))); // bottom: wide-to-narrow { for (size_t j = 0; j < nhy(iy) / 2; ++j) { auto e = xt::view(block, j, xt::range(j, nhx(iy) - j)); m_elem_regular[el_old(ix, 0)].push_back(e(0)); m_frac_regular[el_old(ix, 0)].push_back(0.5); for (size_t k = 1; k < e.size() - 1; ++k) { m_elem_regular[el_old(ix, 0)].push_back(e(k)); m_frac_regular[el_old(ix, 0)].push_back(1.0); } m_elem_regular[el_old(ix, 0)].push_back(e(e.size() - 1)); m_frac_regular[el_old(ix, 0)].push_back(0.5); } } // top: regular small element { auto e = xt::view( block, xt::range(nhy(iy) / 2, nhy(iy)), xt::range(1 * nhx(iy) / 3, 2 * nhx(iy) / 3)); for (auto& i : e) { m_elem_regular[el_old(ix, 2)].push_back(i); m_frac_regular[el_old(ix, 2)].push_back(1.0); } } // left { // left-bottom: narrow-to-wide for (size_t j = 0; j < nhy(iy) / 2; ++j) { auto e = xt::view(block, j, xt::range(0, j + 1)); for (size_t k = 0; k < e.size() - 1; ++k) { m_elem_regular[el_old(ix, 3)].push_back(e(k)); m_frac_regular[el_old(ix, 3)].push_back(1.0); } m_elem_regular[el_old(ix, 3)].push_back(e(e.size() - 1)); m_frac_regular[el_old(ix, 3)].push_back(0.5); } // left-top: regular { auto e = xt::view( block, xt::range(nhy(iy) / 2, nhy(iy)), xt::range(0 * nhx(iy) / 3, 1 * nhx(iy) / 3)); for (auto& i : e) { m_elem_regular[el_old(ix, 3)].push_back(i); m_frac_regular[el_old(ix, 3)].push_back(1.0); } } } // right { // right-bottom: narrow-to-wide for (size_t j = 0; j < nhy(iy) / 2; ++j) { auto e = xt::view(block, j, xt::range(nhx(iy) - j - 1, nhx(iy))); m_elem_regular[el_old(ix, 1)].push_back(e(0)); m_frac_regular[el_old(ix, 1)].push_back(0.5); for (size_t k = 1; k < e.size(); ++k) { m_elem_regular[el_old(ix, 1)].push_back(e(k)); m_frac_regular[el_old(ix, 1)].push_back(1.0); } } // right-top: regular { auto e = xt::view( block, xt::range(nhy(iy) / 2, nhy(iy)), xt::range(2 * nhx(iy) / 3, 3 * nhx(iy) / 3)); for (auto& i : e) { m_elem_regular[el_old(ix, 1)].push_back(i); m_frac_regular[el_old(ix, 1)].push_back(1.0); } } } } } // coarsening along the x-direction (above the middle layer) else if (m_finelayer.m_refine(iy) == 0 && iy > (nely - 1) / 2) { // element numbers of the FineLayer-mesh along this layer // rows: coarse block, columns element numbers per block - xt::xtensor el_old = + xt::xtensor el_old = start(iy) + xt::arange(nelx(iy) * 4ul).reshape({-1, 4}); // loop along this layer of the FineLayer-mesh for (size_t ix = 0; ix < nelx(iy); ++ix) { // get the element numbers of the Regular-mesh for this block of the FineLayer-mesh auto block = xt::view(el_new, xt::all(), xt::range(ix * nhx(iy), (ix + 1) * nhx(iy))); // top: narrow-to-wide { for (size_t j = 0; j < nhy(iy) / 2; ++j) { auto e = xt::view( block, nhy(iy) / 2 + j, xt::range(1 * nhx(iy) / 3 - j - 1, 2 * nhx(iy) / 3 + j + 1)); m_elem_regular[el_old(ix, 3)].push_back(e(0)); m_frac_regular[el_old(ix, 3)].push_back(0.5); for (size_t k = 1; k < e.size() - 1; ++k) { m_elem_regular[el_old(ix, 3)].push_back(e(k)); m_frac_regular[el_old(ix, 3)].push_back(1.0); } m_elem_regular[el_old(ix, 3)].push_back(e(e.size() - 1)); m_frac_regular[el_old(ix, 3)].push_back(0.5); } } // bottom: regular small element { auto e = xt::view( block, xt::range(0, nhy(iy) / 2), xt::range(1 * nhx(iy) / 3, 2 * nhx(iy) / 3)); for (auto& i : e) { m_elem_regular[el_old(ix, 1)].push_back(i); m_frac_regular[el_old(ix, 1)].push_back(1.0); } } // left { // left-bottom: regular { auto e = xt::view( block, xt::range(0, nhy(iy) / 2), xt::range(0 * nhx(iy) / 3, 1 * nhx(iy) / 3)); for (auto& i : e) { m_elem_regular[el_old(ix, 0)].push_back(i); m_frac_regular[el_old(ix, 0)].push_back(1.0); } } // left-top: narrow-to-wide for (size_t j = 0; j < nhy(iy) / 2; ++j) { auto e = xt::view(block, nhy(iy) / 2 + j, xt::range(0, 1 * nhx(iy) / 3 - j)); for (size_t k = 0; k < e.size() - 1; ++k) { m_elem_regular[el_old(ix, 0)].push_back(e(k)); m_frac_regular[el_old(ix, 0)].push_back(1.0); } m_elem_regular[el_old(ix, 0)].push_back(e(e.size() - 1)); m_frac_regular[el_old(ix, 0)].push_back(0.5); } } // right { // right-bottom: regular { auto e = xt::view( block, xt::range(0, nhy(iy) / 2), xt::range(2 * nhx(iy) / 3, 3 * nhx(iy) / 3)); for (auto& i : e) { m_elem_regular[el_old(ix, 2)].push_back(i); m_frac_regular[el_old(ix, 2)].push_back(1.0); } } // right-top: narrow-to-wide for (size_t j = 0; j < nhy(iy) / 2; ++j) { auto e = xt::view( block, nhy(iy) / 2 + j, xt::range(2 * nhx(iy) / 3 + j, nhx(iy))); m_elem_regular[el_old(ix, 2)].push_back(e(0)); m_frac_regular[el_old(ix, 2)].push_back(0.5); for (size_t k = 1; k < e.size(); ++k) { m_elem_regular[el_old(ix, 2)].push_back(e(k)); m_frac_regular[el_old(ix, 2)].push_back(1.0); } } } } } } } inline GooseFEM::Mesh::Quad4::Regular FineLayer2Regular::getRegularMesh() const { return m_regular; } inline GooseFEM::Mesh::Quad4::FineLayer FineLayer2Regular::getFineLayerMesh() const { return m_finelayer; } inline std::vector> FineLayer2Regular::getMap() const { return m_elem_regular; } inline std::vector> FineLayer2Regular::getMapFraction() const { return m_frac_regular; } -inline xt::xtensor -FineLayer2Regular::mapToRegular(const xt::xtensor& data) const +inline xt::xtensor +FineLayer2Regular::mapToRegular(const xt::xtensor& data) const { GOOSEFEM_ASSERT(data.shape(0) == m_finelayer.nelem()); - xt::xtensor out = xt::zeros({m_regular.nelem()}); + xt::xtensor out = xt::zeros({m_regular.nelem()}); for (size_t e = 0; e < m_finelayer.nelem(); ++e) { for (size_t i = 0; i < m_elem_regular[e].size(); ++i) { out(m_elem_regular[e][i]) += m_frac_regular[e][i] * data(e); } } return out; } -inline xt::xtensor -FineLayer2Regular::mapToRegular(const xt::xtensor& data) const +inline xt::xtensor +FineLayer2Regular::mapToRegular(const xt::xtensor& data) const { GOOSEFEM_ASSERT(data.shape(0) == m_finelayer.nelem()); - xt::xtensor out = xt::zeros({m_regular.nelem(), data.shape(1)}); + xt::xtensor out = xt::zeros({m_regular.nelem(), data.shape(1)}); for (size_t e = 0; e < m_finelayer.nelem(); ++e) { for (size_t i = 0; i < m_elem_regular[e].size(); ++i) { xt::view(out, m_elem_regular[e][i]) += m_frac_regular[e][i] * xt::view(data, e); } } return out; } -inline xt::xtensor -FineLayer2Regular::mapToRegular(const xt::xtensor& data) const +inline xt::xtensor +FineLayer2Regular::mapToRegular(const xt::xtensor& data) const { GOOSEFEM_ASSERT(data.shape(0) == m_finelayer.nelem()); - xt::xtensor out = + xt::xtensor out = xt::zeros({m_regular.nelem(), data.shape(1), data.shape(2), data.shape(3)}); for (size_t e = 0; e < m_finelayer.nelem(); ++e) { for (size_t i = 0; i < m_elem_regular[e].size(); ++i) { xt::view(out, m_elem_regular[e][i]) += m_frac_regular[e][i] * xt::view(data, e); } } return out; } } // namespace Map } // namespace Quad4 } // namespace Mesh } // namespace GooseFEM #endif diff --git a/include/GooseFEM/MeshTri3.h b/include/GooseFEM/MeshTri3.h index 098310e..3cb0ea1 100644 --- a/include/GooseFEM/MeshTri3.h +++ b/include/GooseFEM/MeshTri3.h @@ -1,99 +1,96 @@ /* (c - GPLv3) T.W.J. de Geus (Tom) | tom@geus.me | www.geus.me | github.com/tdegeus/GooseFEM */ #ifndef GOOSEFEM_MESHTRI3_H #define GOOSEFEM_MESHTRI3_H #include "config.h" namespace GooseFEM { namespace Mesh { namespace Tri3 { class Regular { public: Regular(size_t nelx, size_t nely, double h = 1.); // size size_t nelem() const; // number of elements size_t nnode() const; // number of nodes size_t nne() const; // number of nodes-per-element size_t ndim() const; // number of dimensions // type ElementType getElementType() const; // mesh - xt::xtensor coor() const; // nodal positions [nnode, ndim] - xt::xtensor conn() const; // connectivity [nelem, nne] + xt::xtensor coor() const; // nodal positions [nnode, ndim] + xt::xtensor conn() const; // connectivity [nelem, nne] // boundary nodes: edges - xt::xtensor nodesBottomEdge() const; - xt::xtensor nodesTopEdge() const; - xt::xtensor nodesLeftEdge() const; - xt::xtensor nodesRightEdge() const; + xt::xtensor nodesBottomEdge() const; + xt::xtensor nodesTopEdge() const; + xt::xtensor nodesLeftEdge() const; + xt::xtensor nodesRightEdge() const; // boundary nodes: edges, without corners - xt::xtensor nodesBottomOpenEdge() const; - xt::xtensor nodesTopOpenEdge() const; - xt::xtensor nodesLeftOpenEdge() const; - xt::xtensor nodesRightOpenEdge() const; + xt::xtensor nodesBottomOpenEdge() const; + xt::xtensor nodesTopOpenEdge() const; + xt::xtensor nodesLeftOpenEdge() const; + xt::xtensor nodesRightOpenEdge() const; // boundary nodes: corners (including aliases) size_t nodesBottomLeftCorner() const; size_t nodesBottomRightCorner() const; size_t nodesTopLeftCorner() const; size_t nodesTopRightCorner() const; size_t nodesLeftBottomCorner() const; size_t nodesLeftTopCorner() const; size_t nodesRightBottomCorner() const; size_t nodesRightTopCorner() const; // DOF-numbers for each component of each node (sequential) - xt::xtensor dofs() const; + xt::xtensor dofs() const; // DOF-numbers for the case that the periodicity if fully eliminated - xt::xtensor dofsPeriodic() const; + xt::xtensor dofsPeriodic() const; // periodic node pairs [:,2]: (independent, dependent) - xt::xtensor nodesPeriodic() const; + xt::xtensor nodesPeriodic() const; // front-bottom-left node, used as reference for periodicity size_t nodesOrigin() const; private: double m_h; // elementary element edge-size (in all directions) size_t m_nelx; // number of elements in x-direction (length == "m_nelx * m_h") size_t m_nely; // number of elements in y-direction (length == "m_nely * m_h") size_t m_nelem; // number of elements size_t m_nnode; // number of nodes static const size_t m_nne = 3; // number of nodes-per-element static const size_t m_ndim = 2; // number of dimensions }; // read / set the orientation (-1/+1) of all triangles -inline xt::xtensor getOrientation( - const xt::xtensor& coor, - const xt::xtensor& conn); +inline xt::xtensor getOrientation( + const xt::xtensor& coor, const xt::xtensor& conn); -inline xt::xtensor setOrientation( - const xt::xtensor& coor, - const xt::xtensor& conn, - int orientation = -1); +inline xt::xtensor setOrientation( + const xt::xtensor& coor, const xt::xtensor& conn, int orientation = -1); -inline xt::xtensor setOrientation( - const xt::xtensor& coor, - const xt::xtensor& conn, - const xt::xtensor& current, // (output of "getOrientation") +inline xt::xtensor setOrientation( + const xt::xtensor& coor, + const xt::xtensor& conn, + const xt::xtensor& current, // (output of "getOrientation") int orientation = -1); } // namespace Tri3 } // namespace Mesh } // namespace GooseFEM #include "MeshTri3.hpp" #endif diff --git a/include/GooseFEM/MeshTri3.hpp b/include/GooseFEM/MeshTri3.hpp index cc71dd7..32f982d 100644 --- a/include/GooseFEM/MeshTri3.hpp +++ b/include/GooseFEM/MeshTri3.hpp @@ -1,354 +1,354 @@ /* (c - GPLv3) T.W.J. de Geus (Tom) | tom@geus.me | www.geus.me | github.com/tdegeus/GooseFEM */ #ifndef GOOSEFEM_MESHTRI3_HPP #define GOOSEFEM_MESHTRI3_HPP #include "MeshTri3.h" namespace GooseFEM { namespace Mesh { namespace Tri3 { inline Regular::Regular(size_t nelx, size_t nely, double h) : m_h(h), m_nelx(nelx), m_nely(nely) { GOOSEFEM_ASSERT(m_nelx >= 1ul); GOOSEFEM_ASSERT(m_nely >= 1ul); m_nnode = (m_nelx + 1) * (m_nely + 1); m_nelem = m_nelx * m_nely * 2; } inline size_t Regular::nelem() const { return m_nelem; } inline size_t Regular::nnode() const { return m_nnode; } inline size_t Regular::nne() const { return m_nne; } inline size_t Regular::ndim() const { return m_ndim; } inline ElementType Regular::getElementType() const { return ElementType::Tri3; } -inline xt::xtensor Regular::coor() const +inline xt::xtensor Regular::coor() const { - xt::xtensor out = xt::empty({m_nnode, m_ndim}); + xt::xtensor out = xt::empty({m_nnode, m_ndim}); - xt::xtensor x = + xt::xtensor x = xt::linspace(0.0, m_h * static_cast(m_nelx), m_nelx + 1); - xt::xtensor y = + xt::xtensor y = xt::linspace(0.0, m_h * static_cast(m_nely), m_nely + 1); size_t inode = 0; for (size_t iy = 0; iy < m_nely + 1; ++iy) { for (size_t ix = 0; ix < m_nelx + 1; ++ix) { out(inode, 0) = x(ix); out(inode, 1) = y(iy); ++inode; } } return out; } -inline xt::xtensor Regular::conn() const +inline xt::xtensor Regular::conn() const { - xt::xtensor out = xt::empty({m_nelem, m_nne}); + xt::xtensor out = xt::empty({m_nelem, m_nne}); size_t ielem = 0; for (size_t iy = 0; iy < m_nely; ++iy) { for (size_t ix = 0; ix < m_nelx; ++ix) { out(ielem, 0) = (iy) * (m_nelx + 1) + (ix); out(ielem, 1) = (iy) * (m_nelx + 1) + (ix + 1); out(ielem, 2) = (iy + 1) * (m_nelx + 1) + (ix); ++ielem; out(ielem, 0) = (iy) * (m_nelx + 1) + (ix + 1); out(ielem, 1) = (iy + 1) * (m_nelx + 1) + (ix + 1); out(ielem, 2) = (iy + 1) * (m_nelx + 1) + (ix); ++ielem; } } return out; } -inline xt::xtensor Regular::nodesBottomEdge() const +inline xt::xtensor Regular::nodesBottomEdge() const { - xt::xtensor out = xt::empty({m_nelx + 1}); + xt::xtensor out = xt::empty({m_nelx + 1}); for (size_t ix = 0; ix < m_nelx + 1; ++ix) { out(ix) = ix; } return out; } -inline xt::xtensor Regular::nodesTopEdge() const +inline xt::xtensor Regular::nodesTopEdge() const { - xt::xtensor out = xt::empty({m_nelx + 1}); + xt::xtensor out = xt::empty({m_nelx + 1}); for (size_t ix = 0; ix < m_nelx + 1; ++ix) { out(ix) = ix + m_nely * (m_nelx + 1); } return out; } -inline xt::xtensor Regular::nodesLeftEdge() const +inline xt::xtensor Regular::nodesLeftEdge() const { - xt::xtensor out = xt::empty({m_nely + 1}); + xt::xtensor out = xt::empty({m_nely + 1}); for (size_t iy = 0; iy < m_nely + 1; ++iy) { out(iy) = iy * (m_nelx + 1); } return out; } -inline xt::xtensor Regular::nodesRightEdge() const +inline xt::xtensor Regular::nodesRightEdge() const { - xt::xtensor out = xt::empty({m_nely + 1}); + xt::xtensor out = xt::empty({m_nely + 1}); for (size_t iy = 0; iy < m_nely + 1; ++iy) { out(iy) = iy * (m_nelx + 1) + m_nelx; } return out; } -inline xt::xtensor Regular::nodesBottomOpenEdge() const +inline xt::xtensor Regular::nodesBottomOpenEdge() const { - xt::xtensor out = xt::empty({m_nelx - 1}); + xt::xtensor out = xt::empty({m_nelx - 1}); for (size_t ix = 1; ix < m_nelx; ++ix) { out(ix - 1) = ix; } return out; } -inline xt::xtensor Regular::nodesTopOpenEdge() const +inline xt::xtensor Regular::nodesTopOpenEdge() const { - xt::xtensor out = xt::empty({m_nelx - 1}); + xt::xtensor out = xt::empty({m_nelx - 1}); for (size_t ix = 1; ix < m_nelx; ++ix) { out(ix - 1) = ix + m_nely * (m_nelx + 1); } return out; } -inline xt::xtensor Regular::nodesLeftOpenEdge() const +inline xt::xtensor Regular::nodesLeftOpenEdge() const { - xt::xtensor out = xt::empty({m_nely - 1}); + xt::xtensor out = xt::empty({m_nely - 1}); for (size_t iy = 1; iy < m_nely; ++iy) { out(iy - 1) = iy * (m_nelx + 1); } return out; } -inline xt::xtensor Regular::nodesRightOpenEdge() const +inline xt::xtensor Regular::nodesRightOpenEdge() const { - xt::xtensor out = xt::empty({m_nely - 1}); + xt::xtensor out = xt::empty({m_nely - 1}); for (size_t iy = 1; iy < m_nely; ++iy) { out(iy - 1) = iy * (m_nelx + 1) + m_nelx; } return out; } inline size_t Regular::nodesBottomLeftCorner() const { return 0; } inline size_t Regular::nodesBottomRightCorner() const { return m_nelx; } inline size_t Regular::nodesTopLeftCorner() const { return m_nely * (m_nelx + 1); } inline size_t Regular::nodesTopRightCorner() const { return m_nely * (m_nelx + 1) + m_nelx; } inline size_t Regular::nodesLeftBottomCorner() const { return nodesBottomLeftCorner(); } inline size_t Regular::nodesLeftTopCorner() const { return nodesTopLeftCorner(); } inline size_t Regular::nodesRightBottomCorner() const { return nodesBottomRightCorner(); } inline size_t Regular::nodesRightTopCorner() const { return nodesTopRightCorner(); } -inline xt::xtensor Regular::nodesPeriodic() const +inline xt::xtensor Regular::nodesPeriodic() const { - xt::xtensor bot = nodesBottomOpenEdge(); - xt::xtensor top = nodesTopOpenEdge(); - xt::xtensor lft = nodesLeftOpenEdge(); - xt::xtensor rgt = nodesRightOpenEdge(); + xt::xtensor bot = nodesBottomOpenEdge(); + xt::xtensor top = nodesTopOpenEdge(); + xt::xtensor lft = nodesLeftOpenEdge(); + xt::xtensor rgt = nodesRightOpenEdge(); size_t tedge = bot.size() + lft.size(); size_t tnode = 3; - xt::xtensor out = xt::empty({tedge + tnode, std::size_t(2)}); + xt::xtensor out = xt::empty({tedge + tnode, std::size_t(2)}); size_t i = 0; out(i, 0) = nodesBottomLeftCorner(); out(i, 1) = nodesBottomRightCorner(); ++i; out(i, 0) = nodesBottomLeftCorner(); out(i, 1) = nodesTopRightCorner(); ++i; out(i, 0) = nodesBottomLeftCorner(); out(i, 1) = nodesTopLeftCorner(); ++i; for (size_t j = 0; j < bot.size(); ++j) { out(i, 0) = bot(j); out(i, 1) = top(j); ++i; } for (size_t j = 0; j < lft.size(); ++j) { out(i, 0) = lft(j); out(i, 1) = rgt(j); ++i; } return out; } inline size_t Regular::nodesOrigin() const { return nodesBottomLeftCorner(); } -inline xt::xtensor Regular::dofs() const +inline xt::xtensor Regular::dofs() const { return GooseFEM::Mesh::dofs(m_nnode, m_ndim); } -inline xt::xtensor Regular::dofsPeriodic() const +inline xt::xtensor Regular::dofsPeriodic() const { - xt::xtensor out = GooseFEM::Mesh::dofs(m_nnode, m_ndim); - xt::xtensor nodePer = nodesPeriodic(); + xt::xtensor out = GooseFEM::Mesh::dofs(m_nnode, m_ndim); + xt::xtensor nodePer = nodesPeriodic(); for (size_t i = 0; i < nodePer.shape(0); ++i) { for (size_t j = 0; j < m_ndim; ++j) { out(nodePer(i, 1), j) = out(nodePer(i, 0), j); } } return GooseFEM::Mesh::renumber(out); } -inline xt::xtensor -getOrientation(const xt::xtensor& coor, const xt::xtensor& conn) +inline xt::xtensor +getOrientation(const xt::xtensor& coor, const xt::xtensor& conn) { GOOSEFEM_ASSERT(conn.shape(1) == 3ul); GOOSEFEM_ASSERT(coor.shape(1) == 2ul); double k; size_t nelem = conn.shape(0); - xt::xtensor out = xt::empty({nelem}); + xt::xtensor out = xt::empty({nelem}); for (size_t ielem = 0; ielem < nelem; ++ielem) { auto v1 = xt::view(coor, conn(ielem, 0), xt::all()) - xt::view(coor, conn(ielem, 1), xt::all()); auto v2 = xt::view(coor, conn(ielem, 2), xt::all()) - xt::view(coor, conn(ielem, 1), xt::all()); k = v1(0) * v2(1) - v2(0) * v1(1); if (k < 0) { out(ielem) = -1; } else { out(ielem) = +1; } } return out; } -inline xt::xtensor setOrientation( - const xt::xtensor& coor, const xt::xtensor& conn, int orientation) +inline xt::xtensor setOrientation( + const xt::xtensor& coor, const xt::xtensor& conn, int orientation) { GOOSEFEM_ASSERT(conn.shape(1) == 3ul); GOOSEFEM_ASSERT(coor.shape(1) == 2ul); GOOSEFEM_ASSERT(orientation == -1 || orientation == +1); - xt::xtensor val = getOrientation(coor, conn); + xt::xtensor val = getOrientation(coor, conn); return setOrientation(coor, conn, val, orientation); } -inline xt::xtensor setOrientation( - const xt::xtensor& coor, - const xt::xtensor& conn, - const xt::xtensor& val, +inline xt::xtensor setOrientation( + const xt::xtensor& coor, + const xt::xtensor& conn, + const xt::xtensor& val, int orientation) { GOOSEFEM_ASSERT(conn.shape(1) == 3ul); GOOSEFEM_ASSERT(coor.shape(1) == 2ul); GOOSEFEM_ASSERT(conn.shape(0) == val.size()); GOOSEFEM_ASSERT(orientation == -1 || orientation == +1); UNUSED(coor); size_t nelem = conn.shape(0); - xt::xtensor out = conn; + xt::xtensor out = conn; for (size_t ielem = 0; ielem < nelem; ++ielem) { if ((orientation == -1 && val(ielem) > 0) || (orientation == +1 && val(ielem) < 0)) { std::swap(out(ielem, 2), out(ielem, 1)); } } return out; } } // namespace Tri3 } // namespace Mesh } // namespace GooseFEM #endif diff --git a/include/GooseFEM/ParaView.h b/include/GooseFEM/ParaView.h index 30c0fdf..e8f6646 100644 --- a/include/GooseFEM/ParaView.h +++ b/include/GooseFEM/ParaView.h @@ -1,272 +1,266 @@ /* (c - GPLv3) T.W.J. de Geus (Tom) | tom@geus.me | www.geus.me | github.com/tdegeus/GooseFEM */ #ifndef GOOSEFEM_PARAVIEW_H #define GOOSEFEM_PARAVIEW_H // See: http://xdmf.org/index.php/XDMF_Model_and_Format #include "config.h" #include #ifndef GOOSEFEM_NO_HIGHFIVE #include #endif namespace GooseFEM { namespace ParaView { namespace HDF5 { inline std::string join(const std::vector& lines, const std::string& sep = "\n"); inline std::string indent(size_t n); -xt::xtensor as3d(const xt::xtensor& data); +xt::xtensor as3d(const xt::xtensor& data); enum class ElementType { Triangle, Quadrilateral, Hexahedron }; enum class AttributeType { Cell, Node }; inline ElementType convert(GooseFEM::Mesh::ElementType type); inline std::string to_string(ElementType type); inline std::string to_string(AttributeType type); class Connectivity { public: Connectivity() = default; - #ifndef GOOSEFEM_NO_HIGHFIVE +#ifndef GOOSEFEM_NO_HIGHFIVE Connectivity( const H5Easy::File& data, const std::string& dataset, GooseFEM::Mesh::ElementType type); - #endif +#endif - #ifndef GOOSEFEM_NO_HIGHFIVE +#ifndef GOOSEFEM_NO_HIGHFIVE Connectivity( const std::string& fname, const std::string& dataset, GooseFEM::Mesh::ElementType type); - #endif +#endif Connectivity( const std::string& fname, const std::string& dataset, GooseFEM::Mesh::ElementType type, const std::vector& shape); - #ifndef GOOSEFEM_NO_HIGHFIVE +#ifndef GOOSEFEM_NO_HIGHFIVE Connectivity(const H5Easy::File& data, const std::string& dataset, ElementType type); - #endif +#endif - #ifndef GOOSEFEM_NO_HIGHFIVE +#ifndef GOOSEFEM_NO_HIGHFIVE Connectivity(const std::string& fname, const std::string& dataset, ElementType type); - #endif +#endif Connectivity( const std::string& fname, const std::string& dataset, ElementType type, const std::vector& shape); size_t nelem() const; size_t nne() const; std::vector shape() const; std::string fname() const; - #ifndef GOOSEFEM_NO_HIGHFIVE +#ifndef GOOSEFEM_NO_HIGHFIVE void checkShape(); - #endif +#endif std::vector xdmf(size_t indent = 4) const; private: - #ifndef GOOSEFEM_NO_HIGHFIVE +#ifndef GOOSEFEM_NO_HIGHFIVE void readShape(const H5Easy::File& data); - #endif +#endif - #ifndef GOOSEFEM_NO_HIGHFIVE +#ifndef GOOSEFEM_NO_HIGHFIVE void init(const H5Easy::File& data, const std::string& dataset, ElementType type); - #endif +#endif - #ifndef GOOSEFEM_NO_HIGHFIVE +#ifndef GOOSEFEM_NO_HIGHFIVE void init(const std::string& fname, const std::string& dataset, ElementType type); - #endif +#endif void init( const std::string& fname, const std::string& dataset, ElementType type, const std::vector& shape); ElementType m_type; std::string m_fname; std::string m_dataset; std::vector m_shape; - #ifndef GOOSEFEM_NO_HIGHFIVE +#ifndef GOOSEFEM_NO_HIGHFIVE bool m_verified = false; // if true: shape read from file, not need to check - #endif +#endif }; class Coordinates { public: Coordinates() = default; - #ifndef GOOSEFEM_NO_HIGHFIVE +#ifndef GOOSEFEM_NO_HIGHFIVE Coordinates(const H5Easy::File& data, const std::string& dataset); - #endif +#endif - #ifndef GOOSEFEM_NO_HIGHFIVE - Coordinates( - const std::string& fname, - const std::string& dataset); - #endif +#ifndef GOOSEFEM_NO_HIGHFIVE + Coordinates(const std::string& fname, const std::string& dataset); +#endif Coordinates( - const std::string& fname, - const std::string& dataset, - const std::vector& shape); + const std::string& fname, const std::string& dataset, const std::vector& shape); size_t nnode() const; size_t ndim() const; std::vector shape() const; std::string fname() const; - #ifndef GOOSEFEM_NO_HIGHFIVE +#ifndef GOOSEFEM_NO_HIGHFIVE void checkShape(); - #endif +#endif std::vector xdmf(size_t indent = 4) const; private: - #ifndef GOOSEFEM_NO_HIGHFIVE +#ifndef GOOSEFEM_NO_HIGHFIVE void readShape(const H5Easy::File& data); - #endif +#endif std::string m_fname; std::string m_dataset; std::vector m_shape; - #ifndef GOOSEFEM_NO_HIGHFIVE +#ifndef GOOSEFEM_NO_HIGHFIVE bool m_verified = false; // if true: shape read from file, not need to check - #endif +#endif }; class Attribute { public: Attribute() = default; - #ifndef GOOSEFEM_NO_HIGHFIVE +#ifndef GOOSEFEM_NO_HIGHFIVE Attribute( const H5Easy::File& data, const std::string& dataset, const std::string& name, AttributeType type); - #endif +#endif - #ifndef GOOSEFEM_NO_HIGHFIVE +#ifndef GOOSEFEM_NO_HIGHFIVE Attribute( const std::string& fname, const std::string& dataset, const std::string& name, AttributeType type); - #endif +#endif Attribute( const std::string& fname, const std::string& dataset, const std::string& name, AttributeType type, const std::vector& shape); std::vector shape() const; std::string fname() const; - #ifndef GOOSEFEM_NO_HIGHFIVE +#ifndef GOOSEFEM_NO_HIGHFIVE void checkShape(); - #endif +#endif std::vector xdmf(size_t indent = 4) const; private: - #ifndef GOOSEFEM_NO_HIGHFIVE +#ifndef GOOSEFEM_NO_HIGHFIVE void readShape(const H5Easy::File& data); - #endif +#endif AttributeType m_type; std::string m_fname; std::string m_dataset; std::string m_name; std::vector m_shape; - #ifndef GOOSEFEM_NO_HIGHFIVE +#ifndef GOOSEFEM_NO_HIGHFIVE bool m_verified = false; // if true: shape read from file, not need to check - #endif +#endif }; class Mesh { public: Mesh() = default; Mesh(const Connectivity& conn, const Coordinates& coor); void push_back(const Attribute& data); std::vector xdmf(size_t indent = 4) const; void write(const std::string& fname, size_t n_indent = 4) const; private: Connectivity m_conn; Coordinates m_coor; std::vector m_attr; }; class Increment { public: Increment() = default; Increment(const Connectivity& conn, const Coordinates& coor); Increment( - const Connectivity& conn, - const Coordinates& coor, - const std::vector& attr); + const Connectivity& conn, const Coordinates& coor, const std::vector& attr); void push_back(const Connectivity& data); void push_back(const Coordinates& data); void push_back(const Attribute& data); std::vector xdmf(size_t indent = 4) const; private: std::vector m_conn; std::vector m_coor; std::vector m_attr; }; class TimeSeries { public: TimeSeries() = default; TimeSeries(const std::vector& data); void push_back(const Increment& data); std::vector xdmf(size_t indent = 4) const; void write(const std::string& fname, size_t n_indent = 4) const; private: std::vector m_data; }; } // namespace HDF5 } // namespace ParaView } // namespace GooseFEM #include "ParaView.hpp" #endif diff --git a/include/GooseFEM/ParaView.hpp b/include/GooseFEM/ParaView.hpp index c8dd4d0..db1c535 100644 --- a/include/GooseFEM/ParaView.hpp +++ b/include/GooseFEM/ParaView.hpp @@ -1,671 +1,671 @@ /* (c - GPLv3) T.W.J. de Geus (Tom) | tom@geus.me | www.geus.me | github.com/tdegeus/GooseFEM */ #ifndef GOOSEFEM_PARAVIEW_HPP #define GOOSEFEM_PARAVIEW_HPP #include "ParaView.h" namespace GooseFEM { namespace ParaView { namespace HDF5 { inline std::string join(const std::vector& lines, const std::string& sep) { if (lines.size() == 1) { return lines[0]; } std::string out = ""; for (auto line : lines) { if (out.size() == 0) { out += line; continue; } if (line[0] == sep[0]) { out += line; } else if (out[out.size() - 1] == sep[0]) { out += line; } else { out += sep + line; } } return out; } inline std::string indent(size_t n) { std::string out = ""; for (size_t i = 0; i < n; ++i) { out += " "; } return out; } -xt::xtensor as3d(const xt::xtensor& data) +xt::xtensor as3d(const xt::xtensor& data) { GOOSEFEM_ASSERT(data.shape(1) > 0 && data.shape(1) < 4) if (data.shape(1) == 3ul) { return data; } - xt::xtensor out = xt::zeros({data.shape(0), 3ul}); + xt::xtensor out = xt::zeros({data.shape(0), 3ul}); if (data.shape(1) == 2ul) { xt::view(out, xt::all(), xt::keep(0, 1)) = data; } if (data.shape(1) == 1ul) { xt::view(out, xt::all(), xt::keep(0)) = data; } return out; } inline ElementType convert(GooseFEM::Mesh::ElementType type) { if (type == GooseFEM::Mesh::ElementType::Tri3) { return ElementType::Triangle; } if (type == GooseFEM::Mesh::ElementType::Quad4) { return ElementType::Quadrilateral; } if (type == GooseFEM::Mesh::ElementType::Hex8) { return ElementType::Hexahedron; } throw std::runtime_error("Unknown GooseFEM::Mesh::ElementType"); } inline std::string to_string(ElementType type) { if (type == ElementType::Triangle) { return "Triangle"; } if (type == ElementType::Quadrilateral) { return "Quadrilateral"; } if (type == ElementType::Hexahedron) { return "Hexahedron"; } throw std::runtime_error("Unknown GooseFEM::ParaView::HDF5::ElementType"); } inline std::string to_string(AttributeType type) { if (type == AttributeType::Cell) { return "Cell"; } if (type == AttributeType::Node) { return "Node"; } throw std::runtime_error("Unknown GooseFEM::ParaView::HDF5::AttributeType"); } #ifndef GOOSEFEM_NO_HIGHFIVE inline Connectivity::Connectivity( const H5Easy::File& data, const std::string& dataset, GooseFEM::Mesh::ElementType type) { init(data, dataset, convert(type)); } #endif #ifndef GOOSEFEM_NO_HIGHFIVE inline Connectivity::Connectivity( const std::string& fname, const std::string& dataset, GooseFEM::Mesh::ElementType type) { init(fname, dataset, convert(type)); } #endif inline Connectivity::Connectivity( const std::string& fname, const std::string& dataset, GooseFEM::Mesh::ElementType type, const std::vector& shape) { init(fname, dataset, convert(type), shape); } #ifndef GOOSEFEM_NO_HIGHFIVE inline Connectivity::Connectivity( const H5Easy::File& data, const std::string& dataset, ElementType type) { init(data, dataset, type); } #endif #ifndef GOOSEFEM_NO_HIGHFIVE inline Connectivity::Connectivity( const std::string& fname, const std::string& dataset, ElementType type) { init(fname, dataset, type); } #endif inline Connectivity::Connectivity( const std::string& fname, const std::string& dataset, ElementType type, const std::vector& shape) { init(fname, dataset, type, shape); } #ifndef GOOSEFEM_NO_HIGHFIVE inline void Connectivity::init(const H5Easy::File& data, const std::string& dataset, ElementType type) { m_type = type; m_dataset = dataset; this->readShape(data); } #endif #ifndef GOOSEFEM_NO_HIGHFIVE inline void Connectivity::init(const std::string& fname, const std::string& dataset, ElementType type) { m_type = type; m_fname = fname; m_dataset = dataset; H5Easy::File data(m_fname, H5Easy::File::ReadOnly); this->readShape(data); } #endif inline void Connectivity::init( const std::string& fname, const std::string& dataset, ElementType type, const std::vector& shape) { m_type = type; m_fname = fname; m_dataset = dataset; m_shape = shape; GOOSEFEM_ASSERT(m_shape.size() == 2); - #ifdef GOOSEFEM_ENABLE_ASSERT +#ifdef GOOSEFEM_ENABLE_ASSERT if (m_type == ElementType::Triangle) { GOOSEFEM_ASSERT(m_shape[1] == 3); } else if (m_type == ElementType::Quadrilateral) { GOOSEFEM_ASSERT(m_shape[1] == 4); } else if (m_type == ElementType::Hexahedron) { GOOSEFEM_ASSERT(m_shape[1] == 8); } - #endif +#endif } inline size_t Connectivity::nelem() const { return m_shape[0]; } inline size_t Connectivity::nne() const { return m_shape[1]; } inline std::vector Connectivity::shape() const { return m_shape; } inline std::string Connectivity::fname() const { return m_fname; } #ifndef GOOSEFEM_NO_HIGHFIVE inline void Connectivity::checkShape() { if (m_verified) return; H5Easy::File data(m_fname, H5Easy::File::ReadOnly); GOOSEFEM_CHECK(m_shape == H5Easy::getShape(data, m_dataset)); m_verified = true; } #endif #ifndef GOOSEFEM_NO_HIGHFIVE inline void Connectivity::readShape(const H5Easy::File& data) { if (m_fname.size() == 0) m_fname = data.getName(); m_shape = H5Easy::getShape(data, m_dataset); GOOSEFEM_ASSERT(m_shape.size() == 2); - #ifdef GOOSEFEM_ENABLE_ASSERT +#ifdef GOOSEFEM_ENABLE_ASSERT if (m_type == ElementType::Triangle) { GOOSEFEM_ASSERT(m_shape[1] == 3); } else if (m_type == ElementType::Quadrilateral) { GOOSEFEM_ASSERT(m_shape[1] == 4); } else if (m_type == ElementType::Hexahedron) { GOOSEFEM_ASSERT(m_shape[1] == 8); } - #endif +#endif m_verified = true; } #endif inline std::vector Connectivity::xdmf(size_t n_indent) const { std::vector out; out.push_back( ""); out.push_back( indent(n_indent) + "" + m_fname + ":" + m_dataset + ""); out.push_back(""); return out; } #ifndef GOOSEFEM_NO_HIGHFIVE inline Coordinates::Coordinates(const H5Easy::File& data, const std::string& dataset) : m_dataset(dataset) { this->readShape(data); } #endif #ifndef GOOSEFEM_NO_HIGHFIVE inline Coordinates::Coordinates(const std::string& fname, const std::string& dataset) : m_fname(fname), m_dataset(dataset) { H5Easy::File data(m_fname, H5Easy::File::ReadOnly); this->readShape(data); } #endif inline Coordinates::Coordinates( const std::string& fname, const std::string& dataset, const std::vector& shape) : m_fname(fname), m_dataset(dataset), m_shape(shape) { GOOSEFEM_ASSERT(m_shape.size() == 2); } inline size_t Coordinates::nnode() const { return m_shape[0]; } inline size_t Coordinates::ndim() const { return m_shape[1]; } inline std::vector Coordinates::shape() const { return m_shape; } inline std::string Coordinates::fname() const { return m_fname; } #ifndef GOOSEFEM_NO_HIGHFIVE inline void Coordinates::checkShape() { if (m_verified) return; H5Easy::File data(m_fname, H5Easy::File::ReadOnly); GOOSEFEM_CHECK(m_shape == H5Easy::getShape(data, m_dataset)); m_verified = true; } #endif #ifndef GOOSEFEM_NO_HIGHFIVE inline void Coordinates::readShape(const H5Easy::File& data) { if (m_fname.size() == 0) m_fname = data.getName(); m_shape = H5Easy::getShape(data, m_dataset); GOOSEFEM_ASSERT(m_shape.size() == 2); m_verified = true; } #endif inline std::vector Coordinates::xdmf(size_t n_indent) const { std::vector out; if (m_shape[1] == 1) { out.push_back(""); } else if (m_shape[1] == 2) { out.push_back(""); } else if (m_shape[1] == 3) { out.push_back(""); } out.push_back( indent(n_indent) + "" + m_fname + ":" + m_dataset + ""); out.push_back(")"); return out; } #ifndef GOOSEFEM_NO_HIGHFIVE inline Attribute::Attribute( const H5Easy::File& data, const std::string& dataset, const std::string& name, AttributeType type) : m_type(type), m_dataset(dataset), m_name(name) { this->readShape(data); } #endif #ifndef GOOSEFEM_NO_HIGHFIVE inline Attribute::Attribute( const std::string& fname, const std::string& dataset, const std::string& name, AttributeType type) : m_type(type), m_fname(fname), m_dataset(dataset), m_name(name) { H5Easy::File data(m_fname, H5Easy::File::ReadOnly); this->readShape(data); } #endif inline Attribute::Attribute( const std::string& fname, const std::string& dataset, const std::string& name, AttributeType type, const std::vector& shape) : m_type(type), m_fname(fname), m_dataset(dataset), m_name(name), m_shape(shape) { GOOSEFEM_ASSERT(m_shape.size() > 0); } inline std::vector Attribute::shape() const { return m_shape; } inline std::string Attribute::fname() const { return m_fname; } #ifndef GOOSEFEM_NO_HIGHFIVE inline void Attribute::checkShape() { if (m_verified) return; H5Easy::File data(m_fname, H5Easy::File::ReadOnly); GOOSEFEM_CHECK(m_shape == H5Easy::getShape(data, m_dataset)); m_verified = true; } #endif #ifndef GOOSEFEM_NO_HIGHFIVE inline void Attribute::readShape(const H5Easy::File& data) { if (m_fname.size() == 0) { m_fname = data.getName(); } m_shape = H5Easy::getShape(data, m_dataset); GOOSEFEM_ASSERT(m_shape.size() > 0); m_verified = true; } #endif inline std::vector Attribute::xdmf(size_t n_indent) const { GOOSEFEM_ASSERT(m_shape.size() > 0); GOOSEFEM_ASSERT(m_shape.size() < 3); std::vector out; if (m_shape.size() == 1) { out.push_back( ""); out.push_back( indent(n_indent) + "" + m_fname + ":" + m_dataset + ""); } else if (m_shape.size() == 2) { out.push_back( ""); out.push_back( indent(n_indent) + "" + m_fname + ":" + m_dataset + ""); } out.push_back(")"); return out; } inline Mesh::Mesh(const Connectivity& conn, const Coordinates& coor) : m_conn(conn), m_coor(coor) { } inline void Mesh::push_back(const Attribute& data) { m_attr.push_back(data); } inline std::vector Mesh::xdmf(size_t n_indent) const { std::vector out; { std::vector lines = m_conn.xdmf(n_indent); for (auto& line : lines) { out.push_back(line); } } { std::vector lines = m_coor.xdmf(n_indent); for (auto& line : lines) { out.push_back(line); } } for (auto& i : m_attr) { std::vector lines = i.xdmf(n_indent); for (auto& line : lines) { out.push_back(line); } } return out; } inline void Mesh::write(const std::string& fname, size_t n_indent) const { TimeSeries({Increment(m_conn, m_coor, m_attr)}).write(fname, n_indent); } inline Increment::Increment(const Connectivity& conn, const Coordinates& coor) { m_conn.push_back(conn); m_coor.push_back(coor); } inline Increment::Increment( const Connectivity& conn, const Coordinates& coor, const std::vector& attr) : m_attr(attr) { m_conn.push_back(conn); m_coor.push_back(coor); } inline void Increment::push_back(const Connectivity& data) { m_conn.push_back(data); } inline void Increment::push_back(const Coordinates& data) { m_coor.push_back(data); } inline void Increment::push_back(const Attribute& data) { m_attr.push_back(data); } inline std::vector Increment::xdmf(size_t n_indent) const { std::vector out; for (auto& i : m_conn) { std::vector lines = i.xdmf(n_indent); for (auto& line : lines) { out.push_back(line); } } for (auto& i : m_coor) { std::vector lines = i.xdmf(n_indent); for (auto& line : lines) { out.push_back(line); } } for (auto& i : m_attr) { std::vector lines = i.xdmf(n_indent); for (auto& line : lines) { out.push_back(line); } } return out; } inline TimeSeries::TimeSeries(const std::vector& data) : m_data(data) { } inline void TimeSeries::push_back(const Increment& data) { m_data.push_back(data); } inline std::vector TimeSeries::xdmf(size_t n_indent) const { std::vector out; for (size_t inc = 0; inc < m_data.size(); ++inc) { out.push_back(""); out.push_back(indent(n_indent) + ")"); } return out; } inline void TimeSeries::write(const std::string& fname, size_t n_indent) const { std::ofstream myfile; myfile.open(fname); myfile << "" << std::endl; myfile << indent(n_indent) + "" << std::endl; - myfile << indent(n_indent * 2) - + "" - << std::endl; + myfile << indent(n_indent * 2) + + "" + << std::endl; std::vector lines = this->xdmf(n_indent); for (auto& line : lines) { myfile << indent(n_indent * 3) + line << std::endl; } myfile << indent(n_indent * 2) + "" << std::endl; myfile << indent(n_indent) + "" << std::endl; myfile << "" << std::endl; myfile.close(); } } // namespace HDF5 } // namespace ParaView } // namespace GooseFEM #endif diff --git a/include/GooseFEM/TyingsPeriodic.h b/include/GooseFEM/TyingsPeriodic.h index 8a225a1..4f3ced6 100644 --- a/include/GooseFEM/TyingsPeriodic.h +++ b/include/GooseFEM/TyingsPeriodic.h @@ -1,94 +1,94 @@ /* (c - GPLv3) T.W.J. de Geus (Tom) | tom@geus.me | www.geus.me | github.com/tdegeus/GooseFEM */ #ifndef GOOSEFEM_TYINGSPERIODIC_H #define GOOSEFEM_TYINGSPERIODIC_H #include "config.h" #include #include namespace GooseFEM { namespace Tyings { class Periodic { public: // Constructors Periodic() = default; Periodic( - const xt::xtensor& coor, - const xt::xtensor& dofs, - const xt::xtensor& control_dofs, - const xt::xtensor& nodal_tyings); // (independent, dependent) + const xt::xtensor& coor, + const xt::xtensor& dofs, + const xt::xtensor& control_dofs, + const xt::xtensor& nodal_tyings); // (independent, dependent) Periodic( - const xt::xtensor& coor, - const xt::xtensor& dofs, - const xt::xtensor& control_dofs, - const xt::xtensor& nodal_tyings, // (independent, dependent) - const xt::xtensor& iip); + const xt::xtensor& coor, + const xt::xtensor& dofs, + const xt::xtensor& control_dofs, + const xt::xtensor& nodal_tyings, // (independent, dependent) + const xt::xtensor& iip); // Dimensions size_t nnd() const; // dependent DOFs size_t nni() const; // independent DOFs size_t nnu() const; // independent, unknown DOFs size_t nnp() const; // independent, prescribed DOFs // DOF lists - xt::xtensor dofs() const; // DOFs - xt::xtensor control() const; // control DOFs - xt::xtensor iid() const; // dependent DOFs - xt::xtensor iii() const; // independent DOFs - xt::xtensor iiu() const; // independent, unknown DOFs - xt::xtensor iip() const; // independent, prescribed DOFs + xt::xtensor dofs() const; // DOFs + xt::xtensor control() const; // control DOFs + xt::xtensor iid() const; // dependent DOFs + xt::xtensor iii() const; // independent DOFs + xt::xtensor iiu() const; // independent, unknown DOFs + xt::xtensor iip() const; // independent, prescribed DOFs // Return the tying matrix // u_d = C_di * u_i // u_d = [C_du, C_dp]^T * [u_u, u_p] = C_du * u_u + C_dp * u_p Eigen::SparseMatrix Cdi() const; Eigen::SparseMatrix Cdu() const; Eigen::SparseMatrix Cdp() const; private: size_t m_nnu; size_t m_nnp; size_t m_nni; size_t m_nnd; size_t m_ndim; size_t m_nties; // number of nodal ties - xt::xtensor m_dofs; - xt::xtensor m_control; - xt::xtensor m_tyings; // nodal ties: (independent, dependent) - xt::xtensor m_coor; + xt::xtensor m_dofs; + xt::xtensor m_control; + xt::xtensor m_tyings; // nodal ties: (independent, dependent) + xt::xtensor m_coor; }; class Control { public: // Constructors Control() = default; - Control(const xt::xtensor& coor, const xt::xtensor& dofs); + Control(const xt::xtensor& coor, const xt::xtensor& dofs); // Extract new lists - xt::xtensor coor() const; - xt::xtensor dofs() const; - xt::xtensor controlDofs() const; - xt::xtensor controlNodes() const; + xt::xtensor coor() const; + xt::xtensor dofs() const; + xt::xtensor controlDofs() const; + xt::xtensor controlNodes() const; private: - xt::xtensor m_coor; - xt::xtensor m_dofs; - xt::xtensor m_control_dofs; - xt::xtensor m_control_nodes; + xt::xtensor m_coor; + xt::xtensor m_dofs; + xt::xtensor m_control_dofs; + xt::xtensor m_control_nodes; }; } // namespace Tyings } // namespace GooseFEM #include "TyingsPeriodic.hpp" #endif diff --git a/include/GooseFEM/TyingsPeriodic.hpp b/include/GooseFEM/TyingsPeriodic.hpp index 2f07df1..ddb3803 100644 --- a/include/GooseFEM/TyingsPeriodic.hpp +++ b/include/GooseFEM/TyingsPeriodic.hpp @@ -1,245 +1,239 @@ /* (c - GPLv3) T.W.J. de Geus (Tom) | tom@geus.me | www.geus.me | github.com/tdegeus/GooseFEM */ #ifndef GOOSEFEM_TYINGSPERIODIC_HPP #define GOOSEFEM_TYINGSPERIODIC_HPP #include "Mesh.h" #include "TyingsPeriodic.h" #include #include namespace GooseFEM { namespace Tyings { inline Periodic::Periodic( - const xt::xtensor& coor, - const xt::xtensor& dofs, - const xt::xtensor& control, - const xt::xtensor& nodal_tyings) + const xt::xtensor& coor, + const xt::xtensor& dofs, + const xt::xtensor& control, + const xt::xtensor& nodal_tyings) : Periodic(coor, dofs, control, nodal_tyings, xt::empty({0})) { } inline Periodic::Periodic( - const xt::xtensor& coor, - const xt::xtensor& dofs, - const xt::xtensor& control, - const xt::xtensor& nodal_tyings, - const xt::xtensor& iip) + const xt::xtensor& coor, + const xt::xtensor& dofs, + const xt::xtensor& control, + const xt::xtensor& nodal_tyings, + const xt::xtensor& iip) : m_tyings(nodal_tyings), m_coor(coor) { m_ndim = m_coor.shape(1); m_nties = m_tyings.shape(0); - xt::xtensor dependent = xt::view(m_tyings, xt::all(), 1); - xt::xtensor dependent_dofs = xt::view(dofs, xt::keep(dependent), xt::all()); - xt::xtensor iid = xt::flatten(dependent_dofs); - xt::xtensor iii = xt::setdiff1d(dofs, iid); - xt::xtensor iiu = xt::setdiff1d(iii, iip); + xt::xtensor dependent = xt::view(m_tyings, xt::all(), 1); + xt::xtensor dependent_dofs = xt::view(dofs, xt::keep(dependent), xt::all()); + xt::xtensor iid = xt::flatten(dependent_dofs); + xt::xtensor iii = xt::setdiff1d(dofs, iid); + xt::xtensor iiu = xt::setdiff1d(iii, iip); m_nnu = iiu.size(); m_nnp = iip.size(); m_nni = iii.size(); m_nnd = iid.size(); GooseFEM::Mesh::Reorder reorder({iiu, iip, iid}); m_dofs = reorder.apply(dofs); m_control = reorder.apply(control); } -inline xt::xtensor Periodic::dofs() const +inline xt::xtensor Periodic::dofs() const { return m_dofs; } -inline xt::xtensor Periodic::control() const +inline xt::xtensor Periodic::control() const { return m_control; } inline size_t Periodic::nnu() const { return m_nnu; } inline size_t Periodic::nnp() const { return m_nnp; } inline size_t Periodic::nni() const { return m_nni; } inline size_t Periodic::nnd() const { return m_nnd; } -inline xt::xtensor Periodic::iiu() const +inline xt::xtensor Periodic::iiu() const { return xt::arange(m_nnu); } -inline xt::xtensor Periodic::iip() const +inline xt::xtensor Periodic::iip() const { return xt::arange(m_nnp) + m_nnu; } -inline xt::xtensor Periodic::iii() const +inline xt::xtensor Periodic::iii() const { return xt::arange(m_nni); } -inline xt::xtensor Periodic::iid() const +inline xt::xtensor Periodic::iid() const { return xt::arange(m_nni, m_nni + m_nnd); } inline Eigen::SparseMatrix Periodic::Cdi() const { std::vector> data; data.reserve(m_nties * m_ndim * (m_ndim + 1)); for (size_t i = 0; i < m_nties; ++i) { for (size_t j = 0; j < m_ndim; ++j) { size_t ni = m_tyings(i, 0); size_t nd = m_tyings(i, 1); data.push_back(Eigen::Triplet(i * m_ndim + j, m_dofs(ni, j), +1.0)); for (size_t k = 0; k < m_ndim; ++k) { data.push_back(Eigen::Triplet( - i * m_ndim + j, - m_control(j, k), - m_coor(nd, k) - m_coor(ni, k))); + i * m_ndim + j, m_control(j, k), m_coor(nd, k) - m_coor(ni, k))); } } } Eigen::SparseMatrix Cdi; Cdi.resize(m_nnd, m_nni); Cdi.setFromTriplets(data.begin(), data.end()); return Cdi; } inline Eigen::SparseMatrix Periodic::Cdu() const { std::vector> data; data.reserve(m_nties * m_ndim * (m_ndim + 1)); for (size_t i = 0; i < m_nties; ++i) { for (size_t j = 0; j < m_ndim; ++j) { size_t ni = m_tyings(i, 0); size_t nd = m_tyings(i, 1); if (m_dofs(ni, j) < m_nnu) { data.push_back(Eigen::Triplet(i * m_ndim + j, m_dofs(ni, j), +1.0)); } for (size_t k = 0; k < m_ndim; ++k) { if (m_control(j, k) < m_nnu) { data.push_back(Eigen::Triplet( - i * m_ndim + j, - m_control(j, k), - m_coor(nd, k) - m_coor(ni, k))); + i * m_ndim + j, m_control(j, k), m_coor(nd, k) - m_coor(ni, k))); } } } } Eigen::SparseMatrix Cdu; Cdu.resize(m_nnd, m_nnu); Cdu.setFromTriplets(data.begin(), data.end()); return Cdu; } inline Eigen::SparseMatrix Periodic::Cdp() const { std::vector> data; data.reserve(m_nties * m_ndim * (m_ndim + 1)); for (size_t i = 0; i < m_nties; ++i) { for (size_t j = 0; j < m_ndim; ++j) { size_t ni = m_tyings(i, 0); size_t nd = m_tyings(i, 1); if (m_dofs(ni, j) >= m_nnu) { data.push_back(Eigen::Triplet(i * m_ndim + j, m_dofs(ni, j) - m_nnu, +1.0)); } for (size_t k = 0; k < m_ndim; ++k) { if (m_control(j, k) >= m_nnu) { data.push_back(Eigen::Triplet( - i * m_ndim + j, - m_control(j, k) - m_nnu, - m_coor(nd, k) - m_coor(ni, k))); + i * m_ndim + j, m_control(j, k) - m_nnu, m_coor(nd, k) - m_coor(ni, k))); } } } } Eigen::SparseMatrix Cdp; Cdp.resize(m_nnd, m_nnp); Cdp.setFromTriplets(data.begin(), data.end()); return Cdp; } -inline Control::Control(const xt::xtensor& coor, const xt::xtensor& dofs) +inline Control::Control(const xt::xtensor& coor, const xt::xtensor& dofs) : m_coor(coor), m_dofs(dofs) { GOOSEFEM_ASSERT(coor.shape().size() == 2); GOOSEFEM_ASSERT(coor.shape() == dofs.shape()); size_t nnode = coor.shape(0); size_t ndim = coor.shape(1); m_control_dofs = xt::arange(ndim * ndim).reshape({ndim, ndim}); m_control_dofs += xt::amax(dofs)[0] + 1; m_control_nodes = nnode + xt::arange(ndim); m_coor = xt::concatenate(xt::xtuple(coor, xt::zeros({ndim, ndim}))); m_dofs = xt::concatenate(xt::xtuple(dofs, m_control_dofs)); } -inline xt::xtensor Control::coor() const +inline xt::xtensor Control::coor() const { return m_coor; } -inline xt::xtensor Control::dofs() const +inline xt::xtensor Control::dofs() const { return m_dofs; } -inline xt::xtensor Control::controlDofs() const +inline xt::xtensor Control::controlDofs() const { return m_control_dofs; } -inline xt::xtensor Control::controlNodes() const +inline xt::xtensor Control::controlNodes() const { return m_control_nodes; } } // namespace Tyings } // namespace GooseFEM #endif diff --git a/include/GooseFEM/Vector.h b/include/GooseFEM/Vector.h index a20c339..ac34a8c 100644 --- a/include/GooseFEM/Vector.h +++ b/include/GooseFEM/Vector.h @@ -1,86 +1,86 @@ /* (c - GPLv3) T.W.J. de Geus (Tom) | tom@geus.me | www.geus.me | github.com/tdegeus/GooseFEM */ #ifndef GOOSEFEM_VECTOR_H #define GOOSEFEM_VECTOR_H #include "config.h" namespace GooseFEM { /* "nodevec" - nodal vectors - [nnode, ndim] "elemvec" - nodal vectors stored per element - [nelem, nne, ndim] "dofval" - DOF values - [ndof] */ class Vector { public: // Constructor Vector() = default; - Vector(const xt::xtensor& conn, const xt::xtensor& dofs); + Vector(const xt::xtensor& conn, const xt::xtensor& dofs); // Dimensions size_t nelem() const; // number of elements size_t nne() const; // number of nodes per element size_t nnode() const; // number of nodes size_t ndim() const; // number of dimensions size_t ndof() const; // number of DOFs // DOF lists - xt::xtensor dofs() const; // DOFs + xt::xtensor dofs() const; // DOFs // Copy nodevec to another nodevec - void copy(const xt::xtensor& nodevec_src, xt::xtensor& nodevec_dest) const; + void copy(const xt::xtensor& nodevec_src, xt::xtensor& nodevec_dest) const; // Convert to "dofval" (overwrite entries that occur more than once) -- (auto allocation below) - void asDofs(const xt::xtensor& nodevec, xt::xtensor& dofval) const; - void asDofs(const xt::xtensor& elemvec, xt::xtensor& dofval) const; + void asDofs(const xt::xtensor& nodevec, xt::xtensor& dofval) const; + void asDofs(const xt::xtensor& elemvec, xt::xtensor& dofval) const; // Convert to "nodevec" (overwrite entries that occur more than once) -- (auto allocation below) - void asNode(const xt::xtensor& dofval, xt::xtensor& nodevec) const; - void asNode(const xt::xtensor& elemvec, xt::xtensor& nodevec) const; + void asNode(const xt::xtensor& dofval, xt::xtensor& nodevec) const; + void asNode(const xt::xtensor& elemvec, xt::xtensor& nodevec) const; // Convert to "elemvec" (overwrite entries that occur more than once) -- (auto allocation below) - void asElement(const xt::xtensor& dofval, xt::xtensor& elemvec) const; - void asElement(const xt::xtensor& nodevec, xt::xtensor& elemvec) const; + void asElement(const xt::xtensor& dofval, xt::xtensor& elemvec) const; + void asElement(const xt::xtensor& nodevec, xt::xtensor& elemvec) const; // Assemble "dofval" (adds entries that occur more that once) -- (auto allocation below) - void assembleDofs(const xt::xtensor& nodevec, xt::xtensor& dofval) const; - void assembleDofs(const xt::xtensor& elemvec, xt::xtensor& dofval) const; + void assembleDofs(const xt::xtensor& nodevec, xt::xtensor& dofval) const; + void assembleDofs(const xt::xtensor& elemvec, xt::xtensor& dofval) const; // Assemble "nodevec" (adds entries that occur more that once) -- (auto allocation below) - void assembleNode(const xt::xtensor& elemvec, xt::xtensor& nodevec) const; + void assembleNode(const xt::xtensor& elemvec, xt::xtensor& nodevec) const; // Auto-allocation of the functions above - xt::xtensor AsDofs(const xt::xtensor& nodevec) const; - xt::xtensor AsDofs(const xt::xtensor& elemvec) const; - xt::xtensor AsNode(const xt::xtensor& dofval) const; - xt::xtensor AsNode(const xt::xtensor& elemvec) const; - xt::xtensor AsElement(const xt::xtensor& dofval) const; - xt::xtensor AsElement(const xt::xtensor& nodevec) const; - xt::xtensor AssembleDofs(const xt::xtensor& nodevec) const; - xt::xtensor AssembleDofs(const xt::xtensor& elemvec) const; - xt::xtensor AssembleNode(const xt::xtensor& elemvec) const; + xt::xtensor AsDofs(const xt::xtensor& nodevec) const; + xt::xtensor AsDofs(const xt::xtensor& elemvec) const; + xt::xtensor AsNode(const xt::xtensor& dofval) const; + xt::xtensor AsNode(const xt::xtensor& elemvec) const; + xt::xtensor AsElement(const xt::xtensor& dofval) const; + xt::xtensor AsElement(const xt::xtensor& nodevec) const; + xt::xtensor AssembleDofs(const xt::xtensor& nodevec) const; + xt::xtensor AssembleDofs(const xt::xtensor& elemvec) const; + xt::xtensor AssembleNode(const xt::xtensor& elemvec) const; private: // Bookkeeping - xt::xtensor m_conn; // connectivity [nelem, nne ] - xt::xtensor m_dofs; // DOF-numbers per node [nnode, ndim] + xt::xtensor m_conn; // connectivity [nelem, nne ] + xt::xtensor m_dofs; // DOF-numbers per node [nnode, ndim] // Dimensions size_t m_nelem; // number of elements size_t m_nne; // number of nodes per element size_t m_nnode; // number of nodes size_t m_ndim; // number of dimensions size_t m_ndof; // number of DOFs }; } // namespace GooseFEM #include "Vector.hpp" #endif diff --git a/include/GooseFEM/Vector.hpp b/include/GooseFEM/Vector.hpp index 7d38bf6..c6b2fb3 100644 --- a/include/GooseFEM/Vector.hpp +++ b/include/GooseFEM/Vector.hpp @@ -1,279 +1,280 @@ /* (c - GPLv3) T.W.J. de Geus (Tom) | tom@geus.me | www.geus.me | github.com/tdegeus/GooseFEM */ #ifndef GOOSEFEM_VECTOR_HPP #define GOOSEFEM_VECTOR_HPP #include "Vector.h" namespace GooseFEM { -inline Vector::Vector(const xt::xtensor& conn, const xt::xtensor& dofs) +inline Vector::Vector(const xt::xtensor& conn, const xt::xtensor& dofs) : m_conn(conn), m_dofs(dofs) { m_nelem = m_conn.shape(0); m_nne = m_conn.shape(1); m_nnode = m_dofs.shape(0); m_ndim = m_dofs.shape(1); m_ndof = xt::amax(m_dofs)[0] + 1; GOOSEFEM_ASSERT(xt::amax(m_conn)[0] + 1 == m_nnode); GOOSEFEM_ASSERT(m_ndof <= m_nnode * m_ndim); } inline size_t Vector::nelem() const { return m_nelem; } inline size_t Vector::nne() const { return m_nne; } inline size_t Vector::nnode() const { return m_nnode; } inline size_t Vector::ndim() const { return m_ndim; } inline size_t Vector::ndof() const { return m_ndof; } -inline xt::xtensor Vector::dofs() const +inline xt::xtensor Vector::dofs() const { return m_dofs; } inline void -Vector::copy(const xt::xtensor& nodevec_src, xt::xtensor& nodevec_dest) const +Vector::copy(const xt::xtensor& nodevec_src, xt::xtensor& nodevec_dest) const { GOOSEFEM_ASSERT( nodevec_src.shape() == std::decay_t::shape_type({m_nnode, m_ndim})); GOOSEFEM_ASSERT( - nodevec_dest.shape() == std::decay_t::shape_type({m_nnode,m_ndim})); + nodevec_dest.shape() == + std::decay_t::shape_type({m_nnode, m_ndim})); xt::noalias(nodevec_dest) = nodevec_src; } inline void -Vector::asDofs(const xt::xtensor& nodevec, xt::xtensor& dofval) const +Vector::asDofs(const xt::xtensor& nodevec, xt::xtensor& dofval) const { GOOSEFEM_ASSERT( nodevec.shape() == std::decay_t::shape_type({m_nnode, m_ndim})); GOOSEFEM_ASSERT(dofval.size() == m_ndof); #pragma omp parallel for for (size_t m = 0; m < m_nnode; ++m) { for (size_t i = 0; i < m_ndim; ++i) { dofval(m_dofs(m, i)) = nodevec(m, i); } } } inline void -Vector::asDofs(const xt::xtensor& elemvec, xt::xtensor& dofval) const +Vector::asDofs(const xt::xtensor& elemvec, xt::xtensor& dofval) const { GOOSEFEM_ASSERT( elemvec.shape() == std::decay_t::shape_type({m_nelem, m_nne, m_ndim})); GOOSEFEM_ASSERT(dofval.size() == m_ndof); #pragma omp parallel for for (size_t e = 0; e < m_nelem; ++e) { for (size_t m = 0; m < m_nne; ++m) { for (size_t i = 0; i < m_ndim; ++i) { dofval(m_dofs(m_conn(e, m), i)) = elemvec(e, m, i); } } } } inline void -Vector::asNode(const xt::xtensor& dofval, xt::xtensor& nodevec) const +Vector::asNode(const xt::xtensor& dofval, xt::xtensor& nodevec) const { GOOSEFEM_ASSERT(dofval.size() == m_ndof); GOOSEFEM_ASSERT( nodevec.shape() == std::decay_t::shape_type({m_nnode, m_ndim})); #pragma omp parallel for for (size_t m = 0; m < m_nnode; ++m) { for (size_t i = 0; i < m_ndim; ++i) { nodevec(m, i) = dofval(m_dofs(m, i)); } } } inline void -Vector::asNode(const xt::xtensor& elemvec, xt::xtensor& nodevec) const +Vector::asNode(const xt::xtensor& elemvec, xt::xtensor& nodevec) const { GOOSEFEM_ASSERT( elemvec.shape() == std::decay_t::shape_type({m_nelem, m_nne, m_ndim})); GOOSEFEM_ASSERT( nodevec.shape() == std::decay_t::shape_type({m_nnode, m_ndim})); #pragma omp parallel for for (size_t e = 0; e < m_nelem; ++e) { for (size_t m = 0; m < m_nne; ++m) { for (size_t i = 0; i < m_ndim; ++i) { nodevec(m_conn(e, m), i) = elemvec(e, m, i); } } } } inline void -Vector::asElement(const xt::xtensor& dofval, xt::xtensor& elemvec) const +Vector::asElement(const xt::xtensor& dofval, xt::xtensor& elemvec) const { GOOSEFEM_ASSERT(dofval.size() == m_ndof); GOOSEFEM_ASSERT( elemvec.shape() == std::decay_t::shape_type({m_nelem, m_nne, m_ndim})); #pragma omp parallel for for (size_t e = 0; e < m_nelem; ++e) { for (size_t m = 0; m < m_nne; ++m) { for (size_t i = 0; i < m_ndim; ++i) { elemvec(e, m, i) = dofval(m_dofs(m_conn(e, m), i)); } } } } inline void -Vector::asElement(const xt::xtensor& nodevec, xt::xtensor& elemvec) const +Vector::asElement(const xt::xtensor& nodevec, xt::xtensor& elemvec) const { GOOSEFEM_ASSERT( nodevec.shape() == std::decay_t::shape_type({m_nnode, m_ndim})); GOOSEFEM_ASSERT( elemvec.shape() == std::decay_t::shape_type({m_nelem, m_nne, m_ndim})); #pragma omp parallel for for (size_t e = 0; e < m_nelem; ++e) { for (size_t m = 0; m < m_nne; ++m) { for (size_t i = 0; i < m_ndim; ++i) { elemvec(e, m, i) = nodevec(m_conn(e, m), i); } } } } inline void -Vector::assembleDofs(const xt::xtensor& nodevec, xt::xtensor& dofval) const +Vector::assembleDofs(const xt::xtensor& nodevec, xt::xtensor& dofval) const { GOOSEFEM_ASSERT( nodevec.shape() == std::decay_t::shape_type({m_nnode, m_ndim})); GOOSEFEM_ASSERT(dofval.size() == m_ndof); dofval.fill(0.0); for (size_t m = 0; m < m_nnode; ++m) { for (size_t i = 0; i < m_ndim; ++i) { dofval(m_dofs(m, i)) += nodevec(m, i); } } } inline void -Vector::assembleDofs(const xt::xtensor& elemvec, xt::xtensor& dofval) const +Vector::assembleDofs(const xt::xtensor& elemvec, xt::xtensor& dofval) const { GOOSEFEM_ASSERT( elemvec.shape() == std::decay_t::shape_type({m_nelem, m_nne, m_ndim})); GOOSEFEM_ASSERT(dofval.size() == m_ndof); dofval.fill(0.0); for (size_t e = 0; e < m_nelem; ++e) { for (size_t m = 0; m < m_nne; ++m) { for (size_t i = 0; i < m_ndim; ++i) { dofval(m_dofs(m_conn(e, m), i)) += elemvec(e, m, i); } } } } inline void -Vector::assembleNode(const xt::xtensor& elemvec, xt::xtensor& nodevec) const +Vector::assembleNode(const xt::xtensor& elemvec, xt::xtensor& nodevec) const { GOOSEFEM_ASSERT( elemvec.shape() == std::decay_t::shape_type({m_nelem, m_nne, m_ndim})); GOOSEFEM_ASSERT( nodevec.shape() == std::decay_t::shape_type({m_nnode, m_ndim})); - xt::xtensor dofval = this->AssembleDofs(elemvec); + xt::xtensor dofval = this->AssembleDofs(elemvec); this->asNode(dofval, nodevec); } -inline xt::xtensor Vector::AsDofs(const xt::xtensor& nodevec) const +inline xt::xtensor Vector::AsDofs(const xt::xtensor& nodevec) const { - xt::xtensor dofval = xt::empty({m_ndof}); + xt::xtensor dofval = xt::empty({m_ndof}); this->asDofs(nodevec, dofval); return dofval; } -inline xt::xtensor Vector::AsDofs(const xt::xtensor& elemvec) const +inline xt::xtensor Vector::AsDofs(const xt::xtensor& elemvec) const { - xt::xtensor dofval = xt::empty({m_ndof}); + xt::xtensor dofval = xt::empty({m_ndof}); this->asDofs(elemvec, dofval); return dofval; } -inline xt::xtensor Vector::AsNode(const xt::xtensor& dofval) const +inline xt::xtensor Vector::AsNode(const xt::xtensor& dofval) const { - xt::xtensor nodevec = xt::empty({m_nnode, m_ndim}); + xt::xtensor nodevec = xt::empty({m_nnode, m_ndim}); this->asNode(dofval, nodevec); return nodevec; } -inline xt::xtensor Vector::AsNode(const xt::xtensor& elemvec) const +inline xt::xtensor Vector::AsNode(const xt::xtensor& elemvec) const { - xt::xtensor nodevec = xt::empty({m_nnode, m_ndim}); + xt::xtensor nodevec = xt::empty({m_nnode, m_ndim}); this->asNode(elemvec, nodevec); return nodevec; } -inline xt::xtensor Vector::AsElement(const xt::xtensor& dofval) const +inline xt::xtensor Vector::AsElement(const xt::xtensor& dofval) const { - xt::xtensor elemvec = xt::empty({m_nelem, m_nne, m_ndim}); + xt::xtensor elemvec = xt::empty({m_nelem, m_nne, m_ndim}); this->asElement(dofval, elemvec); return elemvec; } -inline xt::xtensor Vector::AsElement(const xt::xtensor& nodevec) const +inline xt::xtensor Vector::AsElement(const xt::xtensor& nodevec) const { - xt::xtensor elemvec = xt::empty({m_nelem, m_nne, m_ndim}); + xt::xtensor elemvec = xt::empty({m_nelem, m_nne, m_ndim}); this->asElement(nodevec, elemvec); return elemvec; } -inline xt::xtensor Vector::AssembleDofs(const xt::xtensor& nodevec) const +inline xt::xtensor Vector::AssembleDofs(const xt::xtensor& nodevec) const { - xt::xtensor dofval = xt::empty({m_ndof}); + xt::xtensor dofval = xt::empty({m_ndof}); this->assembleDofs(nodevec, dofval); return dofval; } -inline xt::xtensor Vector::AssembleDofs(const xt::xtensor& elemvec) const +inline xt::xtensor Vector::AssembleDofs(const xt::xtensor& elemvec) const { - xt::xtensor dofval = xt::empty({m_ndof}); + xt::xtensor dofval = xt::empty({m_ndof}); this->assembleDofs(elemvec, dofval); return dofval; } -inline xt::xtensor Vector::AssembleNode(const xt::xtensor& elemvec) const +inline xt::xtensor Vector::AssembleNode(const xt::xtensor& elemvec) const { - xt::xtensor nodevec = xt::empty({m_nnode, m_ndim}); + xt::xtensor nodevec = xt::empty({m_nnode, m_ndim}); this->assembleNode(elemvec, nodevec); return nodevec; } } // namespace GooseFEM #endif diff --git a/include/GooseFEM/VectorPartitioned.h b/include/GooseFEM/VectorPartitioned.h index 86142d6..3b6ee05 100644 --- a/include/GooseFEM/VectorPartitioned.h +++ b/include/GooseFEM/VectorPartitioned.h @@ -1,187 +1,169 @@ /* (c - GPLv3) T.W.J. de Geus (Tom) | tom@geus.me | www.geus.me | github.com/tdegeus/GooseFEM */ #ifndef GOOSEFEM_VECTORPARTITIONED_H #define GOOSEFEM_VECTORPARTITIONED_H #include "config.h" namespace GooseFEM { /* "nodevec" - nodal vectors - [nnode, ndim] "elemvec" - nodal vectors stored per element - [nelem, nne, ndim] "dofval" - DOF values - [ndof] "dofval_u" - DOF values (Unknown) "== dofval[iiu]" - [nnu] "dofval_p" - DOF values (Prescribed) "== dofval[iiu]" - [nnp] */ class VectorPartitioned { public: // Constructor VectorPartitioned() = default; VectorPartitioned( - const xt::xtensor& conn, - const xt::xtensor& dofs, - const xt::xtensor& iip); + const xt::xtensor& conn, + const xt::xtensor& dofs, + const xt::xtensor& iip); // Dimensions size_t nelem() const; // number of elements size_t nne() const; // number of nodes per element size_t nnode() const; // number of nodes size_t ndim() const; // number of dimensions size_t ndof() const; // number of DOFs size_t nnu() const; // number of unknown DOFs size_t nnp() const; // number of prescribed DOFs // DOF lists - xt::xtensor dofs() const; // DOFs - xt::xtensor iiu() const; // unknown DOFs - xt::xtensor iip() const; // prescribed DOFs + xt::xtensor dofs() const; // DOFs + xt::xtensor iiu() const; // unknown DOFs + xt::xtensor iip() const; // prescribed DOFs // Copy (part of) nodevec/dofval to another nodevec/dofval void copy( - const xt::xtensor& nodevec_src, - xt::xtensor& nodevec_dest) const; + const xt::xtensor& nodevec_src, xt::xtensor& nodevec_dest) const; void copy_u( - const xt::xtensor& nodevec_src, - xt::xtensor& nodevec_dest) const; // "iiu" updated + const xt::xtensor& nodevec_src, xt::xtensor& nodevec_dest) const; // "iiu" updated void copy_p( - const xt::xtensor& nodevec_src, - xt::xtensor& nodevec_dest) const; // "iip" updated + const xt::xtensor& nodevec_src, xt::xtensor& nodevec_dest) const; // "iip" updated // Convert to "dofval" (overwrite entries that occur more than once) void asDofs( - const xt::xtensor& dofval_u, - const xt::xtensor& dofval_p, - xt::xtensor& dofval) const; - - void asDofs(const xt::xtensor& nodevec, xt::xtensor& dofval) const; - void asDofs(const xt::xtensor& elemvec, xt::xtensor& dofval) const; - void asDofs_u(const xt::xtensor& dofval, xt::xtensor& dofval_u) const; - void asDofs_u(const xt::xtensor& nodevec, xt::xtensor& dofval_u) const; - void asDofs_u(const xt::xtensor& elemvec, xt::xtensor& dofval_u) const; - void asDofs_p(const xt::xtensor& dofval, xt::xtensor& dofval_p) const; - void asDofs_p(const xt::xtensor& nodevec, xt::xtensor& dofval_p) const; - void asDofs_p(const xt::xtensor& elemvec, xt::xtensor& dofval_p) const; + const xt::xtensor& dofval_u, + const xt::xtensor& dofval_p, + xt::xtensor& dofval) const; + + void asDofs(const xt::xtensor& nodevec, xt::xtensor& dofval) const; + void asDofs(const xt::xtensor& elemvec, xt::xtensor& dofval) const; + void asDofs_u(const xt::xtensor& dofval, xt::xtensor& dofval_u) const; + void asDofs_u(const xt::xtensor& nodevec, xt::xtensor& dofval_u) const; + void asDofs_u(const xt::xtensor& elemvec, xt::xtensor& dofval_u) const; + void asDofs_p(const xt::xtensor& dofval, xt::xtensor& dofval_p) const; + void asDofs_p(const xt::xtensor& nodevec, xt::xtensor& dofval_p) const; + void asDofs_p(const xt::xtensor& elemvec, xt::xtensor& dofval_p) const; // Convert to "nodevec" (overwrite entries that occur more than once) -- (auto allocation below) void asNode( - const xt::xtensor& dofval_u, - const xt::xtensor& dofval_p, - xt::xtensor& nodevec) const; + const xt::xtensor& dofval_u, + const xt::xtensor& dofval_p, + xt::xtensor& nodevec) const; - void asNode(const xt::xtensor& dofval, xt::xtensor& nodevec) const; + void asNode(const xt::xtensor& dofval, xt::xtensor& nodevec) const; - void asNode(const xt::xtensor& elemvec, xt::xtensor& nodevec) const; + void asNode(const xt::xtensor& elemvec, xt::xtensor& nodevec) const; // Convert to "elemvec" (overwrite entries that occur more than once) -- (auto allocation below) void asElement( - const xt::xtensor& dofval_u, - const xt::xtensor& dofval_p, - xt::xtensor& elemvec) const; + const xt::xtensor& dofval_u, + const xt::xtensor& dofval_p, + xt::xtensor& elemvec) const; - void asElement(const xt::xtensor& dofval, xt::xtensor& elemvec) const; - void asElement(const xt::xtensor& nodevec, xt::xtensor& elemvec) const; + void asElement(const xt::xtensor& dofval, xt::xtensor& elemvec) const; + void asElement(const xt::xtensor& nodevec, xt::xtensor& elemvec) const; // Assemble "dofval" (adds entries that occur more that once) -- (auto allocation below) - void assembleDofs(const xt::xtensor& nodevec, xt::xtensor& dofval) const; - void assembleDofs(const xt::xtensor& elemvec, xt::xtensor& dofval) const; - - void assembleDofs_u( - const xt::xtensor& nodevec, - xt::xtensor& dofval_u) const; - - void assembleDofs_u( - const xt::xtensor& elemvec, - xt::xtensor& dofval_u) const; - - void assembleDofs_p( - const xt::xtensor& nodevec, - xt::xtensor& dofval_p) const; - - void assembleDofs_p( - const xt::xtensor& elemvec, - xt::xtensor& dofval_p) const; + void assembleDofs(const xt::xtensor& nodevec, xt::xtensor& dofval) const; + void assembleDofs(const xt::xtensor& elemvec, xt::xtensor& dofval) const; + void assembleDofs_u(const xt::xtensor& nodevec, xt::xtensor& dofval_u) const; + void assembleDofs_u(const xt::xtensor& elemvec, xt::xtensor& dofval_u) const; + void assembleDofs_p(const xt::xtensor& nodevec, xt::xtensor& dofval_p) const; + void assembleDofs_p(const xt::xtensor& elemvec, xt::xtensor& dofval_p) const; // Assemble "nodevec" (adds entries that occur more that once) -- (auto allocation below) - void assembleNode(const xt::xtensor& elemvec, xt::xtensor& nodevec) const; + void assembleNode(const xt::xtensor& elemvec, xt::xtensor& nodevec) const; // Auto-allocation of the functions above - xt::xtensor AsDofs( - const xt::xtensor& dofval_u, - const xt::xtensor& dofval_p) const; - - xt::xtensor AsDofs(const xt::xtensor& nodevec) const; - xt::xtensor AsDofs(const xt::xtensor& elemvec) const; - xt::xtensor AsDofs_u(const xt::xtensor& dofval) const; - xt::xtensor AsDofs_u(const xt::xtensor& nodevec) const; - xt::xtensor AsDofs_u(const xt::xtensor& elemvec) const; - xt::xtensor AsDofs_p(const xt::xtensor& dofval) const; - xt::xtensor AsDofs_p(const xt::xtensor& nodevec) const; - xt::xtensor AsDofs_p(const xt::xtensor& elemvec) const; - - xt::xtensor AsNode( - const xt::xtensor& dofval_u, - const xt::xtensor& dofval_p) const; - - xt::xtensor AsNode(const xt::xtensor& dofval) const; - xt::xtensor AsNode(const xt::xtensor& elemvec) const; - - xt::xtensor AsElement( - const xt::xtensor& dofval_u, - const xt::xtensor& dofval_p) const; - - xt::xtensor AsElement(const xt::xtensor& dofval) const; - xt::xtensor AsElement(const xt::xtensor& nodevec) const; - xt::xtensor AssembleDofs(const xt::xtensor& nodevec) const; - xt::xtensor AssembleDofs(const xt::xtensor& elemvec) const; - xt::xtensor AssembleDofs_u(const xt::xtensor& nodevec) const; - xt::xtensor AssembleDofs_u(const xt::xtensor& elemvec) const; - xt::xtensor AssembleDofs_p(const xt::xtensor& nodevec) const; - xt::xtensor AssembleDofs_p(const xt::xtensor& elemvec) const; - xt::xtensor AssembleNode(const xt::xtensor& elemvec) const; - - xt::xtensor Copy( - const xt::xtensor& nodevec_src, - const xt::xtensor& nodevec_dest) const; - - xt::xtensor Copy_u( - const xt::xtensor& nodevec_src, - const xt::xtensor& nodevec_dest) const; - - xt::xtensor Copy_p( - const xt::xtensor& nodevec_src, - const xt::xtensor& nodevec_dest) const; + xt::xtensor AsDofs( + const xt::xtensor& dofval_u, const xt::xtensor& dofval_p) const; + + xt::xtensor AsDofs(const xt::xtensor& nodevec) const; + xt::xtensor AsDofs(const xt::xtensor& elemvec) const; + xt::xtensor AsDofs_u(const xt::xtensor& dofval) const; + xt::xtensor AsDofs_u(const xt::xtensor& nodevec) const; + xt::xtensor AsDofs_u(const xt::xtensor& elemvec) const; + xt::xtensor AsDofs_p(const xt::xtensor& dofval) const; + xt::xtensor AsDofs_p(const xt::xtensor& nodevec) const; + xt::xtensor AsDofs_p(const xt::xtensor& elemvec) const; + + xt::xtensor AsNode( + const xt::xtensor& dofval_u, const xt::xtensor& dofval_p) const; + + xt::xtensor AsNode(const xt::xtensor& dofval) const; + xt::xtensor AsNode(const xt::xtensor& elemvec) const; + + xt::xtensor AsElement( + const xt::xtensor& dofval_u, const xt::xtensor& dofval_p) const; + + xt::xtensor AsElement(const xt::xtensor& dofval) const; + xt::xtensor AsElement(const xt::xtensor& nodevec) const; + xt::xtensor AssembleDofs(const xt::xtensor& nodevec) const; + xt::xtensor AssembleDofs(const xt::xtensor& elemvec) const; + xt::xtensor AssembleDofs_u(const xt::xtensor& nodevec) const; + xt::xtensor AssembleDofs_u(const xt::xtensor& elemvec) const; + xt::xtensor AssembleDofs_p(const xt::xtensor& nodevec) const; + xt::xtensor AssembleDofs_p(const xt::xtensor& elemvec) const; + xt::xtensor AssembleNode(const xt::xtensor& elemvec) const; + + xt::xtensor Copy( + const xt::xtensor& nodevec_src, + const xt::xtensor& nodevec_dest) const; + + xt::xtensor Copy_u( + const xt::xtensor& nodevec_src, + const xt::xtensor& nodevec_dest) const; + + xt::xtensor Copy_p( + const xt::xtensor& nodevec_src, + const xt::xtensor& nodevec_dest) const; private: // Bookkeeping - xt::xtensor m_conn; // connectivity [nelem, nne ] - xt::xtensor m_dofs; // DOF-numbers per node [nnode, ndim] - xt::xtensor m_iiu; // DOF-numbers that are unknown [nnu] - xt::xtensor m_iip; // DOF-numbers that are prescribed [nnp] + xt::xtensor m_conn; // connectivity [nelem, nne ] + xt::xtensor m_dofs; // DOF-numbers per node [nnode, ndim] + xt::xtensor m_iiu; // DOF-numbers that are unknown [nnu] + xt::xtensor m_iip; // DOF-numbers that are prescribed [nnp] // DOFs per node, such that iiu = arange(nnu), iip = nnu + arange(nnp) - xt::xtensor m_part; + xt::xtensor m_part; // Dimensions size_t m_nelem; // number of elements size_t m_nne; // number of nodes per element size_t m_nnode; // number of nodes size_t m_ndim; // number of dimensions size_t m_ndof; // number of DOFs size_t m_nnu; // number of unknown DOFs size_t m_nnp; // number of prescribed DOFs }; } // namespace GooseFEM #include "VectorPartitioned.hpp" #endif diff --git a/include/GooseFEM/VectorPartitioned.hpp b/include/GooseFEM/VectorPartitioned.hpp index 48f035b..9a2a700 100644 --- a/include/GooseFEM/VectorPartitioned.hpp +++ b/include/GooseFEM/VectorPartitioned.hpp @@ -1,718 +1,720 @@ /* (c - GPLv3) T.W.J. de Geus (Tom) | tom@geus.me | www.geus.me | github.com/tdegeus/GooseFEM */ #ifndef GOOSEFEM_VECTORPARTITIONED_HPP #define GOOSEFEM_VECTORPARTITIONED_HPP #include "Mesh.h" #include "VectorPartitioned.h" namespace GooseFEM { inline VectorPartitioned::VectorPartitioned( - const xt::xtensor& conn, - const xt::xtensor& dofs, - const xt::xtensor& iip) + const xt::xtensor& conn, + const xt::xtensor& dofs, + const xt::xtensor& iip) : m_conn(conn), m_dofs(dofs), m_iip(iip) { m_nelem = m_conn.shape(0); m_nne = m_conn.shape(1); m_nnode = m_dofs.shape(0); m_ndim = m_dofs.shape(1); m_iiu = xt::setdiff1d(dofs, iip); m_ndof = xt::amax(m_dofs)[0] + 1; m_nnp = m_iip.size(); m_nnu = m_iiu.size(); m_part = Mesh::Reorder({m_iiu, m_iip}).get(m_dofs); GOOSEFEM_ASSERT(xt::amax(m_conn)[0] + 1 == m_nnode); GOOSEFEM_ASSERT(xt::amax(m_iip)[0] <= xt::amax(m_dofs)[0]); GOOSEFEM_ASSERT(m_ndof <= m_nnode * m_ndim); } inline size_t VectorPartitioned::nelem() const { return m_nelem; } inline size_t VectorPartitioned::nne() const { return m_nne; } inline size_t VectorPartitioned::nnode() const { return m_nnode; } inline size_t VectorPartitioned::ndim() const { return m_ndim; } inline size_t VectorPartitioned::ndof() const { return m_ndof; } inline size_t VectorPartitioned::nnu() const { return m_nnu; } inline size_t VectorPartitioned::nnp() const { return m_nnp; } -inline xt::xtensor VectorPartitioned::dofs() const +inline xt::xtensor VectorPartitioned::dofs() const { return m_dofs; } -inline xt::xtensor VectorPartitioned::iiu() const +inline xt::xtensor VectorPartitioned::iiu() const { return m_iiu; } -inline xt::xtensor VectorPartitioned::iip() const +inline xt::xtensor VectorPartitioned::iip() const { return m_iip; } inline void VectorPartitioned::copy( - const xt::xtensor& nodevec_src, xt::xtensor& nodevec_dest) const + const xt::xtensor& nodevec_src, xt::xtensor& nodevec_dest) const { GOOSEFEM_ASSERT( nodevec_src.shape() == std::decay_t::shape_type({m_nnode, m_ndim})); GOOSEFEM_ASSERT( - nodevec_dest.shape() == std::decay_t::shape_type({m_nnode,m_ndim})); + nodevec_dest.shape() == + std::decay_t::shape_type({m_nnode, m_ndim})); xt::noalias(nodevec_dest) = nodevec_src; } inline void VectorPartitioned::copy_u( - const xt::xtensor& nodevec_src, xt::xtensor& nodevec_dest) const + const xt::xtensor& nodevec_src, xt::xtensor& nodevec_dest) const { GOOSEFEM_ASSERT( nodevec_src.shape() == std::decay_t::shape_type({m_nnode, m_ndim})); GOOSEFEM_ASSERT( - nodevec_dest.shape() == std::decay_t::shape_type({m_nnode,m_ndim})); + nodevec_dest.shape() == + std::decay_t::shape_type({m_nnode, m_ndim})); #pragma omp parallel for for (size_t m = 0; m < m_nnode; ++m) { for (size_t i = 0; i < m_ndim; ++i) { if (m_part(m, i) < m_nnu) { nodevec_dest(m, i) = nodevec_src(m, i); } } } } inline void VectorPartitioned::copy_p( - const xt::xtensor& nodevec_src, xt::xtensor& nodevec_dest) const + const xt::xtensor& nodevec_src, xt::xtensor& nodevec_dest) const { GOOSEFEM_ASSERT( nodevec_src.shape() == std::decay_t::shape_type({m_nnode, m_ndim})); GOOSEFEM_ASSERT( nodevec_dest.shape() == std::decay_t::shape_type({m_nnode, m_ndim})); #pragma omp parallel for for (size_t m = 0; m < m_nnode; ++m) { for (size_t i = 0; i < m_ndim; ++i) { if (m_part(m, i) >= m_nnu) { nodevec_dest(m, i) = nodevec_src(m, i); } } } } inline void VectorPartitioned::asDofs( - const xt::xtensor& dofval_u, - const xt::xtensor& dofval_p, - xt::xtensor& dofval) const + const xt::xtensor& dofval_u, + const xt::xtensor& dofval_p, + xt::xtensor& dofval) const { GOOSEFEM_ASSERT(dofval_u.size() == m_nnu); GOOSEFEM_ASSERT(dofval_p.size() == m_nnp); GOOSEFEM_ASSERT(dofval.size() == m_ndof); #pragma omp parallel for for (size_t d = 0; d < m_nnu; ++d) { dofval(m_iiu(d)) = dofval_u(d); } #pragma omp parallel for for (size_t d = 0; d < m_nnp; ++d) { dofval(m_iip(d)) = dofval_p(d); } } inline void VectorPartitioned::asDofs( - const xt::xtensor& nodevec, xt::xtensor& dofval) const + const xt::xtensor& nodevec, xt::xtensor& dofval) const { GOOSEFEM_ASSERT( nodevec.shape() == std::decay_t::shape_type({m_nnode, m_ndim})); GOOSEFEM_ASSERT(dofval.size() == m_ndof); #pragma omp parallel for for (size_t m = 0; m < m_nnode; ++m) { for (size_t i = 0; i < m_ndim; ++i) { dofval(m_dofs(m, i)) = nodevec(m, i); } } } inline void VectorPartitioned::asDofs_u( - const xt::xtensor& dofval, xt::xtensor& dofval_u) const + const xt::xtensor& dofval, xt::xtensor& dofval_u) const { GOOSEFEM_ASSERT(dofval.size() == m_ndof); GOOSEFEM_ASSERT(dofval_u.size() == m_nnu); #pragma omp parallel for for (size_t d = 0; d < m_nnu; ++d) { dofval_u(d) = dofval(m_iiu(d)); } } inline void VectorPartitioned::asDofs_u( - const xt::xtensor& nodevec, xt::xtensor& dofval_u) const + const xt::xtensor& nodevec, xt::xtensor& dofval_u) const { GOOSEFEM_ASSERT( nodevec.shape() == std::decay_t::shape_type({m_nnode, m_ndim})); GOOSEFEM_ASSERT(dofval_u.size() == m_nnu); #pragma omp parallel for for (size_t m = 0; m < m_nnode; ++m) { for (size_t i = 0; i < m_ndim; ++i) { if (m_part(m, i) < m_nnu) { dofval_u(m_part(m, i)) = nodevec(m, i); } } } } inline void VectorPartitioned::asDofs_p( - const xt::xtensor& dofval, xt::xtensor& dofval_p) const + const xt::xtensor& dofval, xt::xtensor& dofval_p) const { GOOSEFEM_ASSERT(dofval.size() == m_ndof); GOOSEFEM_ASSERT(dofval_p.size() == m_nnp); #pragma omp parallel for for (size_t d = 0; d < m_nnp; ++d) { dofval_p(d) = dofval(m_iip(d)); } } inline void VectorPartitioned::asDofs_p( - const xt::xtensor& nodevec, xt::xtensor& dofval_p) const + const xt::xtensor& nodevec, xt::xtensor& dofval_p) const { GOOSEFEM_ASSERT( nodevec.shape() == std::decay_t::shape_type({m_nnode, m_ndim})); GOOSEFEM_ASSERT(dofval_p.size() == m_nnp); #pragma omp parallel for for (size_t m = 0; m < m_nnode; ++m) { for (size_t i = 0; i < m_ndim; ++i) { if (m_part(m, i) >= m_nnu) { dofval_p(m_part(m, i) - m_nnu) = nodevec(m, i); } } } } inline void VectorPartitioned::asDofs( - const xt::xtensor& elemvec, xt::xtensor& dofval) const + const xt::xtensor& elemvec, xt::xtensor& dofval) const { GOOSEFEM_ASSERT( elemvec.shape() == std::decay_t::shape_type({m_nelem, m_nne, m_ndim})); GOOSEFEM_ASSERT(dofval.size() == m_ndof); #pragma omp parallel for for (size_t e = 0; e < m_nelem; ++e) { for (size_t m = 0; m < m_nne; ++m) { for (size_t i = 0; i < m_ndim; ++i) { dofval(m_dofs(m_conn(e, m), i)) = elemvec(e, m, i); } } } } inline void VectorPartitioned::asDofs_u( - const xt::xtensor& elemvec, xt::xtensor& dofval_u) const + const xt::xtensor& elemvec, xt::xtensor& dofval_u) const { GOOSEFEM_ASSERT( elemvec.shape() == std::decay_t::shape_type({m_nelem, m_nne, m_ndim})); GOOSEFEM_ASSERT(dofval_u.size() == m_nnu); #pragma omp parallel for for (size_t e = 0; e < m_nelem; ++e) { for (size_t m = 0; m < m_nne; ++m) { for (size_t i = 0; i < m_ndim; ++i) { if (m_part(m_conn(e, m), i) < m_nnu) { dofval_u(m_part(m_conn(e, m), i)) = elemvec(e, m, i); } } } } } inline void VectorPartitioned::asDofs_p( - const xt::xtensor& elemvec, xt::xtensor& dofval_p) const + const xt::xtensor& elemvec, xt::xtensor& dofval_p) const { GOOSEFEM_ASSERT( elemvec.shape() == std::decay_t::shape_type({m_nelem, m_nne, m_ndim})); GOOSEFEM_ASSERT(dofval_p.size() == m_nnp); #pragma omp parallel for for (size_t e = 0; e < m_nelem; ++e) { for (size_t m = 0; m < m_nne; ++m) { for (size_t i = 0; i < m_ndim; ++i) { if (m_part(m_conn(e, m), i) >= m_nnu) { dofval_p(m_part(m_conn(e, m), i) - m_nnu) = elemvec(e, m, i); } } } } } inline void VectorPartitioned::asNode( - const xt::xtensor& dofval, xt::xtensor& nodevec) const + const xt::xtensor& dofval, xt::xtensor& nodevec) const { GOOSEFEM_ASSERT(dofval.size() == m_ndof); GOOSEFEM_ASSERT( nodevec.shape() == std::decay_t::shape_type({m_nnode, m_ndim})); #pragma omp parallel for for (size_t m = 0; m < m_nnode; ++m) { for (size_t i = 0; i < m_ndim; ++i) { nodevec(m, i) = dofval(m_dofs(m, i)); } } } inline void VectorPartitioned::asNode( - const xt::xtensor& dofval_u, - const xt::xtensor& dofval_p, - xt::xtensor& nodevec) const + const xt::xtensor& dofval_u, + const xt::xtensor& dofval_p, + xt::xtensor& nodevec) const { GOOSEFEM_ASSERT(dofval_u.size() == m_nnu); GOOSEFEM_ASSERT(dofval_p.size() == m_nnp); GOOSEFEM_ASSERT( nodevec.shape() == std::decay_t::shape_type({m_nnode, m_ndim})); #pragma omp parallel for for (size_t m = 0; m < m_nnode; ++m) { for (size_t i = 0; i < m_ndim; ++i) { if (m_part(m, i) < m_nnu) { nodevec(m, i) = dofval_u(m_part(m, i)); } else { nodevec(m, i) = dofval_p(m_part(m, i) - m_nnu); } } } } inline void VectorPartitioned::asNode( - const xt::xtensor& elemvec, xt::xtensor& nodevec) const + const xt::xtensor& elemvec, xt::xtensor& nodevec) const { GOOSEFEM_ASSERT( elemvec.shape() == std::decay_t::shape_type({m_nelem, m_nne, m_ndim})); GOOSEFEM_ASSERT( nodevec.shape() == std::decay_t::shape_type({m_nnode, m_ndim})); #pragma omp parallel for for (size_t e = 0; e < m_nelem; ++e) { for (size_t m = 0; m < m_nne; ++m) { for (size_t i = 0; i < m_ndim; ++i) { nodevec(m_conn(e, m), i) = elemvec(e, m, i); } } } } inline void VectorPartitioned::asElement( - const xt::xtensor& dofval, xt::xtensor& elemvec) const + const xt::xtensor& dofval, xt::xtensor& elemvec) const { GOOSEFEM_ASSERT(dofval.size() == m_ndof); GOOSEFEM_ASSERT( elemvec.shape() == std::decay_t::shape_type({m_nelem, m_nne, m_ndim})); #pragma omp parallel for for (size_t e = 0; e < m_nelem; ++e) { for (size_t m = 0; m < m_nne; ++m) { for (size_t i = 0; i < m_ndim; ++i) { elemvec(e, m, i) = dofval(m_dofs(m_conn(e, m), i)); } } } } inline void VectorPartitioned::asElement( - const xt::xtensor& dofval_u, - const xt::xtensor& dofval_p, - xt::xtensor& elemvec) const + const xt::xtensor& dofval_u, + const xt::xtensor& dofval_p, + xt::xtensor& elemvec) const { GOOSEFEM_ASSERT(dofval_u.size() == m_nnu); GOOSEFEM_ASSERT(dofval_p.size() == m_nnp); GOOSEFEM_ASSERT( elemvec.shape() == std::decay_t::shape_type({m_nelem, m_nne, m_ndim})); #pragma omp parallel for for (size_t e = 0; e < m_nelem; ++e) { for (size_t m = 0; m < m_nne; ++m) { for (size_t i = 0; i < m_ndim; ++i) { if (m_part(m_conn(e, m), i) < m_nnu) { elemvec(e, m, i) = dofval_u(m_part(m_conn(e, m), i)); } else { elemvec(e, m, i) = dofval_p(m_part(m_conn(e, m), i) - m_nnu); } } } } } inline void VectorPartitioned::asElement( - const xt::xtensor& nodevec, xt::xtensor& elemvec) const + const xt::xtensor& nodevec, xt::xtensor& elemvec) const { GOOSEFEM_ASSERT( nodevec.shape() == std::decay_t::shape_type({m_nnode, m_ndim})); GOOSEFEM_ASSERT( elemvec.shape() == std::decay_t::shape_type({m_nelem, m_nne, m_ndim})); #pragma omp parallel for for (size_t e = 0; e < m_nelem; ++e) { for (size_t m = 0; m < m_nne; ++m) { for (size_t i = 0; i < m_ndim; ++i) { elemvec(e, m, i) = nodevec(m_conn(e, m), i); } } } } inline void VectorPartitioned::assembleDofs( - const xt::xtensor& nodevec, xt::xtensor& dofval) const + const xt::xtensor& nodevec, xt::xtensor& dofval) const { GOOSEFEM_ASSERT( nodevec.shape() == std::decay_t::shape_type({m_nnode, m_ndim})); GOOSEFEM_ASSERT(dofval.size() == m_ndof); dofval.fill(0.0); for (size_t m = 0; m < m_nnode; ++m) { for (size_t i = 0; i < m_ndim; ++i) { dofval(m_dofs(m, i)) += nodevec(m, i); } } } inline void VectorPartitioned::assembleDofs_u( - const xt::xtensor& nodevec, xt::xtensor& dofval_u) const + const xt::xtensor& nodevec, xt::xtensor& dofval_u) const { GOOSEFEM_ASSERT( nodevec.shape() == std::decay_t::shape_type({m_nnode, m_ndim})); GOOSEFEM_ASSERT(dofval_u.size() == m_nnu); dofval_u.fill(0.0); for (size_t m = 0; m < m_nnode; ++m) { for (size_t i = 0; i < m_ndim; ++i) { if (m_part(m, i) < m_nnu) { dofval_u(m_part(m, i)) += nodevec(m, i); } } } } inline void VectorPartitioned::assembleDofs_p( - const xt::xtensor& nodevec, xt::xtensor& dofval_p) const + const xt::xtensor& nodevec, xt::xtensor& dofval_p) const { GOOSEFEM_ASSERT( nodevec.shape() == std::decay_t::shape_type({m_nnode, m_ndim})); GOOSEFEM_ASSERT(dofval_p.size() == m_nnp); dofval_p.fill(0.0); for (size_t m = 0; m < m_nnode; ++m) { for (size_t i = 0; i < m_ndim; ++i) { if (m_part(m, i) >= m_nnu) { dofval_p(m_part(m, i) - m_nnu) += nodevec(m, i); } } } } inline void VectorPartitioned::assembleDofs( - const xt::xtensor& elemvec, xt::xtensor& dofval) const + const xt::xtensor& elemvec, xt::xtensor& dofval) const { GOOSEFEM_ASSERT( elemvec.shape() == std::decay_t::shape_type({m_nelem, m_nne, m_ndim})); GOOSEFEM_ASSERT(dofval.size() == m_ndof); dofval.fill(0.0); for (size_t e = 0; e < m_nelem; ++e) { for (size_t m = 0; m < m_nne; ++m) { for (size_t i = 0; i < m_ndim; ++i) { dofval(m_dofs(m_conn(e, m), i)) += elemvec(e, m, i); } } } } inline void VectorPartitioned::assembleDofs_u( - const xt::xtensor& elemvec, xt::xtensor& dofval_u) const + const xt::xtensor& elemvec, xt::xtensor& dofval_u) const { GOOSEFEM_ASSERT( elemvec.shape() == std::decay_t::shape_type({m_nelem, m_nne, m_ndim})); GOOSEFEM_ASSERT(dofval_u.size() == m_nnu); dofval_u.fill(0.0); for (size_t e = 0; e < m_nelem; ++e) { for (size_t m = 0; m < m_nne; ++m) { for (size_t i = 0; i < m_ndim; ++i) { if (m_part(m_conn(e, m), i) < m_nnu) { dofval_u(m_part(m_conn(e, m), i)) += elemvec(e, m, i); } } } } } inline void VectorPartitioned::assembleDofs_p( - const xt::xtensor& elemvec, xt::xtensor& dofval_p) const + const xt::xtensor& elemvec, xt::xtensor& dofval_p) const { GOOSEFEM_ASSERT( elemvec.shape() == std::decay_t::shape_type({m_nelem, m_nne, m_ndim})); GOOSEFEM_ASSERT(dofval_p.size() == m_nnp); dofval_p.fill(0.0); for (size_t e = 0; e < m_nelem; ++e) { for (size_t m = 0; m < m_nne; ++m) { for (size_t i = 0; i < m_ndim; ++i) { if (m_part(m_conn(e, m), i) >= m_nnu) { dofval_p(m_part(m_conn(e, m), i) - m_nnu) += elemvec(e, m, i); } } } } } inline void VectorPartitioned::assembleNode( - const xt::xtensor& elemvec, xt::xtensor& nodevec) const + const xt::xtensor& elemvec, xt::xtensor& nodevec) const { GOOSEFEM_ASSERT( elemvec.shape() == std::decay_t::shape_type({m_nelem, m_nne, m_ndim})); GOOSEFEM_ASSERT( nodevec.shape() == std::decay_t::shape_type({m_nnode, m_ndim})); - xt::xtensor dofval = this->AssembleDofs(elemvec); + xt::xtensor dofval = this->AssembleDofs(elemvec); this->asNode(dofval, nodevec); } -inline xt::xtensor VectorPartitioned::AsDofs( - const xt::xtensor& dofval_u, const xt::xtensor& dofval_p) const +inline xt::xtensor VectorPartitioned::AsDofs( + const xt::xtensor& dofval_u, const xt::xtensor& dofval_p) const { - xt::xtensor dofval = xt::empty({m_ndof}); + xt::xtensor dofval = xt::empty({m_ndof}); this->asDofs(dofval_u, dofval_p, dofval); return dofval; } -inline xt::xtensor VectorPartitioned::AsDofs(const xt::xtensor& nodevec) const +inline xt::xtensor VectorPartitioned::AsDofs(const xt::xtensor& nodevec) const { - xt::xtensor dofval = xt::empty({m_ndof}); + xt::xtensor dofval = xt::empty({m_ndof}); this->asDofs(nodevec, dofval); return dofval; } -inline xt::xtensor -VectorPartitioned::AsDofs_u(const xt::xtensor& dofval) const +inline xt::xtensor +VectorPartitioned::AsDofs_u(const xt::xtensor& dofval) const { - xt::xtensor dofval_u = xt::empty({m_nnu}); + xt::xtensor dofval_u = xt::empty({m_nnu}); this->asDofs_u(dofval, dofval_u); return dofval_u; } -inline xt::xtensor -VectorPartitioned::AsDofs_u(const xt::xtensor& nodevec) const +inline xt::xtensor +VectorPartitioned::AsDofs_u(const xt::xtensor& nodevec) const { - xt::xtensor dofval_u = xt::empty({m_nnu}); + xt::xtensor dofval_u = xt::empty({m_nnu}); this->asDofs_u(nodevec, dofval_u); return dofval_u; } -inline xt::xtensor -VectorPartitioned::AsDofs_p(const xt::xtensor& dofval) const +inline xt::xtensor +VectorPartitioned::AsDofs_p(const xt::xtensor& dofval) const { - xt::xtensor dofval_p = xt::empty({m_nnp}); + xt::xtensor dofval_p = xt::empty({m_nnp}); this->asDofs_p(dofval, dofval_p); return dofval_p; } -inline xt::xtensor -VectorPartitioned::AsDofs_p(const xt::xtensor& nodevec) const +inline xt::xtensor +VectorPartitioned::AsDofs_p(const xt::xtensor& nodevec) const { - xt::xtensor dofval_p = xt::empty({m_nnp}); + xt::xtensor dofval_p = xt::empty({m_nnp}); this->asDofs_p(nodevec, dofval_p); return dofval_p; } -inline xt::xtensor VectorPartitioned::AsDofs(const xt::xtensor& elemvec) const +inline xt::xtensor VectorPartitioned::AsDofs(const xt::xtensor& elemvec) const { - xt::xtensor dofval = xt::empty({m_ndof}); + xt::xtensor dofval = xt::empty({m_ndof}); this->asDofs(elemvec, dofval); return dofval; } -inline xt::xtensor -VectorPartitioned::AsDofs_u(const xt::xtensor& elemvec) const +inline xt::xtensor +VectorPartitioned::AsDofs_u(const xt::xtensor& elemvec) const { - xt::xtensor dofval_u = xt::empty({m_nnu}); + xt::xtensor dofval_u = xt::empty({m_nnu}); this->asDofs_u(elemvec, dofval_u); return dofval_u; } -inline xt::xtensor -VectorPartitioned::AsDofs_p(const xt::xtensor& elemvec) const +inline xt::xtensor +VectorPartitioned::AsDofs_p(const xt::xtensor& elemvec) const { - xt::xtensor dofval_p = xt::empty({m_nnp}); + xt::xtensor dofval_p = xt::empty({m_nnp}); this->asDofs_p(elemvec, dofval_p); return dofval_p; } -inline xt::xtensor VectorPartitioned::AsNode(const xt::xtensor& dofval) const +inline xt::xtensor VectorPartitioned::AsNode(const xt::xtensor& dofval) const { - xt::xtensor nodevec = xt::empty({m_nnode, m_ndim}); + xt::xtensor nodevec = xt::empty({m_nnode, m_ndim}); this->asNode(dofval, nodevec); return nodevec; } -inline xt::xtensor VectorPartitioned::AsNode( - const xt::xtensor& dofval_u, const xt::xtensor& dofval_p) const +inline xt::xtensor VectorPartitioned::AsNode( + const xt::xtensor& dofval_u, const xt::xtensor& dofval_p) const { - xt::xtensor nodevec = xt::empty({m_nnode, m_ndim}); + xt::xtensor nodevec = xt::empty({m_nnode, m_ndim}); this->asNode(dofval_u, dofval_p, nodevec); return nodevec; } -inline xt::xtensor VectorPartitioned::AsNode(const xt::xtensor& elemvec) const +inline xt::xtensor VectorPartitioned::AsNode(const xt::xtensor& elemvec) const { - xt::xtensor nodevec = xt::empty({m_nnode, m_ndim}); + xt::xtensor nodevec = xt::empty({m_nnode, m_ndim}); this->asNode(elemvec, nodevec); return nodevec; } -inline xt::xtensor -VectorPartitioned::AsElement(const xt::xtensor& dofval) const +inline xt::xtensor +VectorPartitioned::AsElement(const xt::xtensor& dofval) const { - xt::xtensor elemvec = xt::empty({m_nelem, m_nne, m_ndim}); + xt::xtensor elemvec = xt::empty({m_nelem, m_nne, m_ndim}); this->asElement(dofval, elemvec); return elemvec; } -inline xt::xtensor VectorPartitioned::AsElement( - const xt::xtensor& dofval_u, const xt::xtensor& dofval_p) const +inline xt::xtensor VectorPartitioned::AsElement( + const xt::xtensor& dofval_u, const xt::xtensor& dofval_p) const { - xt::xtensor elemvec = xt::empty({m_nelem, m_nne, m_ndim}); + xt::xtensor elemvec = xt::empty({m_nelem, m_nne, m_ndim}); this->asElement(dofval_u, dofval_p, elemvec); return elemvec; } -inline xt::xtensor -VectorPartitioned::AsElement(const xt::xtensor& nodevec) const +inline xt::xtensor +VectorPartitioned::AsElement(const xt::xtensor& nodevec) const { - xt::xtensor elemvec = xt::empty({m_nelem, m_nne, m_ndim}); + xt::xtensor elemvec = xt::empty({m_nelem, m_nne, m_ndim}); this->asElement(nodevec, elemvec); return elemvec; } -inline xt::xtensor -VectorPartitioned::AssembleDofs(const xt::xtensor& nodevec) const +inline xt::xtensor +VectorPartitioned::AssembleDofs(const xt::xtensor& nodevec) const { - xt::xtensor dofval = xt::empty({m_ndof}); + xt::xtensor dofval = xt::empty({m_ndof}); this->assembleDofs(nodevec, dofval); return dofval; } -inline xt::xtensor -VectorPartitioned::AssembleDofs_u(const xt::xtensor& nodevec) const +inline xt::xtensor +VectorPartitioned::AssembleDofs_u(const xt::xtensor& nodevec) const { - xt::xtensor dofval_u = xt::empty({m_nnu}); + xt::xtensor dofval_u = xt::empty({m_nnu}); this->assembleDofs_u(nodevec, dofval_u); return dofval_u; } -inline xt::xtensor -VectorPartitioned::AssembleDofs_p(const xt::xtensor& nodevec) const +inline xt::xtensor +VectorPartitioned::AssembleDofs_p(const xt::xtensor& nodevec) const { - xt::xtensor dofval_p = xt::empty({m_nnp}); + xt::xtensor dofval_p = xt::empty({m_nnp}); this->assembleDofs_p(nodevec, dofval_p); return dofval_p; } -inline xt::xtensor -VectorPartitioned::AssembleDofs(const xt::xtensor& elemvec) const +inline xt::xtensor +VectorPartitioned::AssembleDofs(const xt::xtensor& elemvec) const { - xt::xtensor dofval = xt::empty({m_ndof}); + xt::xtensor dofval = xt::empty({m_ndof}); this->assembleDofs(elemvec, dofval); return dofval; } -inline xt::xtensor -VectorPartitioned::AssembleDofs_u(const xt::xtensor& elemvec) const +inline xt::xtensor +VectorPartitioned::AssembleDofs_u(const xt::xtensor& elemvec) const { - xt::xtensor dofval_u = xt::empty({m_nnu}); + xt::xtensor dofval_u = xt::empty({m_nnu}); this->assembleDofs_u(elemvec, dofval_u); return dofval_u; } -inline xt::xtensor -VectorPartitioned::AssembleDofs_p(const xt::xtensor& elemvec) const +inline xt::xtensor +VectorPartitioned::AssembleDofs_p(const xt::xtensor& elemvec) const { - xt::xtensor dofval_p = xt::empty({m_nnp}); + xt::xtensor dofval_p = xt::empty({m_nnp}); this->assembleDofs_p(elemvec, dofval_p); return dofval_p; } -inline xt::xtensor -VectorPartitioned::AssembleNode(const xt::xtensor& elemvec) const +inline xt::xtensor +VectorPartitioned::AssembleNode(const xt::xtensor& elemvec) const { - xt::xtensor nodevec = xt::empty({m_nnode, m_ndim}); + xt::xtensor nodevec = xt::empty({m_nnode, m_ndim}); this->assembleNode(elemvec, nodevec); return nodevec; } -inline xt::xtensor VectorPartitioned::Copy( - const xt::xtensor& nodevec_src, const xt::xtensor& nodevec_dest) const +inline xt::xtensor VectorPartitioned::Copy( + const xt::xtensor& nodevec_src, const xt::xtensor& nodevec_dest) const { - xt::xtensor out = nodevec_dest; + xt::xtensor out = nodevec_dest; this->copy(nodevec_src, out); return out; } -inline xt::xtensor VectorPartitioned::Copy_u( - const xt::xtensor& nodevec_src, const xt::xtensor& nodevec_dest) const +inline xt::xtensor VectorPartitioned::Copy_u( + const xt::xtensor& nodevec_src, const xt::xtensor& nodevec_dest) const { - xt::xtensor out = nodevec_dest; + xt::xtensor out = nodevec_dest; this->copy_u(nodevec_src, out); return out; } -inline xt::xtensor VectorPartitioned::Copy_p( - const xt::xtensor& nodevec_src, const xt::xtensor& nodevec_dest) const +inline xt::xtensor VectorPartitioned::Copy_p( + const xt::xtensor& nodevec_src, const xt::xtensor& nodevec_dest) const { - xt::xtensor out = nodevec_dest; + xt::xtensor out = nodevec_dest; this->copy_p(nodevec_src, out); return out; } } // namespace GooseFEM #endif diff --git a/include/GooseFEM/VectorPartitionedTyings.h b/include/GooseFEM/VectorPartitionedTyings.h index d48533c..72c64e8 100644 --- a/include/GooseFEM/VectorPartitionedTyings.h +++ b/include/GooseFEM/VectorPartitionedTyings.h @@ -1,121 +1,120 @@ /* (c - GPLv3) T.W.J. de Geus (Tom) | tom@geus.me | www.geus.me | github.com/tdegeus/GooseFEM */ #ifndef GOOSEFEM_VECTORPARTITIONEDTYINGS_H #define GOOSEFEM_VECTORPARTITIONEDTYINGS_H #include "config.h" #include #include namespace GooseFEM { /* "nodevec" - nodal vectors - [nnode, ndim] "elemvec" - nodal vectors stored per element - [nelem, nne, ndim] "dofval" - DOF values - [ndof] "dofval_u" - DOF values (Unknown) "== dofval[iiu]" - [nnu] "dofval_p" - DOF values (Prescribed) "== dofval[iiu]" - [nnp] */ class VectorPartitionedTyings { public: // Constructor VectorPartitionedTyings() = default; VectorPartitionedTyings( - const xt::xtensor& conn, - const xt::xtensor& dofs, + const xt::xtensor& conn, + const xt::xtensor& dofs, const Eigen::SparseMatrix& Cdu, const Eigen::SparseMatrix& Cdp, const Eigen::SparseMatrix& Cdi); // Dimensions size_t nelem() const; // number of elements size_t nne() const; // number of nodes per element size_t nnode() const; // number of nodes size_t ndim() const; // number of dimensions size_t ndof() const; // number of DOFs size_t nnu() const; // number of independent, unknown DOFs size_t nnp() const; // number of independent, prescribed DOFs size_t nni() const; // number of independent DOFs size_t nnd() const; // number of dependent DOFs // DOF lists - xt::xtensor dofs() const; // DOFs - xt::xtensor iiu() const; // independent, unknown DOFs - xt::xtensor iip() const; // independent, prescribed DOFs - xt::xtensor iii() const; // independent DOFs - xt::xtensor iid() const; // dependent DOFs + xt::xtensor dofs() const; // DOFs + xt::xtensor iiu() const; // independent, unknown DOFs + xt::xtensor iip() const; // independent, prescribed DOFs + xt::xtensor iii() const; // independent DOFs + xt::xtensor iid() const; // dependent DOFs // Copy (part of) nodevec/dofval to another nodevec/dofval void copy_p( - const xt::xtensor& dofval_src, - xt::xtensor& dofval_dest) const; // "iip" updated + const xt::xtensor& dofval_src, xt::xtensor& dofval_dest) const; // "iip" updated // Convert to "dofval" (overwrite entries that occur more than once) void asDofs_i( - const xt::xtensor& nodevec, - xt::xtensor& dofval_i, - bool apply_tyings = true) const; + const xt::xtensor& nodevec, + xt::xtensor& dofval_i, + bool apply_tyings = true) const; // Convert to "nodevec" (overwrite entries that occur more than once) -- (auto allocation below) - void asNode(const xt::xtensor& dofval, xt::xtensor& nodevec) const; + void asNode(const xt::xtensor& dofval, xt::xtensor& nodevec) const; // Convert to "elemvec" (overwrite entries that occur more than once) -- (auto allocation below) - void asElement(const xt::xtensor& nodevec, xt::xtensor& elemvec) const; + void asElement(const xt::xtensor& nodevec, xt::xtensor& elemvec) const; // Assemble "dofval" (adds entries that occur more that once) -- (auto allocation below) - void assembleDofs(const xt::xtensor& elemvec, xt::xtensor& dofval) const; + void assembleDofs(const xt::xtensor& elemvec, xt::xtensor& dofval) const; // Assemble "nodevec" (adds entries that occur more that once) -- (auto allocation below) - void assembleNode(const xt::xtensor& elemvec, xt::xtensor& nodevec) const; + void assembleNode(const xt::xtensor& elemvec, xt::xtensor& nodevec) const; // Auto-allocation of the functions above - xt::xtensor AsDofs_i(const xt::xtensor& nodevec) const; - xt::xtensor AsNode(const xt::xtensor& dofval) const; - xt::xtensor AsElement(const xt::xtensor& nodevec) const; - xt::xtensor AssembleDofs(const xt::xtensor& elemvec) const; - xt::xtensor AssembleNode(const xt::xtensor& elemvec) const; + xt::xtensor AsDofs_i(const xt::xtensor& nodevec) const; + xt::xtensor AsNode(const xt::xtensor& dofval) const; + xt::xtensor AsElement(const xt::xtensor& nodevec) const; + xt::xtensor AssembleDofs(const xt::xtensor& elemvec) const; + xt::xtensor AssembleNode(const xt::xtensor& elemvec) const; private: // Bookkeeping - xt::xtensor m_conn; // connectivity [nelem, nne] - xt::xtensor m_dofs; // DOF-numbers per node [nnode, ndim] - xt::xtensor m_iiu; // unknown DOFs [nnu] - xt::xtensor m_iip; // prescribed DOFs [nnp] - xt::xtensor m_iid; // dependent DOFs [nnd] + xt::xtensor m_conn; // connectivity [nelem, nne] + xt::xtensor m_dofs; // DOF-numbers per node [nnode, ndim] + xt::xtensor m_iiu; // unknown DOFs [nnu] + xt::xtensor m_iip; // prescribed DOFs [nnp] + xt::xtensor m_iid; // dependent DOFs [nnd] // Dimensions size_t m_nelem; // number of elements size_t m_nne; // number of nodes per element size_t m_nnode; // number of nodes size_t m_ndim; // number of dimensions size_t m_ndof; // number of DOFs size_t m_nnu; // number of independent, unknown DOFs size_t m_nnp; // number of independent, prescribed DOFs size_t m_nni; // number of independent DOFs size_t m_nnd; // number of dependent DOFs // Tyings Eigen::SparseMatrix m_Cdu; Eigen::SparseMatrix m_Cdp; Eigen::SparseMatrix m_Cdi; Eigen::SparseMatrix m_Cud; Eigen::SparseMatrix m_Cpd; Eigen::SparseMatrix m_Cid; // equivalent Eigen functions - Eigen::VectorXd Eigen_asDofs_d(const xt::xtensor& nodevec) const; + Eigen::VectorXd Eigen_asDofs_d(const xt::xtensor& nodevec) const; }; } // namespace GooseFEM #include "VectorPartitionedTyings.hpp" #endif diff --git a/include/GooseFEM/VectorPartitionedTyings.hpp b/include/GooseFEM/VectorPartitionedTyings.hpp index 8f03722..295b244 100644 --- a/include/GooseFEM/VectorPartitionedTyings.hpp +++ b/include/GooseFEM/VectorPartitionedTyings.hpp @@ -1,283 +1,283 @@ /* (c - GPLv3) T.W.J. de Geus (Tom) | tom@geus.me | www.geus.me | github.com/tdegeus/GooseFEM */ #ifndef GOOSEFEM_VECTORPARTITIONEDTYINGS_HPP #define GOOSEFEM_VECTORPARTITIONEDTYINGS_HPP #include "VectorPartitionedTyings.h" namespace GooseFEM { inline VectorPartitionedTyings::VectorPartitionedTyings( - const xt::xtensor& conn, - const xt::xtensor& dofs, + const xt::xtensor& conn, + const xt::xtensor& dofs, const Eigen::SparseMatrix& Cdu, const Eigen::SparseMatrix& Cdp, const Eigen::SparseMatrix& Cdi) : m_conn(conn), m_dofs(dofs), m_Cdu(Cdu), m_Cdp(Cdp), m_Cdi(Cdi) { GOOSEFEM_ASSERT(Cdu.rows() == Cdp.rows()); GOOSEFEM_ASSERT(Cdi.rows() == Cdp.rows()); m_nnu = static_cast(m_Cdu.cols()); m_nnp = static_cast(m_Cdp.cols()); m_nnd = static_cast(m_Cdp.rows()); m_nni = m_nnu + m_nnp; m_ndof = m_nni + m_nnd; m_iiu = xt::arange(m_nnu); m_iip = xt::arange(m_nnu, m_nnu + m_nnp); m_iid = xt::arange(m_nni, m_nni + m_nnd); m_nelem = m_conn.shape(0); m_nne = m_conn.shape(1); m_nnode = m_dofs.shape(0); m_ndim = m_dofs.shape(1); m_Cud = m_Cdu.transpose(); m_Cpd = m_Cdp.transpose(); m_Cid = m_Cdi.transpose(); GOOSEFEM_ASSERT(static_cast(m_Cdi.cols()) == m_nni); GOOSEFEM_ASSERT(m_ndof <= m_nnode * m_ndim); GOOSEFEM_ASSERT(m_ndof == xt::amax(m_dofs)[0] + 1); } inline size_t VectorPartitionedTyings::nelem() const { return m_nelem; } inline size_t VectorPartitionedTyings::nne() const { return m_nne; } inline size_t VectorPartitionedTyings::nnode() const { return m_nnode; } inline size_t VectorPartitionedTyings::ndim() const { return m_ndim; } inline size_t VectorPartitionedTyings::ndof() const { return m_ndof; } inline size_t VectorPartitionedTyings::nnu() const { return m_nnu; } inline size_t VectorPartitionedTyings::nnp() const { return m_nnp; } inline size_t VectorPartitionedTyings::nni() const { return m_nni; } inline size_t VectorPartitionedTyings::nnd() const { return m_nnd; } -inline xt::xtensor VectorPartitionedTyings::dofs() const +inline xt::xtensor VectorPartitionedTyings::dofs() const { return m_dofs; } -inline xt::xtensor VectorPartitionedTyings::iiu() const +inline xt::xtensor VectorPartitionedTyings::iiu() const { return m_iiu; } -inline xt::xtensor VectorPartitionedTyings::iip() const +inline xt::xtensor VectorPartitionedTyings::iip() const { return m_iip; } -inline xt::xtensor VectorPartitionedTyings::iii() const +inline xt::xtensor VectorPartitionedTyings::iii() const { return xt::arange(m_nni); } -inline xt::xtensor VectorPartitionedTyings::iid() const +inline xt::xtensor VectorPartitionedTyings::iid() const { return m_iid; } inline void VectorPartitionedTyings::copy_p( - const xt::xtensor& dofval_src, xt::xtensor& dofval_dest) const + const xt::xtensor& dofval_src, xt::xtensor& dofval_dest) const { GOOSEFEM_ASSERT(dofval_src.size() == m_ndof || dofval_src.size() == m_nni); GOOSEFEM_ASSERT(dofval_dest.size() == m_ndof || dofval_dest.size() == m_nni); #pragma omp parallel for for (size_t i = m_nnu; i < m_nni; ++i) { dofval_dest(i) = dofval_src(i); } } inline void VectorPartitionedTyings::asDofs_i( - const xt::xtensor& nodevec, - xt::xtensor& dofval_i, + const xt::xtensor& nodevec, + xt::xtensor& dofval_i, bool apply_tyings) const { GOOSEFEM_ASSERT( nodevec.shape() == std::decay_t::shape_type({m_nnode, m_ndim})); GOOSEFEM_ASSERT(dofval_i.size() == m_nni); #pragma omp parallel for for (size_t m = 0; m < m_nnode; ++m) { for (size_t i = 0; i < m_ndim; ++i) { if (m_dofs(m, i) < m_nni) { dofval_i(m_dofs(m, i)) = nodevec(m, i); } } } if (!apply_tyings) return; Eigen::VectorXd Dofval_d = this->Eigen_asDofs_d(nodevec); Eigen::VectorXd Dofval_i = m_Cid * Dofval_d; #pragma omp parallel for for (size_t i = 0; i < m_nni; ++i) { dofval_i(i) += Dofval_i(i); } } inline void VectorPartitionedTyings::asNode( - const xt::xtensor& dofval, xt::xtensor& nodevec) const + const xt::xtensor& dofval, xt::xtensor& nodevec) const { GOOSEFEM_ASSERT(dofval.size() == m_ndof); GOOSEFEM_ASSERT( nodevec.shape() == std::decay_t::shape_type({m_nnode, m_ndim})); #pragma omp parallel for for (size_t m = 0; m < m_nnode; ++m) { for (size_t i = 0; i < m_ndim; ++i) { nodevec(m, i) = dofval(m_dofs(m, i)); } } } inline void VectorPartitionedTyings::asElement( - const xt::xtensor& nodevec, xt::xtensor& elemvec) const + const xt::xtensor& nodevec, xt::xtensor& elemvec) const { GOOSEFEM_ASSERT( nodevec.shape() == std::decay_t::shape_type({m_nnode, m_ndim})); GOOSEFEM_ASSERT( elemvec.shape() == std::decay_t::shape_type({m_nelem, m_nne, m_ndim})); #pragma omp parallel for for (size_t e = 0; e < m_nelem; ++e) { for (size_t m = 0; m < m_nne; ++m) { for (size_t i = 0; i < m_ndim; ++i) { elemvec(e, m, i) = nodevec(m_conn(e, m), i); } } } } inline void VectorPartitionedTyings::assembleDofs( - const xt::xtensor& elemvec, xt::xtensor& dofval) const + const xt::xtensor& elemvec, xt::xtensor& dofval) const { GOOSEFEM_ASSERT( elemvec.shape() == std::decay_t::shape_type({m_nelem, m_nne, m_ndim})); GOOSEFEM_ASSERT(dofval.size() == m_ndof); dofval.fill(0.0); for (size_t e = 0; e < m_nelem; ++e) { for (size_t m = 0; m < m_nne; ++m) { for (size_t i = 0; i < m_ndim; ++i) { dofval(m_dofs(m_conn(e, m), i)) += elemvec(e, m, i); } } } } inline void VectorPartitionedTyings::assembleNode( - const xt::xtensor& elemvec, xt::xtensor& nodevec) const + const xt::xtensor& elemvec, xt::xtensor& nodevec) const { GOOSEFEM_ASSERT( elemvec.shape() == std::decay_t::shape_type({m_nelem, m_nne, m_ndim})); GOOSEFEM_ASSERT( nodevec.shape() == std::decay_t::shape_type({m_nnode, m_ndim})); - xt::xtensor dofval = this->AssembleDofs(elemvec); + xt::xtensor dofval = this->AssembleDofs(elemvec); this->asNode(dofval, nodevec); } -inline xt::xtensor -VectorPartitionedTyings::AsDofs_i(const xt::xtensor& nodevec) const +inline xt::xtensor +VectorPartitionedTyings::AsDofs_i(const xt::xtensor& nodevec) const { - xt::xtensor dofval = xt::empty({m_nni}); + xt::xtensor dofval = xt::empty({m_nni}); this->asDofs_i(nodevec, dofval); return dofval; } -inline xt::xtensor -VectorPartitionedTyings::AsNode(const xt::xtensor& dofval) const +inline xt::xtensor +VectorPartitionedTyings::AsNode(const xt::xtensor& dofval) const { - xt::xtensor nodevec = xt::empty({m_nnode, m_ndim}); + xt::xtensor nodevec = xt::empty({m_nnode, m_ndim}); this->asNode(dofval, nodevec); return nodevec; } -inline xt::xtensor -VectorPartitionedTyings::AsElement(const xt::xtensor& nodevec) const +inline xt::xtensor +VectorPartitionedTyings::AsElement(const xt::xtensor& nodevec) const { - xt::xtensor elemvec = xt::empty({m_nelem, m_nne, m_ndim}); + xt::xtensor elemvec = xt::empty({m_nelem, m_nne, m_ndim}); this->asElement(nodevec, elemvec); return elemvec; } -inline xt::xtensor -VectorPartitionedTyings::AssembleDofs(const xt::xtensor& elemvec) const +inline xt::xtensor +VectorPartitionedTyings::AssembleDofs(const xt::xtensor& elemvec) const { - xt::xtensor dofval = xt::empty({m_ndof}); + xt::xtensor dofval = xt::empty({m_ndof}); this->assembleDofs(elemvec, dofval); return dofval; } -inline xt::xtensor -VectorPartitionedTyings::AssembleNode(const xt::xtensor& elemvec) const +inline xt::xtensor +VectorPartitionedTyings::AssembleNode(const xt::xtensor& elemvec) const { - xt::xtensor nodevec = xt::empty({m_nnode, m_ndim}); + xt::xtensor nodevec = xt::empty({m_nnode, m_ndim}); this->assembleNode(elemvec, nodevec); return nodevec; } inline Eigen::VectorXd -VectorPartitionedTyings::Eigen_asDofs_d(const xt::xtensor& nodevec) const +VectorPartitionedTyings::Eigen_asDofs_d(const xt::xtensor& nodevec) const { GOOSEFEM_ASSERT( nodevec.shape() == std::decay_t::shape_type({m_nnode, m_ndim})); Eigen::VectorXd dofval_d(m_nnd, 1); #pragma omp parallel for for (size_t m = 0; m < m_nnode; ++m) { for (size_t i = 0; i < m_ndim; ++i) { if (m_dofs(m, i) >= m_nni) { dofval_d(m_dofs(m, i) - m_nni) = nodevec(m, i); } } } return dofval_d; } } // namespace GooseFEM #endif diff --git a/include/GooseFEM/config.h b/include/GooseFEM/config.h index 41e9741..cafa85c 100644 --- a/include/GooseFEM/config.h +++ b/include/GooseFEM/config.h @@ -1,76 +1,76 @@ /* (c - GPLv3) T.W.J. de Geus (Tom) | tom@geus.me | www.geus.me | github.com/tdegeus/GooseFEM */ #ifndef GOOSEFEM_CONFIG_H #define GOOSEFEM_CONFIG_H #define _USE_MATH_DEFINES // to use "M_PI" from "math.h" +#include #include #include -#include -#include -#include -#include #include -#include +#include #include -#include #include +#include +#include +#include +#include -#include -#include #include +#include #include #include #include #include #include #include #include #include +#include #include #include using namespace xt::placeholders; #define UNUSED(p) ((void)(p)) #ifdef GOOSEFEM_ENABLE_ASSERT - #define GOOSEFEM_ASSERT(expr) GOOSEFEM_ASSERT_IMPL(expr, __FILE__, __LINE__) - #define GOOSEFEM_ASSERT_IMPL(expr, file, line) \ - if (!(expr)) { \ - throw std::runtime_error( \ - std::string(file) + ':' + std::to_string(line) + \ - ": assertion failed (" #expr ") \n\t"); \ - } +#define GOOSEFEM_ASSERT(expr) GOOSEFEM_ASSERT_IMPL(expr, __FILE__, __LINE__) +#define GOOSEFEM_ASSERT_IMPL(expr, file, line) \ + if (!(expr)) { \ + throw std::runtime_error( \ + std::string(file) + ':' + std::to_string(line) + \ + ": assertion failed (" #expr ") \n\t"); \ + } #else - #define GOOSEFEM_ASSERT(expr) +#define GOOSEFEM_ASSERT(expr) #endif #define GOOSEFEM_CHECK(expr) GOOSEFEM_CHECK_IMPL(expr, __FILE__, __LINE__) #define GOOSEFEM_CHECK_IMPL(expr, file, line) \ if (!(expr)) { \ throw std::runtime_error( \ std::string(file) + ':' + std::to_string(line) + \ ": assertion failed (" #expr ") \n\t"); \ } #define GOOSEFEM_VERSION_MAJOR 0 #define GOOSEFEM_VERSION_MINOR 3 #define GOOSEFEM_VERSION_PATCH 1 #define GOOSEFEM_VERSION_AT_LEAST(x, y, z) \ (GOOSEFEM_VERSION_MAJOR > x || (GOOSEFEM_VERSION_MAJOR >= x && \ (GOOSEFEM_VERSION_MINOR > y || (GOOSEFEM_VERSION_MINOR >= y && \ GOOSEFEM_VERSION_PATCH >= z)))) #define GOOSEFEM_VERSION(x, y, z) \ (GOOSEFEM_VERSION_MAJOR == x && \ GOOSEFEM_VERSION_MINOR == y && \ GOOSEFEM_VERSION_PATCH == z) #endif