diff --git a/include/GooseFEM/Vector.h b/include/GooseFEM/Vector.h index f5dbdf6..1919424 100644 --- a/include/GooseFEM/Vector.h +++ b/include/GooseFEM/Vector.h @@ -1,321 +1,377 @@ /** Methods to switch between storage types based on a mesh. \file Vector.h \copyright Copyright 2017. Tom de Geus. All rights reserved. \license This project is released under the GNU Public License (GPLv3). */ #ifndef GOOSEFEM_VECTOR_H #define GOOSEFEM_VECTOR_H #include "config.h" namespace GooseFEM { /** Class to switch between storage types. In particular: - "dofval": DOF values [#ndof]. - "nodevec": nodal vectors [#nnode, #ndim]. - "elemvec": nodal vectors stored per element [#nelem, #nne, #ndim]. */ class Vector { public: Vector() = default; /** Constructor. \param conn connectivity [#nelem, #nne]. \param dofs DOFs per node [#nnode, #ndim]. */ template Vector(const S& conn, const T& dofs); /** \return Number of elements. */ size_t nelem() const; /** \return Number of nodes per element. */ size_t nne() const; /** \return Number of nodes. */ size_t nnode() const; /** \return Number of dimensions. */ size_t ndim() const; /** \return Number of DOFs. */ size_t ndof() const; /** \return Connectivity (nodes per element) [#nelem, #nne]. */ xt::xtensor conn() const; /** \return DOFs per node [#nnode, #ndim] */ xt::xtensor dofs() const; /** Copy "nodevec" to another "nodevec". \param nodevec_src input [#nnode, #ndim] \param nodevec_dest input [#nnode, #ndim] \return nodevec output [#nnode, #ndim] */ template T Copy(const T& nodevec_src, const T& nodevec_dest) const; /** Copy "nodevec" to another "nodevec". \param nodevec_src input [#nnode, #ndim] \param nodevec_dest output [#nnode, #ndim] */ template void copy(const T& nodevec_src, T& nodevec_dest) const; /** Convert "nodevec" or "elemvec" to "dofval" (overwrite entries that occur more than once). \param arg nodevec [#nnode, #ndim] or elemvec [#nelem, #nne, #ndim] \return dofval [#ndof] */ template xt::xtensor AsDofs(const T& arg) const; /** Convert "nodevec" or "elemvec" to "dofval" (overwrite entries that occur more than once). \param arg nodevec [#nnode, #ndim] or elemvec [#nelem, #nne, #ndim] \param dofval (output) [#ndof] */ template void asDofs(const T& arg, R& dofval) const; /** Convert "dofval" or "elemvec" to "nodevec" (overwrite entries that occur more than once). \param arg dofval [#ndof] or elemvec [#nelem, #nne, #ndim] \return nodevec output [#nnode, #ndim] */ template xt::xtensor AsNode(const T& arg) const; /** Convert "dofval" or "elemvec" to "nodevec" (overwrite entries that occur more than once). \param arg dofval [#ndof] or elemvec [#nelem, #nne, #ndim] \param nodevec output [#nnode, #ndim] */ template void asNode(const T& arg, R& nodevec) const; /** Convert "dofval" or "nodevec" to "elemvec" (overwrite entries that occur more than once). \param arg dofval [#ndof] or nodevec [#nnode, #ndim]. - \param elemvec output [#nelem, #nne, #ndim]. + \return elemvec output [#nelem, #nne, #ndim]. */ - template - void asElement(const T& arg, R& elemvec) const; + template + xt::xtensor AsElement(const T& arg) const; /** Convert "dofval" or "nodevec" to "elemvec" (overwrite entries that occur more than once). \param arg dofval [#ndof] or nodevec [#nnode, #ndim]. - \return elemvec output [#nelem, #nne, #ndim]. + \param elemvec output [#nelem, #nne, #ndim]. */ - template - xt::xtensor AsElement(const T& arg) const; + template + void asElement(const T& arg, R& elemvec) const; /** Assemble "nodevec" or "elemvec" to "dofval" (adds entries that occur more that once). \param arg nodevec [#nnode, #ndim] or elemvec [#nelem, #nne, #ndim] \return dofval output [#ndof] */ template xt::xtensor AssembleDofs(const T& arg) const; /** Assemble "nodevec" or "elemvec" to "dofval" (adds entries that occur more that once). \param arg nodevec [#nnode, #ndim] or elemvec [#nelem, #nne, #ndim] \param dofval output [#ndof] */ template void assembleDofs(const T& arg, R& dofval) const; /** Assemble "elemvec" to "nodevec" (adds entries that occur more that once. \param arg elemvec [#nelem, #nne, #ndim] \return nodevec output [#nnode, #ndim] */ template xt::xtensor AssembleNode(const T& arg) const; /** Assemble "elemvec" to "nodevec" (adds entries that occur more that once. \param arg elemvec [#nelem, #nne, #ndim] \param nodevec output [#nnode, #ndim] */ template void assembleNode(const T& arg, R& nodevec) const; /** Shape of "dofval". \return [#ndof] */ std::array shape_dofval() const; /** Shape of "nodevec". \return [#nnode, #ndim] */ std::array shape_nodevec() const; /** Shape of "elemvec". \return [#nelem, #nne, #ndim] */ std::array shape_elemvec() const; /** Shape of "elemmat". \return [#nelem, #nne * #ndim, #nne * #ndim] */ std::array shape_elemmat() const; /** Allocated "dofval". \return [#ndof] */ xt::xtensor allocate_dofval() const; /** Allocated and initialised "dofval". \param val value to which to initialise. \return [#ndof] */ xt::xtensor allocate_dofval(double val) const; /** Allocated "nodevec". \return [#nnode, #ndim] */ xt::xtensor allocate_nodevec() const; /** Allocated and initialised "nodevec". \param val value to which to initialise. \return [#nnode, #ndim] */ xt::xtensor allocate_nodevec(double val) const; /** Allocated "elemvec". \return [#nelem, #nne, #ndim] */ xt::xtensor allocate_elemvec() const; /** Allocated and initialised "elemvec". \param val value to which to initialise. \return [#nelem, #nne, #ndim] */ xt::xtensor allocate_elemvec(double val) const; /** Allocated "elemmat". \return [#nelem, #nne * #ndim, #nne * #ndim] */ xt::xtensor allocate_elemmat() const; /** Allocated and initialised "elemmat". \param val value to which to initialise. \return [#nelem, #nne * #ndim, #nne * #ndim] */ xt::xtensor allocate_elemmat(double val) const; -protected: +private: + + /** Distribution to relevant implementation of \copydoc asDofs(const T&, R&) const */ + template ::value, int> = 0> + void asDofs_impl(const T& arg, R& dofval) const; + + /** Distribution to relevant implementation of \copydoc asDofs(const T&, R&) const */ + template ::value == 2, int> = 0> + void asDofs_impl(const T& arg, R& dofval) const; + + /** Distribution to relevant implementation of \copydoc asDofs(const T&, R&) const */ + template ::value == 3, int> = 0> + void asDofs_impl(const T& arg, R& dofval) const; + + /** Distribution to relevant implementation of \copydoc asNode(const T&, R&) const */ + template ::value, int> = 0> + void asNode_impl(const T& arg, R& nodevec) const; + + /** Distribution to relevant implementation of \copydoc asNode(const T&, R&) const */ + template ::value == 1, int> = 0> + void asNode_impl(const T& arg, R& nodevec) const; + + /** Distribution to relevant implementation of \copydoc asNode(const T&, R&) const */ + template ::value == 3, int> = 0> + void asNode_impl(const T& arg, R& nodevec) const; + + /** Distribution to relevant implementation of \copydoc asElement(const T&, R&) const */ + template ::value, int> = 0> + void asElement_impl(const T& arg, R& elemvec) const; + + /** Distribution to relevant implementation of \copydoc asElement(const T&, R&) const */ + template ::value == 1, int> = 0> + void asElement_impl(const T& arg, R& elemvec) const; + + /** Distribution to relevant implementation of \copydoc asElement(const T&, R&) const */ + template ::value == 2, int> = 0> + void asElement_impl(const T& arg, R& elemvec) const; + + /** Distribution to relevant implementation of \copydoc assembleDofs(const T&, R&) const */ + template ::value, int> = 0> + void assembleDofs_impl(const T& arg, R& dofval) const; + + /** Distribution to relevant implementation of \copydoc assembleDofs(const T&, R&) const */ + template ::value == 2, int> = 0> + void assembleDofs_impl(const T& arg, R& dofval) const; + + /** Distribution to relevant implementation of \copydoc assembleDofs(const T&, R&) const */ + template ::value == 3, int> = 0> + void assembleDofs_impl(const T& arg, R& dofval) const; + + /** Distribution to relevant implementation of \copydoc assembleNode(const T&, R&) const */ + template ::value, int> = 0> + void assembleNode_impl(const T& arg, R& nodevec) const; + + /** Distribution to relevant implementation of \copydoc assembleNode(const T&, R&) const */ + template ::value == 3, int> = 0> + void assembleNode_impl(const T& arg, R& nodevec) const; /** Implementation for 'nodevec' input of \copydoc asDofs(const T&, R&) const */ template - void asDofs_nodevec(const T& arg, R& dofval) const; + void asDofs_impl_nodevec(const T& arg, R& dofval) const; /** Implementation for 'elemvec' input of \copydoc asDofs(const T&, R&) const */ template - void asDofs_elemvec(const T& arg, R& dofval) const; + void asDofs_impl_elemvec(const T& arg, R& dofval) const; /** Implementation for 'dofval' input of \copydoc asNode(const T&, R&) const */ template - void asNode_dofval(const T& arg, R& nodevec) const; + void asNode_impl_dofval(const T& arg, R& nodevec) const; /** Implementation for 'elemvec' input of \copydoc asNode(const T&, R&) const */ template - void asNode_elemvec(const T& arg, R& nodevec) const; + void asNode_impl_elemvec(const T& arg, R& nodevec) const; /** Implementation for 'dofval' input of \copydoc asElement(const T&, R&) const */ template - void asElement_dofval(const T& arg, R& elemvec) const; + void asElement_impl_dofval(const T& arg, R& elemvec) const; /** Implementation for 'nodevec' input of \copydoc asElement(const T&, R&) const */ template - void asElement_nodevec(const T& arg, R& elemvec) const; + void asElement_impl_nodevec(const T& arg, R& elemvec) const; /** Implementation for 'nodevec' input of \copydoc assembleDofs(const T&, R&) const */ template - void assembleDofs_nodevec(const T& arg, R& dofval) const; + void assembleDofs_impl_nodevec(const T& arg, R& dofval) const; /** Implementation for 'elemvec' input of \copydoc assembleDofs(const T&, R&) const */ template - void assembleDofs_elemvec(const T& arg, R& dofval) const; + void assembleDofs_impl_elemvec(const T& arg, R& dofval) const; /** Implementation for 'elemvec' input of \copydoc assembleNode(const T&, R&) const */ template - void assembleNode_elemvec(const T& arg, R& nodevec) const; + void assembleNode_impl_elemvec(const T& arg, R& nodevec) const; protected: xt::xtensor m_conn; ///< See conn() xt::xtensor m_dofs; ///< See dofs() size_t m_nelem; ///< See #nelem size_t m_nne; ///< See #nne size_t m_nnode; ///< See #nnode size_t m_ndim; ///< See #ndim size_t m_ndof; ///< See #ndof }; } // namespace GooseFEM #include "Vector.hpp" #endif diff --git a/include/GooseFEM/Vector.hpp b/include/GooseFEM/Vector.hpp index cfe1314..5e86fa3 100644 --- a/include/GooseFEM/Vector.hpp +++ b/include/GooseFEM/Vector.hpp @@ -1,436 +1,535 @@ /** Implementation of Vector.h \file Vector.hpp \copyright Copyright 2017. Tom de Geus. All rights reserved. \license This project is released under the GNU Public License (GPLv3). */ #ifndef GOOSEFEM_VECTOR_HPP #define GOOSEFEM_VECTOR_HPP #include "Vector.h" namespace GooseFEM { template inline Vector::Vector(const S& conn, const T& dofs) { GOOSEFEM_ASSERT(conn.dimension() == 2); GOOSEFEM_ASSERT(dofs.dimension() == 2); 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)() + 1; GOOSEFEM_ASSERT(xt::amax(m_conn)() + 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::conn() const { return m_conn; } inline xt::xtensor Vector::dofs() const { return m_dofs; } +template +inline T Vector::Copy(const T& nodevec_src, const T& nodevec_dest) const +{ + T ret = T::from_shape(nodevec_dest.shape()); + this->copy(nodevec_src, ret); + return ret; +} + template inline void Vector::copy(const T& nodevec_src, T& nodevec_dest) const { GOOSEFEM_ASSERT(xt::has_shape(nodevec_src, this->shape_nodevec())); GOOSEFEM_ASSERT(xt::has_shape(nodevec_dest, this->shape_nodevec())); xt::noalias(nodevec_dest) = nodevec_src; } -template -inline void Vector::asDofs(const T& arg, R& dofval) const +// asDofs + +template +inline xt::xtensor Vector::AsDofs(const T& arg) const { - if (arg.dimension() == 2) { - this->asDofs_nodevec(arg, dofval); - } - else if (arg.dimension() == 3) { - this->asDofs_elemvec(arg, dofval); - } - else if (arg.dimension() == 1) { - dofval = arg; - } - else { - throw std::runtime_error("Vector::asDofs unknown dimension first argument"); - } + xt::xtensor ret = xt::empty(this->shape_dofval()); + this->asDofs_impl(arg, ret); + return ret; } template -inline void Vector::asNode(const T& arg, R& nodevec) const +void Vector::asDofs(const T& arg, R& ret) const { - if (arg.dimension() == 1) { - this->asNode_dofval(arg, nodevec); - } - else if (arg.dimension() == 3) { - this->asNode_elemvec(arg, nodevec); - } - else if (arg.dimension() == 2) { - nodevec = arg; - } - else { - throw std::runtime_error("Vector::asNode unknown dimension first argument"); - } + this->asDofs_impl(arg, ret); } -template -inline void Vector::asElement(const T& arg, R& elemvec) const +// asDofs : implementation distribution + +template ::value, int>> +inline void Vector::asDofs_impl(const T& arg, R& ret) const { - if (arg.dimension() == 1) { - this->asElement_dofval(arg, elemvec); - } - else if (arg.dimension() == 2) { - this->asElement_nodevec(arg, elemvec); + if (arg.dimension() == 2) { + this->asDofs_impl_nodevec(arg, ret); } else if (arg.dimension() == 3) { - elemvec = arg; + this->asDofs_impl_elemvec(arg, ret); } else { - throw std::runtime_error("Vector::asElement unknown dimension first argument"); + throw std::runtime_error("Vector::asDofs unknown dimension for conversion"); } } -template -inline void Vector::assembleDofs(const T& arg, R& dofval) const +template ::value == 2, int>> +inline void Vector::asDofs_impl(const T& arg, R& ret) const { - if (arg.dimension() == 2) { - this->assembleDofs_nodevec(arg, dofval); - } - else if (arg.dimension() == 3) { - this->assembleDofs_elemvec(arg, dofval); - } - else if (arg.dimension() == 1) { - dofval = arg; - } - else { - throw std::runtime_error("Vector::assembleDofs unknown dimension first argument"); - } + this->asDofs_impl_nodevec(arg, ret); } -template -inline void Vector::assembleNode(const T& arg, R& nodevec) const +template ::value == 3, int>> +inline void Vector::asDofs_impl(const T& arg, R& ret) const { - if (arg.dimension() == 3) { - this->assembleNode_elemvec(arg, nodevec); - } - else if (arg.dimension() == 2) { - nodevec = arg; - } - else { - throw std::runtime_error("Vector::assembleNode unknown dimension first argument"); - } + this->asDofs_impl_elemvec(arg, ret); } +// asDofs : implementation + template -inline void Vector::asDofs_nodevec(const T& nodevec, R& dofval) const +inline void Vector::asDofs_impl_nodevec(const T& arg, R& dofval) const { - GOOSEFEM_ASSERT(xt::has_shape(nodevec, this->shape_nodevec())); + GOOSEFEM_ASSERT(xt::has_shape(arg, this->shape_nodevec())); GOOSEFEM_ASSERT(xt::has_shape(dofval, this->shape_dofval())); dofval.fill(0.0); #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); + dofval(m_dofs(m, i)) = arg(m, i); } } } template -inline void Vector::asDofs_elemvec(const T& elemvec, R& dofval) const +inline void Vector::asDofs_impl_elemvec(const T& arg, R& dofval) const { - GOOSEFEM_ASSERT(xt::has_shape(elemvec, this->shape_elemvec())); + GOOSEFEM_ASSERT(xt::has_shape(arg, this->shape_elemvec())); GOOSEFEM_ASSERT(xt::has_shape(dofval, this->shape_dofval())); dofval.fill(0.0); #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); + dofval(m_dofs(m_conn(e, m), i)) = arg(e, m, i); } } } } +// asNode + +template +inline xt::xtensor Vector::AsNode(const T& arg) const +{ + xt::xtensor ret = xt::empty(this->shape_nodevec()); + this->asNode_impl(arg, ret); + return ret; +} + +template +void Vector::asNode(const T& arg, R& ret) const +{ + this->asNode_impl(arg, ret); +} + +// asNode : implementation distribution + +template ::value, int>> +inline void Vector::asNode_impl(const T& arg, R& ret) const +{ + if (arg.dimension() == 1) { + this->asNode_impl_dofval(arg, ret); + } + else if (arg.dimension() == 3) { + this->asNode_impl_elemvec(arg, ret); + } + else { + throw std::runtime_error("Vector::asNode unknown dimension for conversion"); + } +} + +template ::value == 1, int>> +inline void Vector::asNode_impl(const T& arg, R& ret) const +{ + this->asNode_impl_dofval(arg, ret); +} + +template ::value == 3, int>> +inline void Vector::asNode_impl(const T& arg, R& ret) const +{ + this->asNode_impl_elemvec(arg, ret); +} + +// asNode : implementation + template -inline void Vector::asNode_dofval(const T& dofval, R& nodevec) const +inline void Vector::asNode_impl_dofval(const T& dofval, R& nodevec) const { GOOSEFEM_ASSERT(xt::has_shape(dofval, this->shape_dofval())); GOOSEFEM_ASSERT(xt::has_shape(nodevec, this->shape_nodevec())); #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)); } } } template -inline void Vector::asNode_elemvec(const T& elemvec, R& nodevec) const +inline void Vector::asNode_impl_elemvec(const T& elemvec, R& nodevec) const { GOOSEFEM_ASSERT(xt::has_shape(elemvec, this->shape_elemvec())); GOOSEFEM_ASSERT(xt::has_shape(nodevec, this->shape_nodevec())); nodevec.fill(0.0); #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); } } } } +// asElement + +template +inline xt::xtensor Vector::AsElement(const T& arg) const +{ + xt::xtensor ret = xt::empty(this->shape_elemvec()); + this->asElement_impl(arg, ret); + return ret; +} + +template +void Vector::asElement(const T& arg, R& ret) const +{ + this->asElement_impl(arg, ret); +} + +// asElement : implementation distribution + +template ::value, int>> +inline void Vector::asElement_impl(const T& arg, R& ret) const +{ + if (arg.dimension() == 1) { + this->asElement_impl_dofval(arg, ret); + } + else if (arg.dimension() == 2) { + this->asElement_impl_nodevec(arg, ret); + } + else { + throw std::runtime_error("Vector::asElement unknown dimension for conversion"); + } +} + +template ::value == 1, int>> +inline void Vector::asElement_impl(const T& arg, R& ret) const +{ + this->asElement_impl_dofval(arg, ret); +} + +template ::value == 2, int>> +inline void Vector::asElement_impl(const T& arg, R& ret) const +{ + this->asElement_impl_nodevec(arg, ret); +} + +// asElement : implementation + template -inline void Vector::asElement_dofval(const T& dofval, R& elemvec) const +inline void Vector::asElement_impl_dofval(const T& dofval, R& elemvec) const { GOOSEFEM_ASSERT(dofval.size() == m_ndof); GOOSEFEM_ASSERT(xt::has_shape(elemvec, this->shape_elemvec())); #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)); } } } } template -inline void Vector::asElement_nodevec(const T& nodevec,R& elemvec) const +inline void Vector::asElement_impl_nodevec(const T& nodevec,R& elemvec) const { GOOSEFEM_ASSERT(xt::has_shape(nodevec, this->shape_nodevec())); GOOSEFEM_ASSERT(xt::has_shape(elemvec, this->shape_elemvec())); #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); } } } } +// assembleDofs + +template +inline xt::xtensor Vector::AssembleDofs(const T& arg) const +{ + xt::xtensor ret = xt::empty(this->shape_dofval()); + this->assembleDofs_impl(arg, ret); + return ret; +} + +template +void Vector::assembleDofs(const T& arg, R& ret) const +{ + this->assembleDofs_impl(arg, ret); +} + +// assembleDofs : implementation distribution + +template ::value, int>> +inline void Vector::assembleDofs_impl(const T& arg, R& ret) const +{ + if (arg.dimension() == 2) { + this->assembleDofs_impl_nodevec(arg, ret); + } + else if (arg.dimension() == 3) { + this->assembleDofs_impl_elemvec(arg, ret); + } + else { + throw std::runtime_error("Vector::assembleDofs unknown dimension for conversion"); + } +} + +template ::value == 2, int>> +inline void Vector::assembleDofs_impl(const T& arg, R& ret) const +{ + this->assembleDofs_impl_nodevec(arg, ret); +} + +template ::value == 3, int>> +inline void Vector::assembleDofs_impl(const T& arg, R& ret) const +{ + this->assembleDofs_impl_elemvec(arg, ret); +} + +// asDofs : implementation + template -inline void Vector::assembleDofs_nodevec(const T& nodevec, R& dofval) const +inline void Vector::assembleDofs_impl_nodevec(const T& nodevec, R& dofval) const { GOOSEFEM_ASSERT(xt::has_shape(nodevec, this->shape_nodevec())); GOOSEFEM_ASSERT(xt::has_shape(dofval, this->shape_dofval())); 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); } } } template -inline void Vector::assembleDofs_elemvec(const T& elemvec, R& dofval) const +inline void Vector::assembleDofs_impl_elemvec(const T& elemvec, R& dofval) const { GOOSEFEM_ASSERT(xt::has_shape(elemvec, this->shape_elemvec())); GOOSEFEM_ASSERT(xt::has_shape(dofval, this->shape_dofval())); 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); } } } } -template -inline void Vector::assembleNode_elemvec(const T& elemvec, R& nodevec) const -{ - GOOSEFEM_ASSERT(xt::has_shape(elemvec, this->shape_elemvec())); - GOOSEFEM_ASSERT(xt::has_shape(nodevec, this->shape_nodevec())); - - xt::xtensor dofval = this->AssembleDofs(elemvec); - this->asNode(dofval, nodevec); -} +// assembleNode template -inline xt::xtensor Vector::AsDofs(const T& arg) const +inline xt::xtensor Vector::AssembleNode(const T& arg) const { - xt::xtensor dofval = xt::empty(this->shape_dofval()); - this->asDofs(arg, dofval); - return dofval; + xt::xtensor ret = xt::empty(this->shape_nodevec()); + this->assembleNode_impl(arg, ret); + return ret; } -template -inline xt::xtensor Vector::AsNode(const T& arg) const +template +void Vector::assembleNode(const T& arg, R& ret) const { - xt::xtensor nodevec = xt::empty(this->shape_nodevec()); - this->asNode(arg, nodevec); - return nodevec; + this->assembleNode_impl(arg, ret); } -template -inline xt::xtensor Vector::AsElement(const T& arg) const -{ - xt::xtensor elemvec = xt::empty(this->shape_elemvec()); - this->asElement(arg, elemvec); - return elemvec; -} +// assembleNode : implementation distribution -template -inline xt::xtensor Vector::AssembleDofs(const T& arg) const +template ::value, int>> +inline void Vector::assembleNode_impl(const T& arg, R& ret) const { - xt::xtensor dofval = xt::empty(this->shape_dofval()); - this->assembleDofs(arg, dofval); - return dofval; + if (arg.dimension() == 3) { + this->assembleNode_impl_elemvec(arg, ret); + } + else { + throw std::runtime_error("Vector::assembleNode unknown dimension for conversion"); + } } -template -inline xt::xtensor Vector::AssembleNode(const T& arg) const +template ::value == 3, int>> +inline void Vector::assembleNode_impl(const T& arg, R& ret) const { - xt::xtensor nodevec = xt::empty(this->shape_nodevec()); - this->assembleNode(arg, nodevec); - return nodevec; + this->assembleNode_impl_elemvec(arg, ret); } -template -inline T Vector::Copy(const T& nodevec_src, const T& nodevec_dest) const +// asNode : implementation + +template +inline void Vector::assembleNode_impl_elemvec(const T& elemvec, R& nodevec) const { - T ret = T::from_shape(nodevec_dest.shape()); - this->copy(nodevec_src, ret); - return ret; + GOOSEFEM_ASSERT(xt::has_shape(elemvec, this->shape_elemvec())); + GOOSEFEM_ASSERT(xt::has_shape(nodevec, this->shape_nodevec())); + + xt::xtensor dofval = this->AssembleDofs(elemvec); + this->asNode(dofval, nodevec); } inline std::array Vector::shape_dofval() const { std::array shape; shape[0] = m_ndof; return shape; } inline std::array Vector::shape_nodevec() const { std::array shape; shape[0] = m_nnode; shape[1] = m_ndim; return shape; } inline std::array Vector::shape_elemvec() const { std::array shape; shape[0] = m_nelem; shape[1] = m_nne; shape[2] = m_ndim; return shape; } inline std::array Vector::shape_elemmat() const { std::array shape; shape[0] = m_nelem; shape[1] = m_nne * m_ndim; shape[2] = m_nne * m_ndim; return shape; } inline xt::xtensor Vector::allocate_dofval() const { xt::xtensor dofval = xt::empty(this->shape_dofval()); return dofval; } inline xt::xtensor Vector::allocate_nodevec() const { xt::xtensor nodevec = xt::empty(this->shape_nodevec()); return nodevec; } inline xt::xtensor Vector::allocate_elemvec() const { xt::xtensor elemvec = xt::empty(this->shape_elemvec()); return elemvec; } inline xt::xtensor Vector::allocate_elemmat() const { xt::xtensor elemmat = xt::empty(this->shape_elemmat()); return elemmat; } inline xt::xtensor Vector::allocate_dofval(double val) const { xt::xtensor dofval = xt::empty(this->shape_dofval()); dofval.fill(val); return dofval; } inline xt::xtensor Vector::allocate_nodevec(double val) const { xt::xtensor nodevec = xt::empty(this->shape_nodevec()); nodevec.fill(val); return nodevec; } inline xt::xtensor Vector::allocate_elemvec(double val) const { xt::xtensor elemvec = xt::empty(this->shape_elemvec()); elemvec.fill(val); return elemvec; } inline xt::xtensor Vector::allocate_elemmat(double val) const { xt::xtensor elemmat = xt::empty(this->shape_elemmat()); elemmat.fill(val); return elemmat; } } // namespace GooseFEM #endif