diff --git a/include/GooseFEM/MeshQuad4.h b/include/GooseFEM/MeshQuad4.h index 3b2fe81..e5298af 100644 --- a/include/GooseFEM/MeshQuad4.h +++ b/include/GooseFEM/MeshQuad4.h @@ -1,319 +1,325 @@ /** Generate mesh with 4-noded quadrilateral elements. \file MeshQuad4.h \copyright Copyright 2017. Tom de Geus. All rights reserved. \license This project is released under the GNU Public License (GPLv3). */ #ifndef GOOSEFEM_MESHQUAD4_H #define GOOSEFEM_MESHQUAD4_H #include "config.h" namespace GooseFEM { namespace Mesh { namespace Quad4 { // pre-allocation namespace Map { class FineLayer2Regular; } // Regular mesh: equi-sized elements 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 /** Get the element type. \return GooseFEM::Mesh::ElementType(). */ ElementType getElementType() const; // mesh xt::xtensor<double, 2> coor() const; // nodal positions [nnode, ndim] xt::xtensor<size_t, 2> conn() const; // connectivity [nelem, nne] // boundary nodes: edges xt::xtensor<size_t, 1> nodesBottomEdge() const; xt::xtensor<size_t, 1> nodesTopEdge() const; xt::xtensor<size_t, 1> nodesLeftEdge() const; xt::xtensor<size_t, 1> nodesRightEdge() const; // boundary nodes: edges, without corners xt::xtensor<size_t, 1> nodesBottomOpenEdge() const; xt::xtensor<size_t, 1> nodesTopOpenEdge() const; xt::xtensor<size_t, 1> nodesLeftOpenEdge() const; xt::xtensor<size_t, 1> 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<size_t, 2> dofs() const; // DOF-numbers for the case that the periodicity if fully eliminated xt::xtensor<size_t, 2> dofsPeriodic() const; // periodic node pairs [:,2]: (independent, dependent) xt::xtensor<size_t, 2> nodesPeriodic() const; // front-bottom-left node, used as reference for periodicity size_t nodesOrigin() const; // element numbers as matrix xt::xtensor<size_t, 2> elementgrid() 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 }; // Mesh with fine middle layer, and coarser elements towards the top and bottom class FineLayer { public: FineLayer() = default; FineLayer(size_t nelx, size_t nely, double h = 1.0, size_t nfine = 1); // Reconstruct class for given coordinates / connectivity FineLayer(const xt::xtensor<double, 2>& coor, const xt::xtensor<size_t, 2>& conn); // 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 // edge size, per row of elements (in units of "h") xt::xtensor<size_t, 1> elemrow_nhx() const; xt::xtensor<size_t, 1> elemrow_nhy() const; xt::xtensor<size_t, 1> elemrow_nelem() const; // type ElementType getElementType() const; // mesh xt::xtensor<double, 2> coor() const; // nodal positions [nnode, ndim] xt::xtensor<size_t, 2> conn() const; // connectivity [nelem, nne] // elements in the middle (fine) layer xt::xtensor<size_t, 1> elementsMiddleLayer() const; // extract elements along a layer xt::xtensor<size_t, 1> elementsLayer(size_t layer) const; // select region of elements from 'matrix' of element numbers xt::xtensor<size_t, 1> elementgrid_ravel( std::vector<size_t> rows_start_stop, std::vector<size_t> cols_start_stop) const; /** Select region of elements from 'matrix' of element numbers around an element: square box with edge-size ``(2 * size + 1) * h``, around ``element``. \param element The element around which to select elements. \param size Edge size of the square box encapsulating the selected element. \param periodic Assume the mesh periodic. \returns List of elements. */ xt::xtensor<size_t, 1> elementgrid_around_ravel( size_t element, size_t size, bool periodic = true); /** Select region of elements from 'matrix' of element numbers around an element: left/right from ``element`` (on the same layer). \param element The element around which to select elements. \param left Number of elements to select to the left. \param right Number of elements to select to the right. \param periodic Assume the mesh periodic. \returns List of elements. */ // - xt::xtensor<size_t, 1> elementgrid_leftright( size_t element, size_t left, size_t right, bool periodic = true); // boundary nodes: edges xt::xtensor<size_t, 1> nodesBottomEdge() const; xt::xtensor<size_t, 1> nodesTopEdge() const; xt::xtensor<size_t, 1> nodesLeftEdge() const; xt::xtensor<size_t, 1> nodesRightEdge() const; // boundary nodes: edges, without corners xt::xtensor<size_t, 1> nodesBottomOpenEdge() const; xt::xtensor<size_t, 1> nodesTopOpenEdge() const; xt::xtensor<size_t, 1> nodesLeftOpenEdge() const; xt::xtensor<size_t, 1> 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<size_t, 2> dofs() const; // DOF-numbers for the case that the periodicity if fully eliminated xt::xtensor<size_t, 2> dofsPeriodic() const; // periodic node pairs [:,2]: (independent, dependent) xt::xtensor<size_t, 2> nodesPeriodic() const; // front-bottom-left node, used as reference for periodicity size_t nodesOrigin() const; // mapping to 'roll' periodically in the x-direction, // returns element mapping, such that: new_elemvar = elemvar[elem_map] xt::xtensor<size_t, 1> roll(size_t n); 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<size_t, 1> m_nelx; // number of elements in "x" (*) xt::xtensor<size_t, 1> m_nnd; // total number of nodes in the main node layer (**) xt::xtensor<size_t, 1> m_nhx; // element size in x-direction (*) xt::xtensor<size_t, 1> m_nhy; // element size in y-direction (*) xt::xtensor<int, 1> m_refine; // refine direction (-1:no refine, 0:"x" (*) xt::xtensor<size_t, 1> m_startElem; // start element (*) xt::xtensor<size_t, 1> m_startNode; // start node (**) // (*) per element layer in "y" // (**) per node layer in "y" void init(size_t nelx, size_t nely, double h, size_t nfine = 1); void map(const xt::xtensor<double, 2>& coor, const xt::xtensor<size_t, 2>& conn); friend class GooseFEM::Mesh::Quad4::Map::FineLayer2Regular; }; // Mesh mappings namespace Map { // Return "FineLayer"-class responsible for generating a connectivity // Throws if conversion is not possible GooseFEM::Mesh::Quad4::FineLayer FineLayer( const xt::xtensor<double, 2>& coor, const xt::xtensor<size_t, 2>& conn); // Refine a regular mesh: sub-divide elements in several smaller elements class RefineRegular { public: // Constructors RefineRegular() = default; RefineRegular(const GooseFEM::Mesh::Quad4::Regular& mesh, size_t nx, size_t ny); // return the coarse or the fine mesh objects 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<size_t, 2> getMap() const; // map field xt::xtensor<double, 2> mapToCoarse(const xt::xtensor<double, 1>& data) const; // scalar per el xt::xtensor<double, 2> mapToCoarse(const xt::xtensor<double, 2>& data) const; // scalar per intpnt xt::xtensor<double, 4> mapToCoarse(const xt::xtensor<double, 4>& data) const; // tensor per intpnt // map field xt::xtensor<double, 1> mapToFine(const xt::xtensor<double, 1>& data) const; // scalar per el xt::xtensor<double, 2> mapToFine(const xt::xtensor<double, 2>& data) const; // scalar per intpnt xt::xtensor<double, 4> mapToFine(const xt::xtensor<double, 4>& data) const; // tensor per intpnt private: // the meshes GooseFEM::Mesh::Quad4::Regular m_coarse; GooseFEM::Mesh::Quad4::Regular m_fine; // mapping xt::xtensor<size_t, 1> m_fine2coarse; xt::xtensor<size_t, 1> m_fine2coarse_index; xt::xtensor<size_t, 2> m_coarse2fine; }; 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<std::vector<size_t>> getMap() const; std::vector<std::vector<double>> getMapFraction() const; - // map field - xt::xtensor<double, 1> mapToRegular(const xt::xtensor<double, 1>& data) const; // scalar per el - xt::xtensor<double, 2> mapToRegular(const xt::xtensor<double, 2>& data) const; // scalar per intpnt - xt::xtensor<double, 4> mapToRegular(const xt::xtensor<double, 4>& data) const; // tensor per intpnt + /** + Map integration point quantities to Regular. + + \tparam T The type of the data (e.g. ``double``). + \tparam rank Rank of the data. + \param arg The data. + \return The mapped data. + */ + template <class T, size_t rank> + xt::xtensor<T, rank> mapToRegular(const xt::xtensor<T, rank>& arg) const; 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<std::vector<size_t>> m_elem_regular; std::vector<std::vector<double>> 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 71ac6cc..ac7fc7a 100644 --- a/include/GooseFEM/MeshQuad4.hpp +++ b/include/GooseFEM/MeshQuad4.hpp @@ -1,1646 +1,1618 @@ /* (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<double, 2> Regular::coor() const { xt::xtensor<double, 2> ret = xt::empty<double>({m_nnode, m_ndim}); xt::xtensor<double, 1> x = xt::linspace<double>(0.0, m_h * static_cast<double>(m_nelx), m_nelx + 1); xt::xtensor<double, 1> y = xt::linspace<double>(0.0, m_h * static_cast<double>(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) { ret(inode, 0) = x(ix); ret(inode, 1) = y(iy); ++inode; } } return ret; } inline xt::xtensor<size_t, 2> Regular::conn() const { xt::xtensor<size_t, 2> ret = xt::empty<size_t>({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) { ret(ielem, 0) = (iy) * (m_nelx + 1) + (ix); ret(ielem, 1) = (iy) * (m_nelx + 1) + (ix + 1); ret(ielem, 3) = (iy + 1) * (m_nelx + 1) + (ix); ret(ielem, 2) = (iy + 1) * (m_nelx + 1) + (ix + 1); ++ielem; } } return ret; } inline xt::xtensor<size_t, 1> Regular::nodesBottomEdge() const { return xt::arange<size_t>(m_nelx + 1); } inline xt::xtensor<size_t, 1> Regular::nodesTopEdge() const { return xt::arange<size_t>(m_nelx + 1) + m_nely * (m_nelx + 1); } inline xt::xtensor<size_t, 1> Regular::nodesLeftEdge() const { return xt::arange<size_t>(m_nely + 1) * (m_nelx + 1); } inline xt::xtensor<size_t, 1> Regular::nodesRightEdge() const { return xt::arange<size_t>(m_nely + 1) * (m_nelx + 1) + m_nelx; } inline xt::xtensor<size_t, 1> Regular::nodesBottomOpenEdge() const { return xt::arange<size_t>(1, m_nelx); } inline xt::xtensor<size_t, 1> Regular::nodesTopOpenEdge() const { return xt::arange<size_t>(1, m_nelx) + m_nely * (m_nelx + 1); } inline xt::xtensor<size_t, 1> Regular::nodesLeftOpenEdge() const { return xt::arange<size_t>(1, m_nely) * (m_nelx + 1); } inline xt::xtensor<size_t, 1> Regular::nodesRightOpenEdge() const { return xt::arange<size_t>(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<size_t, 2> Regular::nodesPeriodic() const { xt::xtensor<size_t, 1> bot = nodesBottomOpenEdge(); xt::xtensor<size_t, 1> top = nodesTopOpenEdge(); xt::xtensor<size_t, 1> lft = nodesLeftOpenEdge(); xt::xtensor<size_t, 1> rgt = nodesRightOpenEdge(); std::array<size_t, 2> shape = {bot.size() + lft.size() + 3ul, 2ul}; xt::xtensor<size_t, 2> ret = xt::empty<size_t>(shape); ret(0, 0) = nodesBottomLeftCorner(); ret(0, 1) = nodesBottomRightCorner(); ret(1, 0) = nodesBottomLeftCorner(); ret(1, 1) = nodesTopRightCorner(); ret(2, 0) = nodesBottomLeftCorner(); ret(2, 1) = nodesTopLeftCorner(); size_t i = 3; xt::view(ret, xt::range(i, i + bot.size()), 0) = bot; xt::view(ret, xt::range(i, i + bot.size()), 1) = top; i += bot.size(); xt::view(ret, xt::range(i, i + lft.size()), 0) = lft; xt::view(ret, xt::range(i, i + lft.size()), 1) = rgt; return ret; } inline size_t Regular::nodesOrigin() const { return nodesBottomLeftCorner(); } inline xt::xtensor<size_t, 2> Regular::dofs() const { return GooseFEM::Mesh::dofs(m_nnode, m_ndim); } inline xt::xtensor<size_t, 2> Regular::dofsPeriodic() const { xt::xtensor<size_t, 2> ret = GooseFEM::Mesh::dofs(m_nnode, m_ndim); xt::xtensor<size_t, 2> nodePer = nodesPeriodic(); xt::xtensor<size_t, 1> independent = xt::view(nodePer, xt::all(), 0); xt::xtensor<size_t, 1> dependent = xt::view(nodePer, xt::all(), 1); for (size_t j = 0; j < m_ndim; ++j) { xt::view(ret, xt::keep(dependent), j) = xt::view(ret, xt::keep(independent), j); } return GooseFEM::Mesh::renumber(ret); } inline xt::xtensor<size_t, 2> Regular::elementgrid() const { return xt::arange<size_t>(m_nelem).reshape({m_nely, m_nelx}); } inline FineLayer::FineLayer(size_t nelx, size_t nely, double h, size_t nfine) { this->init(nelx, nely, h, nfine); } inline FineLayer::FineLayer(const xt::xtensor<double, 2>& coor, const xt::xtensor<size_t, 2>& conn) { this->map(coor, conn); } inline void FineLayer::init(size_t nelx, size_t nely, double h, size_t nfine) { GOOSEFEM_ASSERT(nelx >= 1ul); GOOSEFEM_ASSERT(nely >= 1ul); m_h = h; m_Lx = m_h * static_cast<double>(nelx); // compute element size in y-direction (use symmetry, compute upper half) // temporary variables size_t nmin, ntot; xt::xtensor<size_t, 1> nhx = xt::ones<size_t>({nely}); xt::xtensor<size_t, 1> nhy = xt::ones<size_t>({nely}); xt::xtensor<int, 1> refine = -1 * xt::ones<int>({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<size_t>({nely * 2 - 1}); m_nhy = xt::empty<size_t>({nely * 2 - 1}); m_refine = xt::empty<int>({nely * 2 - 1}); m_nelx = xt::empty<size_t>({nely * 2 - 1}); m_nnd = xt::empty<size_t>({nely * 2}); m_startElem = xt::empty<size_t>({nely * 2 - 1}); m_startNode = xt::empty<size_t>({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)(); } inline size_t FineLayer::nely() const { return xt::sum(m_nhy)(); } inline double FineLayer::h() const { return m_h; } inline xt::xtensor<size_t, 1> FineLayer::elemrow_nhx() const { return m_nhx; } inline xt::xtensor<size_t, 1> FineLayer::elemrow_nhy() const { return m_nhy; } inline xt::xtensor<size_t, 1> FineLayer::elemrow_nelem() const { return m_nelx; } inline ElementType FineLayer::getElementType() const { return ElementType::Quad4; } inline xt::xtensor<double, 2> FineLayer::coor() const { // allocate output xt::xtensor<double, 2> ret = xt::empty<double>({m_nnode, m_ndim}); // current node, number of element layers size_t inode = 0; size_t nely = static_cast<size_t>(m_nhy.size()); // y-position of each main node layer (i.e. excluding node layers for refinement/coarsening) // - allocate xt::xtensor<double, 1> y = xt::empty<double>({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<double, 1> x = xt::linspace<double>(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) { ret(inode, 0) = x(ix); ret(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<double>(m_nhx(iy) / 3); double dy = m_h * static_cast<double>(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) { ret(inode, 0) = x(ix) + dx * static_cast<double>(j + 1); ret(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<double, 1> x = xt::linspace<double>(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<double>(m_nhx(iy) / 3); double dy = m_h * static_cast<double>(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) { ret(inode, 0) = x(ix) + dx * static_cast<double>(j + 1); ret(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) { ret(inode, 0) = x(ix); ret(inode, 1) = y(iy + 1); ++inode; } } return ret; } inline xt::xtensor<size_t, 2> FineLayer::conn() const { // allocate output xt::xtensor<size_t, 2> ret = xt::empty<size_t>({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<size_t>(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) { ret(ielem, 0) = bot + (ix); ret(ielem, 1) = bot + (ix + 1); ret(ielem, 2) = top + (ix + 1); ret(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 ret(ielem, 0) = bot + (ix); ret(ielem, 1) = bot + (ix + 1); ret(ielem, 2) = mid + (2 * ix + 1); ret(ielem, 3) = mid + (2 * ix); ielem++; // -- top-right element ret(ielem, 0) = bot + (ix + 1); ret(ielem, 1) = top + (3 * ix + 3); ret(ielem, 2) = top + (3 * ix + 2); ret(ielem, 3) = mid + (2 * ix + 1); ielem++; // -- top-center element ret(ielem, 0) = mid + (2 * ix); ret(ielem, 1) = mid + (2 * ix + 1); ret(ielem, 2) = top + (3 * ix + 2); ret(ielem, 3) = top + (3 * ix + 1); ielem++; // -- top-left element ret(ielem, 0) = bot + (ix); ret(ielem, 1) = mid + (2 * ix); ret(ielem, 2) = top + (3 * ix + 1); ret(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 ret(ielem, 0) = bot + (3 * ix); ret(ielem, 1) = bot + (3 * ix + 1); ret(ielem, 2) = mid + (2 * ix); ret(ielem, 3) = top + (ix); ielem++; // -- lower-center element ret(ielem, 0) = bot + (3 * ix + 1); ret(ielem, 1) = bot + (3 * ix + 2); ret(ielem, 2) = mid + (2 * ix + 1); ret(ielem, 3) = mid + (2 * ix); ielem++; // -- lower-right element ret(ielem, 0) = bot + (3 * ix + 2); ret(ielem, 1) = bot + (3 * ix + 3); ret(ielem, 2) = top + (ix + 1); ret(ielem, 3) = mid + (2 * ix + 1); ielem++; // -- upper element ret(ielem, 0) = mid + (2 * ix); ret(ielem, 1) = mid + (2 * ix + 1); ret(ielem, 2) = top + (ix + 1); ret(ielem, 3) = top + (ix); ielem++; } } } return ret; } inline xt::xtensor<size_t, 1> FineLayer::elementsMiddleLayer() const { size_t nely = m_nhy.size(); size_t iy = (nely - 1) / 2; return m_startElem(iy) + xt::arange<size_t>(m_nelx(iy)); } inline xt::xtensor<size_t, 1> FineLayer::elementsLayer(size_t iy) const { GOOSEFEM_ASSERT(iy < m_nelx.size()); size_t n = m_nelx(iy); if (m_refine(iy) != -1) { n *= 4; } return m_startElem(iy) + xt::arange<size_t>(n); } inline xt::xtensor<size_t, 1> FineLayer::elementgrid_ravel( std::vector<size_t> start_stop_rows, std::vector<size_t> start_stop_cols) const { GOOSEFEM_ASSERT(start_stop_rows.size() == 0 || start_stop_rows.size() == 2); GOOSEFEM_ASSERT(start_stop_cols.size() == 0 || start_stop_cols.size() == 2); std::array<size_t, 2> rows; std::array<size_t, 2> cols; if (start_stop_rows.size() == 2) { std::copy(start_stop_rows.begin(), start_stop_rows.end(), rows.begin()); GOOSEFEM_ASSERT(rows[0] <= this->nely()); GOOSEFEM_ASSERT(rows[1] <= this->nely()); } else { rows[0] = 0; rows[1] = this->nely(); } if (start_stop_cols.size() == 2) { std::copy(start_stop_cols.begin(), start_stop_cols.end(), cols.begin()); GOOSEFEM_ASSERT(cols[0] <= this->nelx()); GOOSEFEM_ASSERT(cols[1] <= this->nelx()); } else { cols[0] = 0; cols[1] = this->nelx(); } if (rows[0] == rows[1] || cols[0] == cols[1]) { xt::xtensor<size_t, 1> ret = xt::empty<size_t>({0}); return ret; } // Compute dimensions auto H = xt::cumsum(m_nhy); size_t yl = 0; if (rows[0] > 0) { yl = xt::argmax(H > rows[0])(); } size_t yu = xt::argmax(H >= rows[1])(); size_t hx = std::max(m_nhx(yl), m_nhx(yu)); size_t xl = (cols[0] - cols[0] % hx) / hx; size_t xu = (cols[1] - cols[1] % hx) / hx; // Allocate output size_t N = 0; for (size_t i = yl; i <= yu; ++i) { // no refinement size_t n = (xu - xl) * hx / m_nhx(i); // refinement if (m_refine(i) != -1) { n *= 4; } N += n; } xt::xtensor<size_t, 1> ret = xt::empty<size_t>({N}); // Write output N = 0; for (size_t i = yl; i <= yu; ++i) { // no refinement size_t n = (xu - xl) * hx / m_nhx(i); size_t h = hx; // refinement if (m_refine(i) != -1) { n *= 4; h *= 4; } xt::xtensor<size_t, 1> e = m_startElem(i) + xl * h / m_nhx(i) + xt::arange<size_t>(n); xt::view(ret, xt::range(N, N + n)) = e; N += n; } return ret; } inline xt::xtensor<size_t, 1> FineLayer::elementgrid_around_ravel( size_t e, size_t size, bool periodic) { GOOSEFEM_WIP_ASSERT(periodic == true); size_t iy = xt::argmin(m_startElem <= e)() - 1; size_t nel = m_nelx(iy); GOOSEFEM_WIP_ASSERT(iy == (m_nhy.size() - 1) / 2); auto H = xt::cumsum(m_nhy); if (2 * size >= H(H.size() - 1)) { return xt::arange<size_t>(this->nelem()); } size_t hy = H(iy); size_t l = xt::argmax(H > (hy - size - 1))(); size_t u = xt::argmax(H >= (hy + size))(); size_t lh = 0; if (l > 0) { lh = H(l - 1); } size_t uh = H(u); size_t step = xt::amax(m_nhx)(); size_t relx = (e - m_startElem(iy)) % step; size_t mid = (nel / step - (nel / step) % 2) / 2 * step + relx; size_t nroll = (nel - (nel - mid + e - m_startElem(iy)) % nel) / step; size_t dx = m_nhx(u); size_t xl = 0; size_t xu = nel; if (mid >= size) { xl = mid - size; } if (mid + size < nel) { xu = mid + size + 1; } xl = xl - xl % dx; xu = xu - xu % dx; if (mid - xl < size) { if (xl < dx) { xl = 0; } else { xl -= dx; } } if (xu - mid < size) { if (xu > nel - dx) { xu = nel; } else { xu += dx; } } auto ret = this->elementgrid_ravel({lh, uh}, {xl, xu}); auto map = this->roll(nroll); return xt::view(map, xt::keep(ret)); } inline xt::xtensor<size_t, 1> FineLayer::elementgrid_leftright( size_t e, size_t left, size_t right, bool periodic) { GOOSEFEM_WIP_ASSERT(periodic == true); size_t iy = xt::argmin(m_startElem <= e)() - 1; size_t nel = m_nelx(iy); GOOSEFEM_WIP_ASSERT(iy == (m_nhy.size() - 1) / 2); size_t step = xt::amax(m_nhx)(); size_t relx = (e - m_startElem(iy)) % step; size_t mid = (nel / step - (nel / step) % 2) / 2 * step + relx; size_t nroll = (nel - (nel - mid + e - m_startElem(iy)) % nel) / step; size_t dx = m_nhx(iy); size_t xl = 0; size_t xu = nel; if (mid >= left) { xl = mid - left; } if (mid + right < nel) { xu = mid + right + 1; } xl = xl - xl % dx; xu = xu - xu % dx; if (mid - xl < left) { if (xl < dx) { xl = 0; } else { xl -= dx; } } if (xu - mid < right) { if (xu > nel - dx) { xu = nel; } else { xu += dx; } } auto H = xt::cumsum(m_nhy); size_t yl = 0; if (iy > 0) { yl = H(iy - 1); } auto ret = this->elementgrid_ravel({yl, H(iy)}, {xl, xu}); auto map = this->roll(nroll); return xt::view(map, xt::keep(ret)); } inline xt::xtensor<size_t, 1> FineLayer::nodesBottomEdge() const { return m_startNode(0) + xt::arange<size_t>(m_nelx(0) + 1); } inline xt::xtensor<size_t, 1> FineLayer::nodesTopEdge() const { size_t nely = m_nhy.size(); return m_startNode(nely) + xt::arange<size_t>(m_nelx(nely - 1) + 1); } inline xt::xtensor<size_t, 1> FineLayer::nodesLeftEdge() const { size_t nely = m_nhy.size(); xt::xtensor<size_t, 1> ret = xt::empty<size_t>({nely + 1}); size_t i = 0; size_t j = (nely + 1) / 2; size_t k = (nely - 1) / 2; size_t l = nely; xt::view(ret, xt::range(i, j)) = xt::view(m_startNode, xt::range(i, j)); xt::view(ret, xt::range(k + 1, l + 1)) = xt::view(m_startNode, xt::range(k + 1, l + 1)); return ret; } inline xt::xtensor<size_t, 1> FineLayer::nodesRightEdge() const { size_t nely = m_nhy.size(); xt::xtensor<size_t, 1> ret = xt::empty<size_t>({nely + 1}); size_t i = 0; size_t j = (nely + 1) / 2; size_t k = (nely - 1) / 2; size_t l = nely; xt::view(ret, xt::range(i, j)) = xt::view(m_startNode, xt::range(i, j)) + xt::view(m_nelx, xt::range(i, j)); xt::view(ret, 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 ret; } inline xt::xtensor<size_t, 1> FineLayer::nodesBottomOpenEdge() const { return m_startNode(0) + xt::arange<size_t>(1, m_nelx(0)); } inline xt::xtensor<size_t, 1> FineLayer::nodesTopOpenEdge() const { size_t nely = m_nhy.size(); return m_startNode(nely) + xt::arange<size_t>(1, m_nelx(nely - 1)); } inline xt::xtensor<size_t, 1> FineLayer::nodesLeftOpenEdge() const { size_t nely = m_nhy.size(); xt::xtensor<size_t, 1> ret = xt::empty<size_t>({nely - 1}); size_t i = 0; size_t j = (nely + 1) / 2; size_t k = (nely - 1) / 2; size_t l = nely; xt::view(ret, xt::range(i, j - 1)) = xt::view(m_startNode, xt::range(i + 1, j)); xt::view(ret, xt::range(k, l - 1)) = xt::view(m_startNode, xt::range(k + 1, l)); return ret; } inline xt::xtensor<size_t, 1> FineLayer::nodesRightOpenEdge() const { size_t nely = m_nhy.size(); xt::xtensor<size_t, 1> ret = xt::empty<size_t>({nely - 1}); size_t i = 0; size_t j = (nely + 1) / 2; size_t k = (nely - 1) / 2; size_t l = nely; xt::view(ret, 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(ret, xt::range(k, l - 1)) = xt::view(m_startNode, xt::range(k + 1, l)) + xt::view(m_nelx, xt::range(k, l - 1)); return ret; } 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<size_t, 2> FineLayer::nodesPeriodic() const { xt::xtensor<size_t, 1> bot = nodesBottomOpenEdge(); xt::xtensor<size_t, 1> top = nodesTopOpenEdge(); xt::xtensor<size_t, 1> lft = nodesLeftOpenEdge(); xt::xtensor<size_t, 1> rgt = nodesRightOpenEdge(); std::array<size_t, 2> shape = {bot.size() + lft.size() + 3ul, 2ul}; xt::xtensor<size_t, 2> ret = xt::empty<size_t>(shape); ret(0, 0) = nodesBottomLeftCorner(); ret(0, 1) = nodesBottomRightCorner(); ret(1, 0) = nodesBottomLeftCorner(); ret(1, 1) = nodesTopRightCorner(); ret(2, 0) = nodesBottomLeftCorner(); ret(2, 1) = nodesTopLeftCorner(); size_t i = 3; xt::view(ret, xt::range(i, i + bot.size()), 0) = bot; xt::view(ret, xt::range(i, i + bot.size()), 1) = top; i += bot.size(); xt::view(ret, xt::range(i, i + lft.size()), 0) = lft; xt::view(ret, xt::range(i, i + lft.size()), 1) = rgt; return ret; } inline size_t FineLayer::nodesOrigin() const { return nodesBottomLeftCorner(); } inline xt::xtensor<size_t, 2> FineLayer::dofs() const { return GooseFEM::Mesh::dofs(m_nnode, m_ndim); } inline xt::xtensor<size_t, 2> FineLayer::dofsPeriodic() const { xt::xtensor<size_t, 2> ret = GooseFEM::Mesh::dofs(m_nnode, m_ndim); xt::xtensor<size_t, 2> nodePer = nodesPeriodic(); xt::xtensor<size_t, 1> independent = xt::view(nodePer, xt::all(), 0); xt::xtensor<size_t, 1> dependent = xt::view(nodePer, xt::all(), 1); for (size_t j = 0; j < m_ndim; ++j) { xt::view(ret, xt::keep(dependent), j) = xt::view(ret, xt::keep(independent), j); } return GooseFEM::Mesh::renumber(ret); } inline xt::xtensor<size_t, 1> FineLayer::roll(size_t n) { auto conn = this->conn(); size_t nely = static_cast<size_t>(m_nhy.size()); xt::xtensor<size_t, 1> ret = xt::empty<size_t>({m_nelem}); // loop over all element layers for (size_t iy = 0; iy < nely; ++iy) { // no refinement size_t shift = n * (m_nelx(iy) / m_nelx(0)); size_t nel = m_nelx(iy); // refinement if (m_refine(iy) != -1) { shift = n * (m_nelx(iy) / m_nelx(0)) * 4; nel = m_nelx(iy) * 4; } // element numbers of the layer, and roll them auto e = m_startElem(iy) + xt::arange<size_t>(nel); xt::view(ret, xt::range(m_startElem(iy), m_startElem(iy) + nel)) = xt::roll(e, shift); } return ret; } inline void FineLayer::map(const xt::xtensor<double, 2>& coor, const xt::xtensor<size_t, 2>& conn) { GOOSEFEM_ASSERT(coor.shape(1) == 2); GOOSEFEM_ASSERT(conn.shape(1) == 4); GOOSEFEM_ASSERT(conn.shape(0) > 0); GOOSEFEM_ASSERT(coor.shape(0) >= 4); GOOSEFEM_ASSERT(xt::amax(conn)() < coor.shape(0)); if (conn.shape(0) == 1) { this->init(1, 1, coor(conn(0, 1), 0) - coor(conn(0, 0), 0)); GOOSEFEM_CHECK(xt::all(xt::equal(this->conn(), conn))); GOOSEFEM_CHECK(xt::allclose(this->coor(), coor)); return; } // Identify the middle layer size_t emid = (conn.shape(0) - conn.shape(0) % 2) / 2; size_t eleft = emid; size_t eright = emid; while (conn(eleft, 0) == conn(eleft - 1, 1) && eleft > 0) { eleft--; } while (conn(eright, 1) == conn(eright + 1, 0) && eright < conn.shape(0) - 1) { eright++; } GOOSEFEM_CHECK(xt::allclose(coor(conn(eleft, 0), 0), 0.0)); // Get element sizes along the middle layer auto n0 = xt::view(conn, xt::range(eleft, eright + 1), 0); auto n1 = xt::view(conn, xt::range(eleft, eright + 1), 1); auto n2 = xt::view(conn, xt::range(eleft, eright + 1), 2); auto dx = xt::view(coor, xt::keep(n1), 0) - xt::view(coor, xt::keep(n0), 0); auto dy = xt::view(coor, xt::keep(n2), 1) - xt::view(coor, xt::keep(n1), 1); auto hx = xt::amin(dx)(); auto hy = xt::amin(dy)(); GOOSEFEM_CHECK(xt::allclose(hx, hy)); GOOSEFEM_CHECK(xt::allclose(dx, hx)); GOOSEFEM_CHECK(xt::allclose(dy, hy)); // Extract shape and initialise size_t nelx = eright - eleft + 1; size_t nely = static_cast<size_t>((coor(coor.shape(0) - 1, 1) - coor(0, 1)) / hx); this->init(nelx, nely, hx); GOOSEFEM_CHECK(xt::all(xt::equal(this->conn(), conn))); GOOSEFEM_CHECK(xt::allclose(this->coor(), coor)); GOOSEFEM_CHECK(xt::all(xt::equal(this->elementsMiddleLayer(), eleft + xt::arange<size_t>(nelx)))); } 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<size_t, 2> elmat_coarse = m_coarse.elementgrid(); xt::xtensor<size_t, 2> elmat_fine = m_fine.elementgrid(); m_coarse2fine = xt::empty<size_t>({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<size_t, 2> RefineRegular::getMap() const { return m_coarse2fine; } inline xt::xtensor<double, 2> RefineRegular::mapToCoarse(const xt::xtensor<double, 1>& 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<double, 2> ret = xt::empty<double>({m, n}); for (size_t i = 0; i < m; ++i) { auto e = xt::view(m_coarse2fine, i, xt::all()); xt::view(ret, i) = xt::view(data, xt::keep(e)); } return ret; } inline xt::xtensor<double, 2> RefineRegular::mapToCoarse(const xt::xtensor<double, 2>& 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<double, 2> ret = xt::empty<double>({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(ret, i, xt::range(q + 0, q + n * N, N)) = xt::view(data, xt::keep(e), q); } } return ret; } inline xt::xtensor<double, 4> RefineRegular::mapToCoarse(const xt::xtensor<double, 4>& 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<double, 4> ret = xt::empty<double>({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(ret, i, xt::range(q + 0, q + n * N, N)) = xt::view(data, xt::keep(e), q); } } return ret; } inline xt::xtensor<double, 1> RefineRegular::mapToFine(const xt::xtensor<double, 1>& data) const { GOOSEFEM_ASSERT(data.shape(0) == m_coarse2fine.shape(0)); xt::xtensor<double, 1> ret = xt::empty<double>({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(ret, xt::keep(e)) = data(i); } return ret; } inline xt::xtensor<double, 2> RefineRegular::mapToFine(const xt::xtensor<double, 2>& data) const { GOOSEFEM_ASSERT(data.shape(0) == m_coarse2fine.shape(0)); xt::xtensor<double, 2> ret = xt::empty<double>({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(ret, xt::keep(e)) = xt::view(data, i); } return ret; } inline xt::xtensor<double, 4> RefineRegular::mapToFine(const xt::xtensor<double, 4>& data) const { GOOSEFEM_ASSERT(data.shape(0) == m_coarse2fine.shape(0)); xt::xtensor<double, 4> ret = xt::empty<double>({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(ret, xt::keep(e)) = xt::view(data, i); } return ret; } 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)(), xt::sum(m_finelayer.m_nhy)(), 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<size_t, 1> nhx = m_finelayer.m_nhx; xt::xtensor<size_t, 1> nhy = m_finelayer.m_nhy; xt::xtensor<size_t, 1> nelx = m_finelayer.m_nelx; xt::xtensor<size_t, 1> start = m_finelayer.m_startElem; // 'matrix' of element numbers of the Regular-mesh xt::xtensor<size_t, 2> elementgrid = m_regular.elementgrid(); // cumulative number of element-rows of the Regular-mesh per layer of the FineLayer-mesh xt::xtensor<size_t, 1> cum_nhy = xt::concatenate(xt::xtuple(xt::zeros<size_t>({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(elementgrid, 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<size_t, 1> el_old = start(iy) + xt::arange<size_t>(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<size_t, 2> el_old = start(iy) + xt::arange<size_t>(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<size_t, 2> el_old = start(iy) + xt::arange<size_t>(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<std::vector<size_t>> FineLayer2Regular::getMap() const { return m_elem_regular; } inline std::vector<std::vector<double>> FineLayer2Regular::getMapFraction() const { return m_frac_regular; } -inline xt::xtensor<double, 1> -FineLayer2Regular::mapToRegular(const xt::xtensor<double, 1>& data) const +template <class T, size_t rank> +inline xt::xtensor<T, rank> +FineLayer2Regular::mapToRegular(const xt::xtensor<T, rank>& data) const { GOOSEFEM_ASSERT(data.shape(0) == m_finelayer.nelem()); - xt::xtensor<double, 1> ret = xt::zeros<double>({m_regular.nelem()}); + std::array<size_t, rank> shape; + std::copy(data.shape().cbegin(), data.shape().cend(), &shape[0]); + shape[0] = 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) { - ret(m_elem_regular[e][i]) += m_frac_regular[e][i] * data(e); - } - } - - return ret; -} - -inline xt::xtensor<double, 2> -FineLayer2Regular::mapToRegular(const xt::xtensor<double, 2>& data) const -{ - GOOSEFEM_ASSERT(data.shape(0) == m_finelayer.nelem()); - - xt::xtensor<double, 2> ret = xt::zeros<double>({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(ret, m_elem_regular[e][i]) += m_frac_regular[e][i] * xt::view(data, e); - } - } - - return ret; -} - -inline xt::xtensor<double, 4> -FineLayer2Regular::mapToRegular(const xt::xtensor<double, 4>& data) const -{ - GOOSEFEM_ASSERT(data.shape(0) == m_finelayer.nelem()); - - xt::xtensor<double, 4> ret = - xt::zeros<double>({m_regular.nelem(), data.shape(1), data.shape(2), data.shape(3)}); + xt::xtensor<T, rank> ret = xt::zeros<T>(shape); for (size_t e = 0; e < m_finelayer.nelem(); ++e) { for (size_t i = 0; i < m_elem_regular[e].size(); ++i) { xt::view(ret, m_elem_regular[e][i]) += m_frac_regular[e][i] * xt::view(data, e); } } return ret; } } // namespace Map } // namespace Quad4 } // namespace Mesh } // namespace GooseFEM #endif diff --git a/include/GooseFEM/VectorPartitioned.hpp b/include/GooseFEM/VectorPartitioned.hpp index dca41a3..92ba965 100644 --- a/include/GooseFEM/VectorPartitioned.hpp +++ b/include/GooseFEM/VectorPartitioned.hpp @@ -1,757 +1,757 @@ /* (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<size_t, 2>& conn, const xt::xtensor<size_t, 2>& dofs, const xt::xtensor<size_t, 1>& 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(m_dofs, m_iip); m_ndof = xt::amax(m_dofs)() + 1; m_nnp = m_iip.size(); m_nnu = m_iiu.size(); - m_part = Mesh::Reorder({m_iiu, m_iip}).get(m_dofs); + m_part = Mesh::Reorder({m_iiu, m_iip}).apply(m_dofs); GOOSEFEM_ASSERT(xt::amax(m_conn)() + 1 <= m_nnode); GOOSEFEM_ASSERT(xt::amax(m_iip)() <= xt::amax(m_dofs)()); 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<size_t, 2> VectorPartitioned::dofs() const { return m_dofs; } inline xt::xtensor<size_t, 1> VectorPartitioned::iiu() const { return m_iiu; } inline xt::xtensor<size_t, 1> VectorPartitioned::iip() const { return m_iip; } inline void VectorPartitioned::copy( const xt::xtensor<double, 2>& nodevec_src, xt::xtensor<double, 2>& nodevec_dest) const { GOOSEFEM_ASSERT(xt::has_shape(nodevec_src, {m_nnode, m_ndim})); GOOSEFEM_ASSERT(xt::has_shape(nodevec_dest, {m_nnode, m_ndim})); xt::noalias(nodevec_dest) = nodevec_src; } inline void VectorPartitioned::copy_u( const xt::xtensor<double, 2>& nodevec_src, xt::xtensor<double, 2>& nodevec_dest) const { GOOSEFEM_ASSERT(xt::has_shape(nodevec_src, {m_nnode, m_ndim})); GOOSEFEM_ASSERT(xt::has_shape(nodevec_dest, {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<double, 2>& nodevec_src, xt::xtensor<double, 2>& nodevec_dest) const { GOOSEFEM_ASSERT(xt::has_shape(nodevec_src, {m_nnode, m_ndim})); GOOSEFEM_ASSERT(xt::has_shape(nodevec_dest, {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<double, 1>& dofval_u, const xt::xtensor<double, 1>& dofval_p, xt::xtensor<double, 1>& dofval) const { GOOSEFEM_ASSERT(dofval_u.size() == m_nnu); GOOSEFEM_ASSERT(dofval_p.size() == m_nnp); GOOSEFEM_ASSERT(dofval.size() == m_ndof); dofval.fill(0.0); #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<double, 2>& nodevec, xt::xtensor<double, 1>& dofval) const { GOOSEFEM_ASSERT(xt::has_shape(nodevec, {m_nnode, m_ndim})); GOOSEFEM_ASSERT(dofval.size() == m_ndof); 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); } } } inline void VectorPartitioned::asDofs_u( const xt::xtensor<double, 1>& dofval, xt::xtensor<double, 1>& 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<double, 2>& nodevec, xt::xtensor<double, 1>& dofval_u) const { GOOSEFEM_ASSERT(xt::has_shape(nodevec, {m_nnode, m_ndim})); GOOSEFEM_ASSERT(dofval_u.size() == m_nnu); dofval_u.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) { if (m_part(m, i) < m_nnu) { dofval_u(m_part(m, i)) = nodevec(m, i); } } } } inline void VectorPartitioned::asDofs_p( const xt::xtensor<double, 1>& dofval, xt::xtensor<double, 1>& 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<double, 2>& nodevec, xt::xtensor<double, 1>& dofval_p) const { GOOSEFEM_ASSERT(xt::has_shape(nodevec, {m_nnode, m_ndim})); GOOSEFEM_ASSERT(dofval_p.size() == m_nnp); dofval_p.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) { 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<double, 3>& elemvec, xt::xtensor<double, 1>& dofval) const { GOOSEFEM_ASSERT(xt::has_shape(elemvec, {m_nelem, m_nne, m_ndim})); GOOSEFEM_ASSERT(dofval.size() == m_ndof); 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); } } } } inline void VectorPartitioned::asDofs_u( const xt::xtensor<double, 3>& elemvec, xt::xtensor<double, 1>& dofval_u) const { GOOSEFEM_ASSERT(xt::has_shape(elemvec, {m_nelem, m_nne, m_ndim})); GOOSEFEM_ASSERT(dofval_u.size() == m_nnu); dofval_u.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) { 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<double, 3>& elemvec, xt::xtensor<double, 1>& dofval_p) const { GOOSEFEM_ASSERT(xt::has_shape(elemvec, {m_nelem, m_nne, m_ndim})); GOOSEFEM_ASSERT(dofval_p.size() == m_nnp); dofval_p.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) { 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<double, 1>& dofval, xt::xtensor<double, 2>& nodevec) const { GOOSEFEM_ASSERT(dofval.size() == m_ndof); GOOSEFEM_ASSERT(xt::has_shape(nodevec, {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<double, 1>& dofval_u, const xt::xtensor<double, 1>& dofval_p, xt::xtensor<double, 2>& nodevec) const { GOOSEFEM_ASSERT(dofval_u.size() == m_nnu); GOOSEFEM_ASSERT(dofval_p.size() == m_nnp); GOOSEFEM_ASSERT(xt::has_shape(nodevec, {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<double, 3>& elemvec, xt::xtensor<double, 2>& nodevec) const { GOOSEFEM_ASSERT(xt::has_shape(elemvec, {m_nelem, m_nne, m_ndim})); GOOSEFEM_ASSERT(xt::has_shape(nodevec, {m_nnode, m_ndim})); 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); } } } } inline void VectorPartitioned::asElement( const xt::xtensor<double, 1>& dofval, xt::xtensor<double, 3>& elemvec) const { GOOSEFEM_ASSERT(dofval.size() == m_ndof); GOOSEFEM_ASSERT(xt::has_shape(elemvec, {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<double, 1>& dofval_u, const xt::xtensor<double, 1>& dofval_p, xt::xtensor<double, 3>& elemvec) const { GOOSEFEM_ASSERT(dofval_u.size() == m_nnu); GOOSEFEM_ASSERT(dofval_p.size() == m_nnp); GOOSEFEM_ASSERT(xt::has_shape(elemvec, {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<double, 2>& nodevec, xt::xtensor<double, 3>& elemvec) const { GOOSEFEM_ASSERT(xt::has_shape(nodevec, {m_nnode, m_ndim})); GOOSEFEM_ASSERT(xt::has_shape(elemvec, {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<double, 2>& nodevec, xt::xtensor<double, 1>& dofval) const { GOOSEFEM_ASSERT(xt::has_shape(nodevec, {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<double, 2>& nodevec, xt::xtensor<double, 1>& dofval_u) const { GOOSEFEM_ASSERT(xt::has_shape(nodevec, {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<double, 2>& nodevec, xt::xtensor<double, 1>& dofval_p) const { GOOSEFEM_ASSERT(xt::has_shape(nodevec, {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<double, 3>& elemvec, xt::xtensor<double, 1>& dofval) const { GOOSEFEM_ASSERT(xt::has_shape(elemvec, {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<double, 3>& elemvec, xt::xtensor<double, 1>& dofval_u) const { GOOSEFEM_ASSERT(xt::has_shape(elemvec, {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<double, 3>& elemvec, xt::xtensor<double, 1>& dofval_p) const { GOOSEFEM_ASSERT(xt::has_shape(elemvec, {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<double, 3>& elemvec, xt::xtensor<double, 2>& nodevec) const { GOOSEFEM_ASSERT(xt::has_shape(elemvec, {m_nelem, m_nne, m_ndim})); GOOSEFEM_ASSERT(xt::has_shape(nodevec, {m_nnode, m_ndim})); xt::xtensor<double, 1> dofval = this->AssembleDofs(elemvec); this->asNode(dofval, nodevec); } inline xt::xtensor<double, 1> VectorPartitioned::AsDofs( const xt::xtensor<double, 1>& dofval_u, const xt::xtensor<double, 1>& dofval_p) const { xt::xtensor<double, 1> dofval = xt::empty<double>({m_ndof}); this->asDofs(dofval_u, dofval_p, dofval); return dofval; } inline xt::xtensor<double, 1> VectorPartitioned::AsDofs(const xt::xtensor<double, 2>& nodevec) const { xt::xtensor<double, 1> dofval = xt::empty<double>({m_ndof}); this->asDofs(nodevec, dofval); return dofval; } inline xt::xtensor<double, 1> VectorPartitioned::AsDofs_u(const xt::xtensor<double, 1>& dofval) const { xt::xtensor<double, 1> dofval_u = xt::empty<double>({m_nnu}); this->asDofs_u(dofval, dofval_u); return dofval_u; } inline xt::xtensor<double, 1> VectorPartitioned::AsDofs_u(const xt::xtensor<double, 2>& nodevec) const { xt::xtensor<double, 1> dofval_u = xt::empty<double>({m_nnu}); this->asDofs_u(nodevec, dofval_u); return dofval_u; } inline xt::xtensor<double, 1> VectorPartitioned::AsDofs_p(const xt::xtensor<double, 1>& dofval) const { xt::xtensor<double, 1> dofval_p = xt::empty<double>({m_nnp}); this->asDofs_p(dofval, dofval_p); return dofval_p; } inline xt::xtensor<double, 1> VectorPartitioned::AsDofs_p(const xt::xtensor<double, 2>& nodevec) const { xt::xtensor<double, 1> dofval_p = xt::empty<double>({m_nnp}); this->asDofs_p(nodevec, dofval_p); return dofval_p; } inline xt::xtensor<double, 1> VectorPartitioned::AsDofs(const xt::xtensor<double, 3>& elemvec) const { xt::xtensor<double, 1> dofval = xt::empty<double>({m_ndof}); this->asDofs(elemvec, dofval); return dofval; } inline xt::xtensor<double, 1> VectorPartitioned::AsDofs_u(const xt::xtensor<double, 3>& elemvec) const { xt::xtensor<double, 1> dofval_u = xt::empty<double>({m_nnu}); this->asDofs_u(elemvec, dofval_u); return dofval_u; } inline xt::xtensor<double, 1> VectorPartitioned::AsDofs_p(const xt::xtensor<double, 3>& elemvec) const { xt::xtensor<double, 1> dofval_p = xt::empty<double>({m_nnp}); this->asDofs_p(elemvec, dofval_p); return dofval_p; } inline xt::xtensor<double, 2> VectorPartitioned::AsNode(const xt::xtensor<double, 1>& dofval) const { xt::xtensor<double, 2> nodevec = xt::empty<double>({m_nnode, m_ndim}); this->asNode(dofval, nodevec); return nodevec; } inline xt::xtensor<double, 2> VectorPartitioned::AsNode( const xt::xtensor<double, 1>& dofval_u, const xt::xtensor<double, 1>& dofval_p) const { xt::xtensor<double, 2> nodevec = xt::empty<double>({m_nnode, m_ndim}); this->asNode(dofval_u, dofval_p, nodevec); return nodevec; } inline xt::xtensor<double, 2> VectorPartitioned::AsNode(const xt::xtensor<double, 3>& elemvec) const { xt::xtensor<double, 2> nodevec = xt::empty<double>({m_nnode, m_ndim}); this->asNode(elemvec, nodevec); return nodevec; } inline xt::xtensor<double, 3> VectorPartitioned::AsElement(const xt::xtensor<double, 1>& dofval) const { xt::xtensor<double, 3> elemvec = xt::empty<double>({m_nelem, m_nne, m_ndim}); this->asElement(dofval, elemvec); return elemvec; } inline xt::xtensor<double, 3> VectorPartitioned::AsElement( const xt::xtensor<double, 1>& dofval_u, const xt::xtensor<double, 1>& dofval_p) const { xt::xtensor<double, 3> elemvec = xt::empty<double>({m_nelem, m_nne, m_ndim}); this->asElement(dofval_u, dofval_p, elemvec); return elemvec; } inline xt::xtensor<double, 3> VectorPartitioned::AsElement(const xt::xtensor<double, 2>& nodevec) const { xt::xtensor<double, 3> elemvec = xt::empty<double>({m_nelem, m_nne, m_ndim}); this->asElement(nodevec, elemvec); return elemvec; } inline xt::xtensor<double, 1> VectorPartitioned::AssembleDofs(const xt::xtensor<double, 2>& nodevec) const { xt::xtensor<double, 1> dofval = xt::empty<double>({m_ndof}); this->assembleDofs(nodevec, dofval); return dofval; } inline xt::xtensor<double, 1> VectorPartitioned::AssembleDofs_u(const xt::xtensor<double, 2>& nodevec) const { xt::xtensor<double, 1> dofval_u = xt::empty<double>({m_nnu}); this->assembleDofs_u(nodevec, dofval_u); return dofval_u; } inline xt::xtensor<double, 1> VectorPartitioned::AssembleDofs_p(const xt::xtensor<double, 2>& nodevec) const { xt::xtensor<double, 1> dofval_p = xt::empty<double>({m_nnp}); this->assembleDofs_p(nodevec, dofval_p); return dofval_p; } inline xt::xtensor<double, 1> VectorPartitioned::AssembleDofs(const xt::xtensor<double, 3>& elemvec) const { xt::xtensor<double, 1> dofval = xt::empty<double>({m_ndof}); this->assembleDofs(elemvec, dofval); return dofval; } inline xt::xtensor<double, 1> VectorPartitioned::AssembleDofs_u(const xt::xtensor<double, 3>& elemvec) const { xt::xtensor<double, 1> dofval_u = xt::empty<double>({m_nnu}); this->assembleDofs_u(elemvec, dofval_u); return dofval_u; } inline xt::xtensor<double, 1> VectorPartitioned::AssembleDofs_p(const xt::xtensor<double, 3>& elemvec) const { xt::xtensor<double, 1> dofval_p = xt::empty<double>({m_nnp}); this->assembleDofs_p(elemvec, dofval_p); return dofval_p; } inline xt::xtensor<double, 2> VectorPartitioned::AssembleNode(const xt::xtensor<double, 3>& elemvec) const { xt::xtensor<double, 2> nodevec = xt::empty<double>({m_nnode, m_ndim}); this->assembleNode(elemvec, nodevec); return nodevec; } inline xt::xtensor<double, 2> VectorPartitioned::Copy( const xt::xtensor<double, 2>& nodevec_src, const xt::xtensor<double, 2>& nodevec_dest) const { xt::xtensor<double, 2> ret = nodevec_dest; this->copy(nodevec_src, ret); return ret; } inline xt::xtensor<double, 2> VectorPartitioned::Copy_u( const xt::xtensor<double, 2>& nodevec_src, const xt::xtensor<double, 2>& nodevec_dest) const { xt::xtensor<double, 2> ret = nodevec_dest; this->copy_u(nodevec_src, ret); return ret; } inline xt::xtensor<double, 2> VectorPartitioned::Copy_p( const xt::xtensor<double, 2>& nodevec_src, const xt::xtensor<double, 2>& nodevec_dest) const { xt::xtensor<double, 2> ret = nodevec_dest; this->copy_p(nodevec_src, ret); return ret; } inline xt::xtensor<double, 1> VectorPartitioned::AllocateDofval() const { xt::xtensor<double, 1> dofval = xt::empty<double>({m_ndof}); return dofval; } inline xt::xtensor<double, 2> VectorPartitioned::AllocateNodevec() const { xt::xtensor<double, 2> nodevec = xt::empty<double>({m_nnode, m_ndim}); return nodevec; } inline xt::xtensor<double, 3> VectorPartitioned::AllocateElemvec() const { xt::xtensor<double, 3> elemvec = xt::empty<double>({m_nelem, m_nne, m_ndim}); return elemvec; } inline xt::xtensor<double, 3> VectorPartitioned::AllocateElemmat() const { xt::xtensor<double, 3> elemmat = xt::empty<double>({m_nelem, m_nne * m_ndim, m_nne * m_ndim}); return elemmat; } inline xt::xtensor<double, 1> VectorPartitioned::AllocateDofval(double val) const { xt::xtensor<double, 1> dofval = xt::zeros<double>({m_ndof}); dofval.fill(val); return dofval; } inline xt::xtensor<double, 2> VectorPartitioned::AllocateNodevec(double val) const { xt::xtensor<double, 2> nodevec = xt::zeros<double>({m_nnode, m_ndim}); nodevec.fill(val); return nodevec; } inline xt::xtensor<double, 3> VectorPartitioned::AllocateElemvec(double val) const { xt::xtensor<double, 3> elemvec = xt::zeros<double>({m_nelem, m_nne, m_ndim}); elemvec.fill(val); return elemvec; } inline xt::xtensor<double, 3> VectorPartitioned::AllocateElemmat(double val) const { xt::xtensor<double, 3> elemmat = xt::empty<double>({m_nelem, m_nne * m_ndim, m_nne * m_ndim}); elemmat.fill(val); return elemmat; } } // namespace GooseFEM #endif diff --git a/python/MeshQuad4.hpp b/python/MeshQuad4.hpp index 65d8c10..b7f38f6 100644 --- a/python/MeshQuad4.hpp +++ b/python/MeshQuad4.hpp @@ -1,229 +1,234 @@ /* ================================================================================================= (c - GPLv3) T.W.J. de Geus (Tom) | tom@geus.me | www.geus.me | github.com/tdegeus/GooseFEM ================================================================================================= */ #include <GooseFEM/GooseFEM.h> #include <pybind11/pybind11.h> #include <pybind11/stl.h> #include <pyxtensor/pyxtensor.hpp> namespace py = pybind11; void init_MeshQuad4(py::module& m) { py::class_<GooseFEM::Mesh::Quad4::Regular>(m, "Regular") .def( py::init<size_t, size_t, double>(), "Regular mesh: 'nx' pixels in horizontal direction, 'ny' in vertical direction, edge " "size 'h'", py::arg("nx"), py::arg("ny"), py::arg("h") = 1.) .def("coor", &GooseFEM::Mesh::Quad4::Regular::coor) .def("conn", &GooseFEM::Mesh::Quad4::Regular::conn) .def("nelem", &GooseFEM::Mesh::Quad4::Regular::nelem) .def("nnode", &GooseFEM::Mesh::Quad4::Regular::nnode) .def("nne", &GooseFEM::Mesh::Quad4::Regular::nne) .def("ndim", &GooseFEM::Mesh::Quad4::Regular::ndim) .def("nelx", &GooseFEM::Mesh::Quad4::Regular::nelx) .def("nely", &GooseFEM::Mesh::Quad4::Regular::nely) .def("h", &GooseFEM::Mesh::Quad4::Regular::h) .def("getElementType", &GooseFEM::Mesh::Quad4::Regular::getElementType) .def("nodesBottomEdge", &GooseFEM::Mesh::Quad4::Regular::nodesBottomEdge) .def("nodesTopEdge", &GooseFEM::Mesh::Quad4::Regular::nodesTopEdge) .def("nodesLeftEdge", &GooseFEM::Mesh::Quad4::Regular::nodesLeftEdge) .def("nodesRightEdge", &GooseFEM::Mesh::Quad4::Regular::nodesRightEdge) .def("nodesBottomOpenEdge", &GooseFEM::Mesh::Quad4::Regular::nodesBottomOpenEdge) .def("nodesTopOpenEdge", &GooseFEM::Mesh::Quad4::Regular::nodesTopOpenEdge) .def("nodesLeftOpenEdge", &GooseFEM::Mesh::Quad4::Regular::nodesLeftOpenEdge) .def("nodesRightOpenEdge", &GooseFEM::Mesh::Quad4::Regular::nodesRightOpenEdge) .def("nodesBottomLeftCorner", &GooseFEM::Mesh::Quad4::Regular::nodesBottomLeftCorner) .def("nodesBottomRightCorner", &GooseFEM::Mesh::Quad4::Regular::nodesBottomRightCorner) .def("nodesTopLeftCorner", &GooseFEM::Mesh::Quad4::Regular::nodesTopLeftCorner) .def("nodesTopRightCorner", &GooseFEM::Mesh::Quad4::Regular::nodesTopRightCorner) .def("nodesLeftBottomCorner", &GooseFEM::Mesh::Quad4::Regular::nodesLeftBottomCorner) .def("nodesLeftTopCorner", &GooseFEM::Mesh::Quad4::Regular::nodesLeftTopCorner) .def("nodesRightBottomCorner", &GooseFEM::Mesh::Quad4::Regular::nodesRightBottomCorner) .def("nodesRightTopCorner", &GooseFEM::Mesh::Quad4::Regular::nodesRightTopCorner) .def("dofs", &GooseFEM::Mesh::Quad4::Regular::dofs) .def("nodesPeriodic", &GooseFEM::Mesh::Quad4::Regular::nodesPeriodic) .def("nodesOrigin", &GooseFEM::Mesh::Quad4::Regular::nodesOrigin) .def("dofsPeriodic", &GooseFEM::Mesh::Quad4::Regular::dofsPeriodic) .def("elementgrid", &GooseFEM::Mesh::Quad4::Regular::elementgrid) .def("__repr__", [](const GooseFEM::Mesh::Quad4::Regular&) { return "<GooseFEM.Mesh.Quad4.Regular>"; }); py::class_<GooseFEM::Mesh::Quad4::FineLayer>(m, "FineLayer") .def( py::init<size_t, size_t, double, size_t>(), "FineLayer mesh: 'nx' pixels in horizontal direction (length 'Lx'), idem in vertical " "direction", py::arg("nx"), py::arg("ny"), py::arg("h") = 1., py::arg("nfine") = 1) .def( py::init<const xt::xtensor<double, 2>&, const xt::xtensor<size_t, 2>&>(), "Map connectivity to generating FineLayer-object.", py::arg("coor"), py::arg("conn")) .def("coor", &GooseFEM::Mesh::Quad4::FineLayer::coor) .def("conn", &GooseFEM::Mesh::Quad4::FineLayer::conn) .def("nelem", &GooseFEM::Mesh::Quad4::FineLayer::nelem) .def("nnode", &GooseFEM::Mesh::Quad4::FineLayer::nnode) .def("nne", &GooseFEM::Mesh::Quad4::FineLayer::nne) .def("ndim", &GooseFEM::Mesh::Quad4::FineLayer::ndim) .def("nelx", &GooseFEM::Mesh::Quad4::FineLayer::nelx) .def("nely", &GooseFEM::Mesh::Quad4::FineLayer::nely) .def("h", &GooseFEM::Mesh::Quad4::FineLayer::h) .def("elemrow_nhx", &GooseFEM::Mesh::Quad4::FineLayer::elemrow_nhx) .def("elemrow_nhy", &GooseFEM::Mesh::Quad4::FineLayer::elemrow_nhy) .def("elemrow_nelem", &GooseFEM::Mesh::Quad4::FineLayer::elemrow_nelem) .def("getElementType", &GooseFEM::Mesh::Quad4::FineLayer::getElementType) .def("elementsMiddleLayer", &GooseFEM::Mesh::Quad4::FineLayer::elementsMiddleLayer) .def("elementsLayer", &GooseFEM::Mesh::Quad4::FineLayer::elementsLayer) .def( "elementgrid_ravel", &GooseFEM::Mesh::Quad4::FineLayer::elementgrid_ravel, py::arg("rows_range"), py::arg("cols_range")) .def( "elementgrid_around_ravel", &GooseFEM::Mesh::Quad4::FineLayer::elementgrid_around_ravel, py::arg("element"), py::arg("size"), py::arg("periodic") = true) .def( "elementgrid_leftright", &GooseFEM::Mesh::Quad4::FineLayer::elementgrid_leftright, py::arg("element"), py::arg("left"), py::arg("right"), py::arg("periodic") = true) .def("nodesBottomEdge", &GooseFEM::Mesh::Quad4::FineLayer::nodesBottomEdge) .def("nodesTopEdge", &GooseFEM::Mesh::Quad4::FineLayer::nodesTopEdge) .def("nodesLeftEdge", &GooseFEM::Mesh::Quad4::FineLayer::nodesLeftEdge) .def("nodesRightEdge", &GooseFEM::Mesh::Quad4::FineLayer::nodesRightEdge) .def("nodesBottomOpenEdge", &GooseFEM::Mesh::Quad4::FineLayer::nodesBottomOpenEdge) .def("nodesTopOpenEdge", &GooseFEM::Mesh::Quad4::FineLayer::nodesTopOpenEdge) .def("nodesLeftOpenEdge", &GooseFEM::Mesh::Quad4::FineLayer::nodesLeftOpenEdge) .def("nodesRightOpenEdge", &GooseFEM::Mesh::Quad4::FineLayer::nodesRightOpenEdge) .def("nodesBottomLeftCorner", &GooseFEM::Mesh::Quad4::FineLayer::nodesBottomLeftCorner) .def("nodesBottomRightCorner", &GooseFEM::Mesh::Quad4::FineLayer::nodesBottomRightCorner) .def("nodesTopLeftCorner", &GooseFEM::Mesh::Quad4::FineLayer::nodesTopLeftCorner) .def("nodesTopRightCorner", &GooseFEM::Mesh::Quad4::FineLayer::nodesTopRightCorner) .def("nodesLeftBottomCorner", &GooseFEM::Mesh::Quad4::FineLayer::nodesLeftBottomCorner) .def("nodesLeftTopCorner", &GooseFEM::Mesh::Quad4::FineLayer::nodesLeftTopCorner) .def("nodesRightBottomCorner", &GooseFEM::Mesh::Quad4::FineLayer::nodesRightBottomCorner) .def("nodesRightTopCorner", &GooseFEM::Mesh::Quad4::FineLayer::nodesRightTopCorner) .def("dofs", &GooseFEM::Mesh::Quad4::FineLayer::dofs) .def("nodesPeriodic", &GooseFEM::Mesh::Quad4::FineLayer::nodesPeriodic) .def("nodesOrigin", &GooseFEM::Mesh::Quad4::FineLayer::nodesOrigin) .def("dofsPeriodic", &GooseFEM::Mesh::Quad4::FineLayer::dofsPeriodic) .def("roll", &GooseFEM::Mesh::Quad4::FineLayer::roll) .def("__repr__", [](const GooseFEM::Mesh::Quad4::FineLayer&) { return "<GooseFEM.Mesh.Quad4.FineLayer>"; }); } void init_MeshQuad4Map(py::module& m) { py::class_<GooseFEM::Mesh::Quad4::Map::RefineRegular>(m, "RefineRegular") .def( py::init<const GooseFEM::Mesh::Quad4::Regular&, size_t, size_t>(), "Refine a regular mesh", py::arg("mesh"), py::arg("nx"), py::arg("ny")) .def("getCoarseMesh", &GooseFEM::Mesh::Quad4::Map::RefineRegular::getCoarseMesh) .def("getFineMesh", &GooseFEM::Mesh::Quad4::Map::RefineRegular::getFineMesh) .def("getMap", &GooseFEM::Mesh::Quad4::Map::RefineRegular::getMap) .def( "mapToCoarse", py::overload_cast<const xt::xtensor<double, 1>&>( &GooseFEM::Mesh::Quad4::Map::RefineRegular::mapToCoarse, py::const_)) .def( "mapToCoarse", py::overload_cast<const xt::xtensor<double, 2>&>( &GooseFEM::Mesh::Quad4::Map::RefineRegular::mapToCoarse, py::const_)) .def( "mapToCoarse", py::overload_cast<const xt::xtensor<double, 4>&>( &GooseFEM::Mesh::Quad4::Map::RefineRegular::mapToCoarse, py::const_)) .def( "mapToFine", py::overload_cast<const xt::xtensor<double, 1>&>( &GooseFEM::Mesh::Quad4::Map::RefineRegular::mapToFine, py::const_)) .def( "mapToFine", py::overload_cast<const xt::xtensor<double, 2>&>( &GooseFEM::Mesh::Quad4::Map::RefineRegular::mapToFine, py::const_)) .def( "mapToFine", py::overload_cast<const xt::xtensor<double, 4>&>( &GooseFEM::Mesh::Quad4::Map::RefineRegular::mapToFine, py::const_)) .def("__repr__", [](const GooseFEM::Mesh::Quad4::Map::RefineRegular&) { return "<GooseFEM.Mesh.Quad4.Map.RefineRegular>"; }); py::class_<GooseFEM::Mesh::Quad4::Map::FineLayer2Regular>(m, "FineLayer2Regular") .def( py::init<const GooseFEM::Mesh::Quad4::FineLayer&>(), "Map a FineLayer mesh to a Regular mesh", py::arg("mesh")) .def("getRegularMesh", &GooseFEM::Mesh::Quad4::Map::FineLayer2Regular::getRegularMesh) .def("getFineLayerMesh", &GooseFEM::Mesh::Quad4::Map::FineLayer2Regular::getFineLayerMesh) .def("getMap", &GooseFEM::Mesh::Quad4::Map::FineLayer2Regular::getMap) .def("getMapFraction", &GooseFEM::Mesh::Quad4::Map::FineLayer2Regular::getMapFraction) .def( "mapToRegular", py::overload_cast<const xt::xtensor<double, 1>&>( - &GooseFEM::Mesh::Quad4::Map::FineLayer2Regular::mapToRegular, py::const_)) + &GooseFEM::Mesh::Quad4::Map::FineLayer2Regular::mapToRegular<double, 1>, py::const_)) .def( "mapToRegular", py::overload_cast<const xt::xtensor<double, 2>&>( - &GooseFEM::Mesh::Quad4::Map::FineLayer2Regular::mapToRegular, py::const_)) + &GooseFEM::Mesh::Quad4::Map::FineLayer2Regular::mapToRegular<double, 2>, py::const_)) + + .def( + "mapToRegular", + py::overload_cast<const xt::xtensor<double, 3>&>( + &GooseFEM::Mesh::Quad4::Map::FineLayer2Regular::mapToRegular<double, 3>, py::const_)) .def( "mapToRegular", py::overload_cast<const xt::xtensor<double, 4>&>( - &GooseFEM::Mesh::Quad4::Map::FineLayer2Regular::mapToRegular, py::const_)) + &GooseFEM::Mesh::Quad4::Map::FineLayer2Regular::mapToRegular<double, 4>, py::const_)) .def("__repr__", [](const GooseFEM::Mesh::Quad4::Map::FineLayer2Regular&) { return "<GooseFEM.Mesh.Quad4.Map.FineLayer2Regular>"; }); } diff --git a/test/basic/MeshQuad4.cpp b/test/basic/MeshQuad4.cpp index ebe1f28..aabe773 100644 --- a/test/basic/MeshQuad4.cpp +++ b/test/basic/MeshQuad4.cpp @@ -1,674 +1,676 @@ #include <catch2/catch.hpp> #include <xtensor/xrandom.hpp> #include <xtensor/xmath.hpp> #include <GooseFEM/GooseFEM.h> TEST_CASE("GooseFEM::MeshQuad4", "MeshQuad4.h") { SECTION("Regular") { xt::xtensor<double, 2> coor_ = {{0., 0.}, {1., 0.}, {2., 0.}, {3., 0.}, {4., 0.}, {5., 0.}, {0., 1.}, {1., 1.}, {2., 1.}, {3., 1.}, {4., 1.}, {5., 1.}, {0., 2.}, {1., 2.}, {2., 2.}, {3., 2.}, {4., 2.}, {5., 2.}, {0., 3.}, {1., 3.}, {2., 3.}, {3., 3.}, {4., 3.}, {5., 3.}}; xt::xtensor<double, 2> conn_ = {{0, 1, 7, 6}, {1, 2, 8, 7}, {2, 3, 9, 8}, {3, 4, 10, 9}, {4, 5, 11, 10}, {6, 7, 13, 12}, {7, 8, 14, 13}, {8, 9, 15, 14}, {9, 10, 16, 15}, {10, 11, 17, 16}, {12, 13, 19, 18}, {13, 14, 20, 19}, {14, 15, 21, 20}, {15, 16, 22, 21}, {16, 17, 23, 22}}; size_t nelem_ = 15; size_t nnode_ = 24; size_t nne_ = 4; size_t ndim_ = 2; size_t nnodePeriodic_ = 15; xt::xtensor<size_t, 1> nodesBottomEdge_ = {0, 1, 2, 3, 4, 5}; xt::xtensor<size_t, 1> nodesTopEdge_ = {18, 19, 20, 21, 22, 23}; xt::xtensor<size_t, 1> nodesLeftEdge_ = {0, 6, 12, 18}; xt::xtensor<size_t, 1> nodesRightEdge_ = {5, 11, 17, 23}; xt::xtensor<size_t, 1> nodesBottomOpenEdge_ = {1, 2, 3, 4}; xt::xtensor<size_t, 1> nodesTopOpenEdge_ = {19, 20, 21, 22}; xt::xtensor<size_t, 1> nodesLeftOpenEdge_ = {6, 12}; xt::xtensor<size_t, 1> nodesRightOpenEdge_ = {11, 17}; size_t nodesBottomLeftCorner_ = 0; size_t nodesBottomRightCorner_ = 5; size_t nodesTopLeftCorner_ = 18; size_t nodesTopRightCorner_ = 23; size_t nodesLeftBottomCorner_ = 0; size_t nodesLeftTopCorner_ = 18; size_t nodesRightBottomCorner_ = 5; size_t nodesRightTopCorner_ = 23; xt::xtensor<size_t, 2> dofs_ = {{0, 1}, {2, 3}, {4, 5}, {6, 7}, {8, 9}, {10, 11}, {12, 13}, {14, 15}, {16, 17}, {18, 19}, {20, 21}, {22, 23}, {24, 25}, {26, 27}, {28, 29}, {30, 31}, {32, 33}, {34, 35}, {36, 37}, {38, 39}, {40, 41}, {42, 43}, {44, 45}, {46, 47}}; xt::xtensor<size_t, 2> nodesPeriodic_ = { {0, 5}, {0, 23}, {0, 18}, {1, 19}, {2, 20}, {3, 21}, {4, 22}, {6, 11}, {12, 17}}; size_t nodesOrigin_ = 0; xt::xtensor<size_t, 2> dofsPeriodic_ = { {0, 1}, {2, 3}, {4, 5}, {6, 7}, {8, 9}, {0, 1}, {10, 11}, {12, 13}, {14, 15}, {16, 17}, {18, 19}, {10, 11}, {20, 21}, {22, 23}, {24, 25}, {26, 27}, {28, 29}, {20, 21}, {0, 1}, {2, 3}, {4, 5}, {6, 7}, {8, 9}, {0, 1}}; GooseFEM::Mesh::Quad4::Regular mesh(5, 3); xt::xtensor<double, 2> coor = mesh.coor(); xt::xtensor<size_t, 2> conn = mesh.conn(); size_t nelem = mesh.nelem(); size_t nnode = mesh.nnode(); size_t nne = mesh.nne(); size_t ndim = mesh.ndim(); size_t nnodePeriodic = mesh.nnode() - mesh.nodesPeriodic().shape(0); xt::xtensor<size_t, 1> nodesBottomEdge = mesh.nodesBottomEdge(); xt::xtensor<size_t, 1> nodesTopEdge = mesh.nodesTopEdge(); xt::xtensor<size_t, 1> nodesLeftEdge = mesh.nodesLeftEdge(); xt::xtensor<size_t, 1> nodesRightEdge = mesh.nodesRightEdge(); xt::xtensor<size_t, 1> nodesBottomOpenEdge = mesh.nodesBottomOpenEdge(); xt::xtensor<size_t, 1> nodesTopOpenEdge = mesh.nodesTopOpenEdge(); xt::xtensor<size_t, 1> nodesLeftOpenEdge = mesh.nodesLeftOpenEdge(); xt::xtensor<size_t, 1> nodesRightOpenEdge = mesh.nodesRightOpenEdge(); size_t nodesBottomLeftCorner = mesh.nodesBottomLeftCorner(); size_t nodesBottomRightCorner = mesh.nodesBottomRightCorner(); size_t nodesTopLeftCorner = mesh.nodesTopLeftCorner(); size_t nodesTopRightCorner = mesh.nodesTopRightCorner(); size_t nodesLeftBottomCorner = mesh.nodesLeftBottomCorner(); size_t nodesLeftTopCorner = mesh.nodesLeftTopCorner(); size_t nodesRightBottomCorner = mesh.nodesRightBottomCorner(); size_t nodesRightTopCorner = mesh.nodesRightTopCorner(); xt::xtensor<size_t, 2> dofs = mesh.dofs(); xt::xtensor<size_t, 2> nodesPeriodic = mesh.nodesPeriodic(); size_t nodesOrigin = mesh.nodesOrigin(); xt::xtensor<size_t, 2> dofsPeriodic = mesh.dofsPeriodic(); REQUIRE(nelem == nelem_); REQUIRE(nnode == nnode_); REQUIRE(nne == nne_); REQUIRE(ndim == ndim_); REQUIRE(nnodePeriodic == nnodePeriodic_); REQUIRE(nodesBottomLeftCorner == nodesBottomLeftCorner_); REQUIRE(nodesBottomRightCorner == nodesBottomRightCorner_); REQUIRE(nodesTopLeftCorner == nodesTopLeftCorner_); REQUIRE(nodesTopRightCorner == nodesTopRightCorner_); REQUIRE(nodesLeftBottomCorner == nodesLeftBottomCorner_); REQUIRE(nodesLeftTopCorner == nodesLeftTopCorner_); REQUIRE(nodesRightBottomCorner == nodesRightBottomCorner_); REQUIRE(nodesRightTopCorner == nodesRightTopCorner_); REQUIRE(nodesOrigin == nodesOrigin_); REQUIRE(xt::allclose(coor, coor_)); REQUIRE(xt::all(xt::equal(conn, conn_))); REQUIRE(xt::all(xt::equal(nodesBottomEdge, nodesBottomEdge_))); REQUIRE(xt::all(xt::equal(nodesTopEdge, nodesTopEdge_))); REQUIRE(xt::all(xt::equal(nodesLeftEdge, nodesLeftEdge_))); REQUIRE(xt::all(xt::equal(nodesRightEdge, nodesRightEdge_))); REQUIRE(xt::all(xt::equal(nodesBottomOpenEdge, nodesBottomOpenEdge_))); REQUIRE(xt::all(xt::equal(nodesTopOpenEdge, nodesTopOpenEdge_))); REQUIRE(xt::all(xt::equal(nodesLeftOpenEdge, nodesLeftOpenEdge_))); REQUIRE(xt::all(xt::equal(nodesRightOpenEdge, nodesRightOpenEdge_))); REQUIRE(xt::all(xt::equal(nodesPeriodic, nodesPeriodic_))); REQUIRE(xt::all(xt::equal(dofsPeriodic, dofsPeriodic_))); } SECTION("FineLayer") { xt::xtensor<double, 2> coor_ = { {0., 0.}, {3., 0.}, {6., 0.}, {9., 0.}, {0., 3.}, {3., 3.}, {6., 3.}, {9., 3.}, {0., 6.}, {3., 6.}, {6., 6.}, {9., 6.}, {1., 7.}, {2., 7.}, {4., 7.}, {5., 7.}, {7., 7.}, {8., 7.}, {0., 8.}, {1., 8.}, {2., 8.}, {3., 8.}, {4., 8.}, {5., 8.}, {6., 8.}, {7., 8.}, {8., 8.}, {9., 8.}, {0., 9.}, {1., 9.}, {2., 9.}, {3., 9.}, {4., 9.}, {5., 9.}, {6., 9.}, {7., 9.}, {8., 9.}, {9., 9.}, {0., 10.}, {1., 10.}, {2., 10.}, {3., 10.}, {4., 10.}, {5., 10.}, {6., 10.}, {7., 10.}, {8., 10.}, {9., 10.}, {0., 11.}, {1., 11.}, {2., 11.}, {3., 11.}, {4., 11.}, {5., 11.}, {6., 11.}, {7., 11.}, {8., 11.}, {9., 11.}, {0., 12.}, {1., 12.}, {2., 12.}, {3., 12.}, {4., 12.}, {5., 12.}, {6., 12.}, {7., 12.}, {8., 12.}, {9., 12.}, {0., 13.}, {1., 13.}, {2., 13.}, {3., 13.}, {4., 13.}, {5., 13.}, {6., 13.}, {7., 13.}, {8., 13.}, {9., 13.}, {1., 14.}, {2., 14.}, {4., 14.}, {5., 14.}, {7., 14.}, {8., 14.}, {0., 15.}, {3., 15.}, {6., 15.}, {9., 15.}, {0., 18.}, {3., 18.}, {6., 18.}, {9., 18.}, {0., 21.}, {3., 21.}, {6., 21.}, {9., 21.}}; xt::xtensor<double, 2> conn_ = { {0, 1, 5, 4}, {1, 2, 6, 5}, {2, 3, 7, 6}, {4, 5, 9, 8}, {5, 6, 10, 9}, {6, 7, 11, 10}, {8, 9, 13, 12}, {9, 21, 20, 13}, {12, 13, 20, 19}, {8, 12, 19, 18}, {9, 10, 15, 14}, {10, 24, 23, 15}, {14, 15, 23, 22}, {9, 14, 22, 21}, {10, 11, 17, 16}, {11, 27, 26, 17}, {16, 17, 26, 25}, {10, 16, 25, 24}, {18, 19, 29, 28}, {19, 20, 30, 29}, {20, 21, 31, 30}, {21, 22, 32, 31}, {22, 23, 33, 32}, {23, 24, 34, 33}, {24, 25, 35, 34}, {25, 26, 36, 35}, {26, 27, 37, 36}, {28, 29, 39, 38}, {29, 30, 40, 39}, {30, 31, 41, 40}, {31, 32, 42, 41}, {32, 33, 43, 42}, {33, 34, 44, 43}, {34, 35, 45, 44}, {35, 36, 46, 45}, {36, 37, 47, 46}, {38, 39, 49, 48}, {39, 40, 50, 49}, {40, 41, 51, 50}, {41, 42, 52, 51}, {42, 43, 53, 52}, {43, 44, 54, 53}, {44, 45, 55, 54}, {45, 46, 56, 55}, {46, 47, 57, 56}, {48, 49, 59, 58}, {49, 50, 60, 59}, {50, 51, 61, 60}, {51, 52, 62, 61}, {52, 53, 63, 62}, {53, 54, 64, 63}, {54, 55, 65, 64}, {55, 56, 66, 65}, {56, 57, 67, 66}, {58, 59, 69, 68}, {59, 60, 70, 69}, {60, 61, 71, 70}, {61, 62, 72, 71}, {62, 63, 73, 72}, {63, 64, 74, 73}, {64, 65, 75, 74}, {65, 66, 76, 75}, {66, 67, 77, 76}, {68, 69, 78, 84}, {69, 70, 79, 78}, {70, 71, 85, 79}, {78, 79, 85, 84}, {71, 72, 80, 85}, {72, 73, 81, 80}, {73, 74, 86, 81}, {80, 81, 86, 85}, {74, 75, 82, 86}, {75, 76, 83, 82}, {76, 77, 87, 83}, {82, 83, 87, 86}, {84, 85, 89, 88}, {85, 86, 90, 89}, {86, 87, 91, 90}, {88, 89, 93, 92}, {89, 90, 94, 93}, {90, 91, 95, 94}}; size_t nelem_ = 81; size_t nnode_ = 96; size_t nne_ = 4; size_t ndim_ = 2; size_t shape_x_ = 9; size_t shape_y_ = 21; xt::xtensor<size_t, 1> elementsMiddleLayer_ = {36, 37, 38, 39, 40, 41, 42, 43, 44}; xt::xtensor<size_t, 1> nodesBottomEdge_ = {0, 1, 2, 3}; xt::xtensor<size_t, 1> nodesTopEdge_ = {92, 93, 94, 95}; xt::xtensor<size_t, 1> nodesLeftEdge_ = {0, 4, 8, 18, 28, 38, 48, 58, 68, 84, 88, 92}; xt::xtensor<size_t, 1> nodesRightEdge_ = {3, 7, 11, 27, 37, 47, 57, 67, 77, 87, 91, 95}; xt::xtensor<size_t, 1> nodesBottomOpenEdge_ = {1, 2}; xt::xtensor<size_t, 1> nodesTopOpenEdge_ = {93, 94}; xt::xtensor<size_t, 1> nodesLeftOpenEdge_ = {4, 8, 18, 28, 38, 48, 58, 68, 84, 88}; xt::xtensor<size_t, 1> nodesRightOpenEdge_ = {7, 11, 27, 37, 47, 57, 67, 77, 87, 91}; size_t nodesBottomLeftCorner_ = 0; size_t nodesBottomRightCorner_ = 3; size_t nodesTopLeftCorner_ = 92; size_t nodesTopRightCorner_ = 95; size_t nodesLeftBottomCorner_ = 0; size_t nodesLeftTopCorner_ = 92; size_t nodesRightBottomCorner_ = 3; size_t nodesRightTopCorner_ = 95; xt::xtensor<size_t, 2> dofs_ = { {0, 1}, {2, 3}, {4, 5}, {6, 7}, {8, 9}, {10, 11}, {12, 13}, {14, 15}, {16, 17}, {18, 19}, {20, 21}, {22, 23}, {24, 25}, {26, 27}, {28, 29}, {30, 31}, {32, 33}, {34, 35}, {36, 37}, {38, 39}, {40, 41}, {42, 43}, {44, 45}, {46, 47}, {48, 49}, {50, 51}, {52, 53}, {54, 55}, {56, 57}, {58, 59}, {60, 61}, {62, 63}, {64, 65}, {66, 67}, {68, 69}, {70, 71}, {72, 73}, {74, 75}, {76, 77}, {78, 79}, {80, 81}, {82, 83}, {84, 85}, {86, 87}, {88, 89}, {90, 91}, {92, 93}, {94, 95}, {96, 97}, {98, 99}, {100, 101}, {102, 103}, {104, 105}, {106, 107}, {108, 109}, {110, 111}, {112, 113}, {114, 115}, {116, 117}, {118, 119}, {120, 121}, {122, 123}, {124, 125}, {126, 127}, {128, 129}, {130, 131}, {132, 133}, {134, 135}, {136, 137}, {138, 139}, {140, 141}, {142, 143}, {144, 145}, {146, 147}, {148, 149}, {150, 151}, {152, 153}, {154, 155}, {156, 157}, {158, 159}, {160, 161}, {162, 163}, {164, 165}, {166, 167}, {168, 169}, {170, 171}, {172, 173}, {174, 175}, {176, 177}, {178, 179}, {180, 181}, {182, 183}, {184, 185}, {186, 187}, {188, 189}, {190, 191}}; xt::xtensor<size_t, 2> nodesPeriodic_ = {{0, 3}, {0, 95}, {0, 92}, {1, 93}, {2, 94}, {4, 7}, {8, 11}, {18, 27}, {28, 37}, {38, 47}, {48, 57}, {58, 67}, {68, 77}, {84, 87}, {88, 91}}; size_t nodesOrigin_ = 0; xt::xtensor<size_t, 2> dofsPeriodic_ = { {0, 1}, {2, 3}, {4, 5}, {0, 1}, {6, 7}, {8, 9}, {10, 11}, {6, 7}, {12, 13}, {14, 15}, {16, 17}, {12, 13}, {18, 19}, {20, 21}, {22, 23}, {24, 25}, {26, 27}, {28, 29}, {30, 31}, {32, 33}, {34, 35}, {36, 37}, {38, 39}, {40, 41}, {42, 43}, {44, 45}, {46, 47}, {30, 31}, {48, 49}, {50, 51}, {52, 53}, {54, 55}, {56, 57}, {58, 59}, {60, 61}, {62, 63}, {64, 65}, {48, 49}, {66, 67}, {68, 69}, {70, 71}, {72, 73}, {74, 75}, {76, 77}, {78, 79}, {80, 81}, {82, 83}, {66, 67}, {84, 85}, {86, 87}, {88, 89}, {90, 91}, {92, 93}, {94, 95}, {96, 97}, {98, 99}, {100, 101}, {84, 85}, {102, 103}, {104, 105}, {106, 107}, {108, 109}, {110, 111}, {112, 113}, {114, 115}, {116, 117}, {118, 119}, {102, 103}, {120, 121}, {122, 123}, {124, 125}, {126, 127}, {128, 129}, {130, 131}, {132, 133}, {134, 135}, {136, 137}, {120, 121}, {138, 139}, {140, 141}, {142, 143}, {144, 145}, {146, 147}, {148, 149}, {150, 151}, {152, 153}, {154, 155}, {150, 151}, {156, 157}, {158, 159}, {160, 161}, {156, 157}, {0, 1}, {2, 3}, {4, 5}, {0, 1}}; GooseFEM::Mesh::Quad4::FineLayer mesh(9, 18); xt::xtensor<double, 2> coor = mesh.coor(); xt::xtensor<size_t, 2> conn = mesh.conn(); size_t nelem = mesh.nelem(); size_t nnode = mesh.nnode(); size_t nne = mesh.nne(); size_t ndim = mesh.ndim(); size_t shape_x = mesh.nelx(); size_t shape_y = mesh.nely(); xt::xtensor<size_t, 1> elementsMiddleLayer = mesh.elementsMiddleLayer(); xt::xtensor<size_t, 1> nodesBottomEdge = mesh.nodesBottomEdge(); xt::xtensor<size_t, 1> nodesTopEdge = mesh.nodesTopEdge(); xt::xtensor<size_t, 1> nodesLeftEdge = mesh.nodesLeftEdge(); xt::xtensor<size_t, 1> nodesRightEdge = mesh.nodesRightEdge(); xt::xtensor<size_t, 1> nodesBottomOpenEdge = mesh.nodesBottomOpenEdge(); xt::xtensor<size_t, 1> nodesTopOpenEdge = mesh.nodesTopOpenEdge(); xt::xtensor<size_t, 1> nodesLeftOpenEdge = mesh.nodesLeftOpenEdge(); xt::xtensor<size_t, 1> nodesRightOpenEdge = mesh.nodesRightOpenEdge(); size_t nodesBottomLeftCorner = mesh.nodesBottomLeftCorner(); size_t nodesBottomRightCorner = mesh.nodesBottomRightCorner(); size_t nodesTopLeftCorner = mesh.nodesTopLeftCorner(); size_t nodesTopRightCorner = mesh.nodesTopRightCorner(); size_t nodesLeftBottomCorner = mesh.nodesLeftBottomCorner(); size_t nodesLeftTopCorner = mesh.nodesLeftTopCorner(); size_t nodesRightBottomCorner = mesh.nodesRightBottomCorner(); size_t nodesRightTopCorner = mesh.nodesRightTopCorner(); xt::xtensor<size_t, 2> dofs = mesh.dofs(); xt::xtensor<size_t, 2> nodesPeriodic = mesh.nodesPeriodic(); size_t nodesOrigin = mesh.nodesOrigin(); xt::xtensor<size_t, 2> dofsPeriodic = mesh.dofsPeriodic(); REQUIRE(nelem == nelem_); REQUIRE(nnode == nnode_); REQUIRE(nne == nne_); REQUIRE(ndim == ndim_); REQUIRE(shape_x == shape_x_); REQUIRE(shape_y == shape_y_); REQUIRE(nodesBottomLeftCorner == nodesBottomLeftCorner_); REQUIRE(nodesBottomRightCorner == nodesBottomRightCorner_); REQUIRE(nodesTopLeftCorner == nodesTopLeftCorner_); REQUIRE(nodesTopRightCorner == nodesTopRightCorner_); REQUIRE(nodesLeftBottomCorner == nodesLeftBottomCorner_); REQUIRE(nodesLeftTopCorner == nodesLeftTopCorner_); REQUIRE(nodesRightBottomCorner == nodesRightBottomCorner_); REQUIRE(nodesRightTopCorner == nodesRightTopCorner_); REQUIRE(nodesOrigin == nodesOrigin_); REQUIRE(xt::allclose(coor, coor_)); REQUIRE(xt::all(xt::equal(elementsMiddleLayer, elementsMiddleLayer_))); REQUIRE(xt::all(xt::equal(conn, conn_))); REQUIRE(xt::all(xt::equal(nodesBottomEdge, nodesBottomEdge_))); REQUIRE(xt::all(xt::equal(nodesTopEdge, nodesTopEdge_))); REQUIRE(xt::all(xt::equal(nodesLeftEdge, nodesLeftEdge_))); REQUIRE(xt::all(xt::equal(nodesRightEdge, nodesRightEdge_))); REQUIRE(xt::all(xt::equal(nodesBottomOpenEdge, nodesBottomOpenEdge_))); REQUIRE(xt::all(xt::equal(nodesTopOpenEdge, nodesTopOpenEdge_))); REQUIRE(xt::all(xt::equal(nodesLeftOpenEdge, nodesLeftOpenEdge_))); REQUIRE(xt::all(xt::equal(nodesRightOpenEdge, nodesRightOpenEdge_))); REQUIRE(xt::all(xt::equal(nodesPeriodic, nodesPeriodic_))); REQUIRE(xt::all(xt::equal(dofsPeriodic, dofsPeriodic_))); } SECTION("FineLayer::elementgrid_ravel - uniform") { GooseFEM::Mesh::Quad4::FineLayer mesh(5, 5); xt::xtensor<size_t, 1> a = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24}; REQUIRE(xt::all(xt::equal(a, mesh.elementgrid_ravel({0, 5}, {0, 5})))); REQUIRE(xt::all(xt::equal(a, mesh.elementgrid_ravel({0, 5}, {})))); REQUIRE(xt::all(xt::equal(a, mesh.elementgrid_ravel({}, {0, 5})))); REQUIRE(xt::all(xt::equal(a, mesh.elementgrid_ravel({}, {})))); xt::xtensor<size_t, 1> b = { 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19}; REQUIRE(xt::all(xt::equal(b, mesh.elementgrid_ravel({1, 4}, {0, 5})))); xt::xtensor<size_t, 1> c = { 6, 7, 8, 11, 12, 13, 16, 17, 18}; REQUIRE(xt::all(xt::equal(c, mesh.elementgrid_ravel({1, 4}, {1, 4})))); } SECTION("FineLayer::elementgrid_ravel - refined") { GooseFEM::Mesh::Quad4::FineLayer mesh(6, 18); xt::xtensor<size_t, 1> a = { 19, 20, 21, 22, 25, 26, 27, 28, 31, 32, 33, 34}; REQUIRE(xt::all(xt::equal(a, mesh.elementgrid_ravel({9, 12}, {1, 5})))); xt::xtensor<size_t, 1> b = { 0, 1, 2, 3}; REQUIRE(xt::all(xt::equal(b, mesh.elementgrid_ravel({0, 6}, {0, 6})))); xt::xtensor<size_t, 1> c = { 50, 51, 52, 53}; REQUIRE(xt::all(xt::equal(c, mesh.elementgrid_ravel({15, 21}, {0, 6})))); xt::xtensor<size_t, 1> d = { 4, 5, 6, 7, 8, 9, 10, 11}; REQUIRE(xt::all(xt::equal(d, mesh.elementgrid_ravel({6, 8}, {0, 6})))); } SECTION("FineLayer::elementgrid_ravel - uniform") { GooseFEM::Mesh::Quad4::FineLayer mesh(5, 5); xt::xtensor<size_t, 1> a = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24}; REQUIRE(xt::all(xt::equal(a, xt::sort(mesh.elementgrid_around_ravel(10, 2))))); REQUIRE(xt::all(xt::equal(a, xt::sort(mesh.elementgrid_around_ravel(11, 2))))); REQUIRE(xt::all(xt::equal(a, xt::sort(mesh.elementgrid_around_ravel(12, 2))))); REQUIRE(xt::all(xt::equal(a, xt::sort(mesh.elementgrid_around_ravel(13, 2))))); REQUIRE(xt::all(xt::equal(a, xt::sort(mesh.elementgrid_around_ravel(14, 2))))); xt::xtensor<size_t, 1> b10 = { 5, 6, 9, 10, 11, 14, 15, 16, 19}; xt::xtensor<size_t, 1> b11 = { 5, 6, 7, 10, 11, 12, 15, 16, 17}; xt::xtensor<size_t, 1> b12 = { 6, 7, 8, 11, 12, 13, 16, 17, 18}; xt::xtensor<size_t, 1> b13 = { 7, 8, 9, 12, 13, 14, 17, 18, 19}; xt::xtensor<size_t, 1> b14 = { 5, 8, 9, 10, 13, 14, 15, 18, 19}; REQUIRE(xt::all(xt::equal(xt::sort(b10), xt::sort(mesh.elementgrid_around_ravel(10, 1))))); REQUIRE(xt::all(xt::equal(xt::sort(b11), xt::sort(mesh.elementgrid_around_ravel(11, 1))))); REQUIRE(xt::all(xt::equal(xt::sort(b12), xt::sort(mesh.elementgrid_around_ravel(12, 1))))); REQUIRE(xt::all(xt::equal(xt::sort(b13), xt::sort(mesh.elementgrid_around_ravel(13, 1))))); REQUIRE(xt::all(xt::equal(xt::sort(b14), xt::sort(mesh.elementgrid_around_ravel(14, 1))))); REQUIRE(xt::all(xt::equal(10, xt::sort(mesh.elementgrid_around_ravel(10, 0))))); REQUIRE(xt::all(xt::equal(11, xt::sort(mesh.elementgrid_around_ravel(11, 0))))); REQUIRE(xt::all(xt::equal(12, xt::sort(mesh.elementgrid_around_ravel(12, 0))))); REQUIRE(xt::all(xt::equal(13, xt::sort(mesh.elementgrid_around_ravel(13, 0))))); REQUIRE(xt::all(xt::equal(14, xt::sort(mesh.elementgrid_around_ravel(14, 0))))); } SECTION("FineLayer::elementgrid_around_ravel") { GooseFEM::Mesh::Quad4::FineLayer mesh(12, 18); xt::xtensor<size_t, 1> r0 = { 36, 37, 71, 48, 49, 59, 60, 61, 47, }; xt::xtensor<size_t, 1> r1 = { 36, 37, 38, 48, 49, 50, 60, 61, 62, }; xt::xtensor<size_t, 1> r12 = { 46, 47, 36, 58, 59, 48, 70, 71, 60, }; REQUIRE(xt::all(xt::equal(xt::sort(r0), xt::sort(mesh.elementgrid_around_ravel(48, 1))))); for (size_t n = 0; n < 10; ++n) { REQUIRE(xt::all(xt::equal(xt::sort(r1) + n, xt::sort(mesh.elementgrid_around_ravel(49 + n, 1))))); } REQUIRE(xt::all(xt::equal(xt::sort(r12), xt::sort(mesh.elementgrid_around_ravel(59, 1))))); } SECTION("FineLayer::elementgrid_leftright") { GooseFEM::Mesh::Quad4::FineLayer mesh(12, 18); xt::xtensor<size_t, 1> r0 = { 48, 49, 59, }; xt::xtensor<size_t, 1> r1 = { 48, 49, 50, }; xt::xtensor<size_t, 1> r12 = { 58, 59, 48, }; REQUIRE(xt::all(xt::equal(xt::sort(r0), xt::sort(mesh.elementgrid_leftright(48, 1, 1))))); for (size_t n = 0; n < 10; ++n) { REQUIRE(xt::all(xt::equal(xt::sort(r1) + n, xt::sort(mesh.elementgrid_leftright(49 + n, 1, 1))))); } REQUIRE(xt::all(xt::equal(xt::sort(r12), xt::sort(mesh.elementgrid_leftright(59, 1, 1))))); } SECTION("FineLayer - replica - trivial") { GooseFEM::Mesh::Quad4::FineLayer mesh(1, 1); GooseFEM::Mesh::Quad4::FineLayer replica(mesh.coor(), mesh.conn()); REQUIRE(xt::all(xt::equal(mesh.conn(), replica.conn()))); REQUIRE(xt::allclose(mesh.coor(), replica.coor())); } SECTION("FineLayer - replica - equi-sized") { GooseFEM::Mesh::Quad4::FineLayer mesh(4, 4); GooseFEM::Mesh::Quad4::FineLayer replica(mesh.coor(), mesh.conn()); REQUIRE(xt::all(xt::equal(mesh.conn(), replica.conn()))); REQUIRE(xt::allclose(mesh.coor(), replica.coor())); } SECTION("FineLayer - replica") { GooseFEM::Mesh::Quad4::FineLayer mesh(27, 27); GooseFEM::Mesh::Quad4::FineLayer replica(mesh.coor(), mesh.conn()); REQUIRE(xt::all(xt::equal(mesh.conn(), replica.conn()))); REQUIRE(xt::allclose(mesh.coor(), replica.coor())); } SECTION("FineLayer - replica - one") { double h = xt::numeric_constants<double>::PI; GooseFEM::Mesh::Quad4::FineLayer mesh(1, 1, h); GooseFEM::Mesh::Quad4::FineLayer replica(mesh.coor(), mesh.conn()); REQUIRE(xt::all(xt::equal(mesh.conn(), replica.conn()))); REQUIRE(xt::allclose(mesh.coor(), replica.coor())); } SECTION("FineLayer - replica - large") { size_t N = 2 * std::pow(3, 6); double h = xt::numeric_constants<double>::PI; GooseFEM::Mesh::Quad4::FineLayer mesh(N, N, h); GooseFEM::Mesh::Quad4::FineLayer replica(mesh.coor(), mesh.conn()); REQUIRE(xt::all(xt::equal(mesh.conn(), replica.conn()))); REQUIRE(xt::allclose(mesh.coor(), replica.coor())); } SECTION("FineLayer - roll - trivial") { GooseFEM::Mesh::Quad4::FineLayer mesh(3, 3); xt::xtensor<size_t, 1> m0 = { 0, 1, 2, 3, 4, 5, 6, 7, 8 }; xt::xtensor<size_t, 1> m1 = { 2, 0, 1, 5, 3, 4, 8, 6, 7 }; xt::xtensor<size_t, 1> m2 = { 1, 2, 0, 4, 5, 3, 7, 8, 6, }; REQUIRE(xt::all(xt::equal(mesh.roll(0), m0))); REQUIRE(xt::all(xt::equal(mesh.roll(1), m1))); REQUIRE(xt::all(xt::equal(mesh.roll(2), m2))); REQUIRE(xt::all(xt::equal(mesh.roll(3), m0))); REQUIRE(xt::all(xt::equal(mesh.roll(4), m1))); REQUIRE(xt::all(xt::equal(mesh.roll(5), m2))); } SECTION("FineLayer - roll - a") { GooseFEM::Mesh::Quad4::FineLayer mesh(6, 18); xt::xtensor<size_t, 1> m0 = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53 }; xt::xtensor<size_t, 1> m1 = { 1, 0, 3, 2, 8, 9, 10, 11, 4, 5, 6, 7, 15, 16, 17, 12, 13, 14, 21, 22, 23, 18, 19, 20, 27, 28, 29, 24, 25, 26, 33, 34, 35, 30, 31, 32, 39, 40, 41, 36, 37, 38, 46, 47, 48, 49, 42, 43, 44, 45, 51, 50, 53, 52 }; REQUIRE(xt::all(xt::equal(mesh.roll(0), m0))); REQUIRE(xt::all(xt::equal(mesh.roll(1), m1))); REQUIRE(xt::all(xt::equal(mesh.roll(2), m0))); REQUIRE(xt::all(xt::equal(mesh.roll(3), m1))); } SECTION("FineLayer - roll - b") { GooseFEM::Mesh::Quad4::FineLayer mesh(9, 18); xt::xtensor<size_t, 1> m0 = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80 }; xt::xtensor<size_t, 1> m1 = { 2, 0, 1, 5, 3, 4, 14, 15, 16, 17, 6, 7, 8, 9, 10, 11, 12, 13, 24, 25, 26, 18, 19, 20, 21, 22, 23, 33, 34, 35, 27, 28, 29, 30, 31, 32, 42, 43, 44, 36, 37, 38, 39, 40, 41, 51, 52, 53, 45, 46, 47, 48, 49, 50, 60, 61, 62, 54, 55, 56, 57, 58, 59, 71, 72, 73, 74, 63, 64, 65, 66, 67, 68, 69, 70, 77, 75, 76, 80, 78, 79 }; xt::xtensor<size_t, 1> m2 = { 1, 2, 0, 4, 5, 3, 10, 11, 12, 13, 14, 15, 16, 17, 6, 7, 8, 9, 21, 22, 23, 24, 25, 26, 18, 19, 20, 30, 31, 32, 33, 34, 35, 27, 28, 29, 39, 40, 41, 42, 43, 44, 36, 37, 38, 48, 49, 50, 51, 52, 53, 45, 46, 47, 57, 58, 59, 60, 61, 62, 54, 55, 56, 67, 68, 69, 70, 71, 72, 73, 74, 63, 64, 65, 66, 76, 77, 75, 79, 80, 78 }; REQUIRE(xt::all(xt::equal(mesh.roll(0), m0))); REQUIRE(xt::all(xt::equal(mesh.roll(1), m1))); REQUIRE(xt::all(xt::equal(mesh.roll(2), m2))); REQUIRE(xt::all(xt::equal(mesh.roll(3), m0))); REQUIRE(xt::all(xt::equal(mesh.roll(4), m1))); REQUIRE(xt::all(xt::equal(mesh.roll(5), m2))); } SECTION("Map::RefineRegular") { GooseFEM::Mesh::Quad4::Regular mesh(5, 4); GooseFEM::Mesh::Quad4::Map::RefineRegular refine(mesh, 5, 3); - xt::xtensor<double, 1> a = xt::random::rand<double>({mesh.nelem()}); + std::array<size_t, 1> as = {mesh.nelem()}; + xt::xtensor<double, 1> a = xt::random::rand<double>(as); auto a_ = refine.mapToCoarse(refine.mapToFine(a)); REQUIRE(xt::allclose(a, xt::mean(a_, {1}))); - xt::xtensor<double, 2> b = - xt::random::rand<double>(std::array<size_t, 2>{mesh.nelem(), 4ul}); + std::array<size_t, 2> bs = {mesh.nelem(), 4}; + xt::xtensor<double, 2> b = xt::random::rand<double>(bs); auto b_ = refine.mapToCoarse(refine.mapToFine(b)); REQUIRE(xt::allclose(xt::mean(b, {1}), xt::mean(b_, {1}))); - xt::xtensor<double, 4> c = - xt::random::rand<double>(std::array<size_t, 4>{mesh.nelem(), 4ul, 3ul, 3ul}); + std::array<size_t, 4> cs = {mesh.nelem(), 4, 3, 3}; + xt::xtensor<double, 4> c = xt::random::rand<double>(cs); auto c_ = refine.mapToCoarse(refine.mapToFine(c)); REQUIRE(xt::allclose(xt::mean(c, {1}), xt::mean(c_, {1}))); } SECTION("Map::FineLayer2Regular") { GooseFEM::Mesh::Quad4::FineLayer mesh(5, 5); GooseFEM::Mesh::Quad4::Map::FineLayer2Regular map(mesh); - xt::xtensor<double, 1> a = xt::random::rand<double>({mesh.nelem()}); + std::array<size_t, 1> as = {mesh.nelem()}; + xt::xtensor<double, 1> a = xt::random::rand<double>(as); auto a_ = map.mapToRegular(a); REQUIRE(xt::allclose(a, a_)); - xt::xtensor<double, 2> b = - xt::random::rand<double>(std::array<size_t, 2>{mesh.nelem(), 4ul}); + std::array<size_t, 2> bs = {mesh.nelem(), 4}; + xt::xtensor<double, 2> b = xt::random::rand<double>(bs); auto b_ = map.mapToRegular(b); REQUIRE(xt::allclose(b, b_)); - xt::xtensor<double, 4> c = - xt::random::rand<double>(std::array<size_t, 4>{mesh.nelem(), 4ul, 3ul, 3ul}); + std::array<size_t, 4> cs = {mesh.nelem(), 4, 3, 3}; + xt::xtensor<double, 4> c = xt::random::rand<double>(cs); auto c_ = map.mapToRegular(c); REQUIRE(xt::allclose(c, c_)); } }