diff --git a/CMakeLists.txt b/CMakeLists.txt index 4bd237d..1696214 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,145 +1,145 @@ #==================================================================================================# # # # (c - GPLv3) T.W.J. de Geus (Tom) | tom@geus.me | www.geus.me | github.com/tdegeus/GooseFEM # # # #==================================================================================================# # initialization # -------------- # required to specify the c++ standard cmake_minimum_required(VERSION 3.0) # required for install include(CMakePackageConfigHelpers) include(GNUInstallDirs) # options option(PKGCONFIG "Build pkg-config" ON) option(BUILD_TESTS "${PROJECT_NAME} test suite" OFF) # project settings # ---------------- # name -project(xGooseFEM) +project(GooseFEM) # file that contains the version information -set(parse_version include/xGooseFEM/GooseFEM.h) +set(parse_version include/GooseFEM/GooseFEM.h) # header files set(headers - include/xGooseFEM/GooseFEM.h - include/xGooseFEM/Mesh.hpp - include/xGooseFEM/Mesh.h - include/xGooseFEM/MeshTri3.hpp - include/xGooseFEM/MeshTri3.h - include/xGooseFEM/MeshQuad4.hpp - include/xGooseFEM/MeshQuad4.h - include/xGooseFEM/MeshHex8.hpp - include/xGooseFEM/MeshHex8.h - include/xGooseFEM/Element.hpp - include/xGooseFEM/Element.h - include/xGooseFEM/ElementQuad4.hpp - include/xGooseFEM/ElementQuad4.h - include/xGooseFEM/ElementQuad4Planar.hpp - include/xGooseFEM/ElementQuad4Planar.h - include/xGooseFEM/ElementHex8.hpp - include/xGooseFEM/ElementHex8.h - include/xGooseFEM/Vector.hpp - include/xGooseFEM/Vector.h - include/xGooseFEM/VectorPartitioned.hpp - include/xGooseFEM/VectorPartitioned.h - include/xGooseFEM/MatrixPartitioned.hpp - include/xGooseFEM/MatrixPartitioned.h - include/xGooseFEM/MatrixDiagonal.hpp - include/xGooseFEM/MatrixDiagonal.h - include/xGooseFEM/MatrixDiagonalPartitioned.hpp - include/xGooseFEM/MatrixDiagonalPartitioned.h - include/xGooseFEM/Iterate.hpp - include/xGooseFEM/Iterate.h - include/xGooseFEM/Dynamics.hpp - include/xGooseFEM/Dynamics.h + include/GooseFEM/GooseFEM.h + include/GooseFEM/Mesh.hpp + include/GooseFEM/Mesh.h + include/GooseFEM/MeshTri3.hpp + include/GooseFEM/MeshTri3.h + include/GooseFEM/MeshQuad4.hpp + include/GooseFEM/MeshQuad4.h + include/GooseFEM/MeshHex8.hpp + include/GooseFEM/MeshHex8.h + include/GooseFEM/Element.hpp + include/GooseFEM/Element.h + include/GooseFEM/ElementQuad4.hpp + include/GooseFEM/ElementQuad4.h + include/GooseFEM/ElementQuad4Planar.hpp + include/GooseFEM/ElementQuad4Planar.h + include/GooseFEM/ElementHex8.hpp + include/GooseFEM/ElementHex8.h + include/GooseFEM/Vector.hpp + include/GooseFEM/Vector.h + include/GooseFEM/VectorPartitioned.hpp + include/GooseFEM/VectorPartitioned.h + include/GooseFEM/MatrixPartitioned.hpp + include/GooseFEM/MatrixPartitioned.h + include/GooseFEM/MatrixDiagonal.hpp + include/GooseFEM/MatrixDiagonal.h + include/GooseFEM/MatrixDiagonalPartitioned.hpp + include/GooseFEM/MatrixDiagonalPartitioned.h + include/GooseFEM/Iterate.hpp + include/GooseFEM/Iterate.h + include/GooseFEM/Dynamics.hpp + include/GooseFEM/Dynamics.h ) # automatically parse the version number file(READ "${parse_version}" version) string(REGEX MATCH "define[ \t]+GOOSEFEM_WORLD_VERSION[ \t]+([0-9]+)" _ "${version}") set(world_version "${CMAKE_MATCH_1}") string(REGEX MATCH "define[ \t]+GOOSEFEM_MAJOR_VERSION[ \t]+([0-9]+)" _ "${version}") set(major_version "${CMAKE_MATCH_1}") string(REGEX MATCH "define[ \t]+GOOSEFEM_MINOR_VERSION[ \t]+([0-9]+)" _ "${version}") set(minor_version "${CMAKE_MATCH_1}") set(GOOSEFEM_VERSION ${world_version}.${major_version}.${minor_version}) # print information to screen message(STATUS "Building ${PROJECT_NAME} v${GOOSEFEM_VERSION}") # paths # ----- set(GOOSEFEM_ROOT_DIR "${CMAKE_INSTALL_PREFIX}") set(GOOSEFEM_INCLUDE_DIR "${CMAKE_INSTALL_PREFIX}/${INCLUDE_INSTALL_DIR}") set(INCLUDE_INSTALL_DIR "${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}") set(CMAKEPACKAGE_INSTALL_DIR "${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}") set(PKGCONFIG_INSTALL_DIR "${CMAKE_INSTALL_DATADIR}/pkgconfig") set(fcmake "GooseFEMConfig.cmake") set(fpkg "GooseFEM.pc") # configure CMake # --------------- configure_package_config_file( ${CMAKE_CURRENT_SOURCE_DIR}/GooseFEMConfig.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/GooseFEMConfig.cmake PATH_VARS GOOSEFEM_INCLUDE_DIR GOOSEFEM_ROOT_DIR INSTALL_DESTINATION ${CMAKEPACKAGE_INSTALL_DIR} NO_CHECK_REQUIRED_COMPONENTS_MACRO ) # install/build # ------------- # build test cases if(BUILD_TESTS) add_subdirectory(test) endif() # disable pkg-config for native Windows builds if(WIN32 OR CMAKE_HOST_SYSTEM_NAME MATCHES Windows) option(PKGCONFIG "Build pkg-config ${fpkg} file" OFF) endif() # pkg-config if(PKGCONFIG) configure_file(${fpkg}.in ${fpkg} @ONLY) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${fpkg} DESTINATION ${PKGCONFIG_INSTALL_DIR}) endif() # CMake install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${fcmake} DESTINATION ${CMAKEPACKAGE_INSTALL_DIR}) # header files install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${headers} DESTINATION ${INCLUDE_INSTALL_DIR}) # print information to screen # --------------------------- message(STATUS "") message(STATUS "+---------------------------------------------------------------------------------") message(STATUS "|") message(STATUS "| Use 'make install' to install in") message(STATUS "| ${CMAKE_INSTALL_PREFIX}") if(BUILD_TESTS) message(STATUS "|") message(STATUS "| Use 'make' and './test/test' to run the tests") endif() message(STATUS "|") message(STATUS "| To specify a custom directory call") message(STATUS "| cmake /path/to/${PROJECT_NAME} -DCMAKE_INSTALL_PREFIX=yourprefix") message(STATUS "|") message(STATUS "| For custom paths, add the following line to your '~/.bashrc'") message(STATUS "| export PKG_CONFIG_PATH=${CMAKE_INSTALL_PREFIX}/share/pkgconfig:$PKG_CONFIG_PATH") message(STATUS "|") message(STATUS "+---------------------------------------------------------------------------------") message(STATUS "") diff --git a/docs/examples/Dynamics/laminateElastic/noDamping/main.cpp b/docs/examples/Dynamics/laminateElastic/noDamping/main.cpp index b432085..da9afb3 100644 --- a/docs/examples/Dynamics/laminateElastic/noDamping/main.cpp +++ b/docs/examples/Dynamics/laminateElastic/noDamping/main.cpp @@ -1,239 +1,239 @@ -#include +#include #include #include // ------------------------------------------------------------------------------------------------- -namespace GF = xGooseFEM; -namespace QD = xGooseFEM::Element::Quad4; +namespace GF = GooseFEM; +namespace QD = GooseFEM::Element::Quad4; namespace GM = xElastoPlasticQPot::Cartesian2d; using T2 = xt::xtensor_fixed>; // ------------------------------------------------------------------------------------------------- inline double sqdot(const xt::xtensor &M, const xt::xtensor &V) { double out = 0.; for ( size_t i = 0 ; i < M.size() ; ++i ) out += M(i) * V(i) * V(i); return out; } // ------------------------------------------------------------------------------------------------- -class Geometry : public xGooseFEM::Dynamics::Geometry +class Geometry : public GooseFEM::Dynamics::Geometry { private: // dimensions size_t m_nnode; size_t m_ndim; size_t m_nelem; size_t m_nne; size_t m_nip; // mesh xt::xtensor m_conn; xt::xtensor m_coor; xt::xtensor m_u; xt::xtensor m_v; xt::xtensor m_a; // vector-definition: transform nodal vectors <-> DOF values GF::Vector m_vec; // mass matrix (diagonal) GF::MatrixDiagonal m_M; // numerical quadrature QD::Quadrature m_quad; // material definition GM::Matrix m_mat; public: // constructor Geometry(size_t nx); // apply update in macroscopic deformation gradient void add_dFbar(const T2 &dFbar); // compute total kinetic and potential energy double Ekin() const; double Epot() const; // return mesh xt::xtensor conn() const { return m_conn; } xt::xtensor coor() const { return m_coor; } // return nodal vectors xt::xtensor u() const { return m_u; } xt::xtensor v() const { return m_v; } xt::xtensor a() const { return m_a; } // return DOF values xt::xtensor dofs_v() const { return m_vec.asDofs(m_v); } xt::xtensor dofs_a() const { return m_vec.asDofs(m_a); } // overwrite nodal vectors void set_u(const xt::xtensor &nodevec) { m_u = nodevec; }; // overwrite nodal vectors, reconstructed from DOF values void set_v(const xt::xtensor &dofval) { m_v = m_vec.asNode(dofval); }; void set_a(const xt::xtensor &dofval) { m_a = m_vec.asNode(dofval); }; // solve for DOF-accelerations xt::xtensor solve_A(); }; // ------------------------------------------------------------------------------------------------- inline Geometry::Geometry(size_t nx) { // get mesh GF::Mesh::Quad4::Regular mesh(nx,nx,1.); // vector-definition m_vec = GF::Vector(mesh.conn(), mesh.dofsPeriodic()); // quadrature m_quad = QD::Quadrature(m_vec.asElement(mesh.coor())); // dimensions, connectivity, and coordinates m_nnode = mesh.nnode(); m_ndim = mesh.ndim(); m_nelem = mesh.nelem(); m_nne = mesh.nne(); m_nip = m_quad.nip(); m_conn = mesh.conn(); m_coor = mesh.coor(); // zero-initialize displacement, velocity, acceleration m_u = xt::zeros({m_nnode, m_ndim}); m_v = xt::zeros({m_nnode, m_ndim}); m_a = xt::zeros({m_nnode, m_ndim}); // material definition // - allocate m_mat = GM::Matrix({m_nelem, m_nip}); // - phase indicators xt::xtensor Ihard = xt::zeros({m_nelem, m_nip}); xt::xtensor Isoft = xt::ones ({m_nelem, m_nip}); // - set hard indicator for ( size_t e = 0 ; e < nx*nx/4 ; ++e ) for ( size_t k = 0 ; k < m_nip ; ++k ) Ihard(e,k) = 1; // - set soft indicator Isoft -= Ihard; // - set material definition m_mat.setElastic(Ihard, 100., 10.); m_mat.setElastic(Isoft, 100., 1.); // - check that all points have been set (not strictly needed) m_mat.check(); // mass matrix // - nodal quadrature QD::Quadrature q(m_vec.asElement(m_coor), QD::Nodal::xi(), QD::Nodal::w()); // - set density xt::xtensor rho = 1.0 * xt::ones({m_nelem, m_nip}); // - allocate mass matrix m_M = GF::MatrixDiagonal(m_conn, mesh.dofsPeriodic()); // - compute (constant hereafter) m_M.assemble( q.int_N_scalar_NT_dV(rho) ); } // ------------------------------------------------------------------------------------------------- inline xt::xtensor Geometry::solve_A() { xt::xtensor Eps = m_quad.symGradN_vector( m_vec.asElement(m_u) ); xt::xtensor Sig = m_mat.Sig(Eps); xt::xtensor F = m_vec.assembleDofs( m_quad.int_gradN_dot_tensor2_dV(Sig) ); return m_M.solve( -F ); } // ------------------------------------------------------------------------------------------------- inline void Geometry::add_dFbar(const T2 &dFbar) { for ( size_t i = 0 ; i < m_nnode ; ++i ) for ( size_t j = 0 ; j < m_ndim ; ++j ) for ( size_t k = 0 ; k < m_ndim ; ++k ) m_u(i,j) += dFbar(j,k) * ( m_coor(i,k) - m_coor(0,k) ); } // ------------------------------------------------------------------------------------------------- inline double Geometry::Ekin() const { xt::xtensor V = m_vec.asDofs(m_v); xt::xtensor M = m_M.asDiagonal(); return 0.5 * sqdot(M,V); } // ------------------------------------------------------------------------------------------------- inline double Geometry::Epot() const { xt::xtensor Eps = m_quad.symGradN_vector( m_vec.asElement(m_u) ); xt::xtensor E = m_mat.energy(Eps); xt::xtensor dV = m_quad.dV(); return ( xt::sum( E*dV ) )[0]; } // ------------------------------------------------------------------------------------------------- int main() { // set simulation parameters double T = 60. ; // total time double dt = 1.e-2; // time increment size_t nx = 60 ; // number of elements in both directions double gamma = .05 ; // displacement step // define geometry Geometry geometry(nx); // define update in macroscopic deformation gradient T2 dFbar = xt::zeros({2,2}); dFbar(0,1) = gamma; // update displacement geometry.add_dFbar(dFbar); // output variables xt::xtensor Epot = xt::zeros({static_cast(T/dt)}); xt::xtensor Ekin = xt::zeros({static_cast(T/dt)}); xt::xtensor t = xt::zeros({static_cast(T/dt)}); // loop over increments for ( size_t inc = 0 ; inc < static_cast(Epot.size()) ; ++inc ) { // - compute increment GF::Dynamics::velocityVerlet(geometry, dt); // - store output t (inc) = static_cast(inc) * dt; Ekin(inc) = geometry.Ekin(); Epot(inc) = geometry.Epot(); } // write to output file H5p::File f = H5p::File("example.hdf5","w"); f.write("/global/Epot",Epot ); f.write("/global/Ekin",Ekin ); f.write("/global/t" ,t ); f.write("/mesh/conn" ,geometry.conn()); f.write("/mesh/coor" ,geometry.coor()); f.write("/mesh/disp" ,geometry.u() ); return 0; } diff --git a/docs/examples/Statics/LinearElasticity.cpp b/docs/examples/Statics/LinearElasticity.cpp index eae2885..dad4bd6 100644 --- a/docs/examples/Statics/LinearElasticity.cpp +++ b/docs/examples/Statics/LinearElasticity.cpp @@ -1,71 +1,71 @@ -#include +#include #include int main() { // mesh // ---- - xGooseFEM::Mesh::Quad4::Regular mesh(5,5); + GooseFEM::Mesh::Quad4::Regular mesh(5,5); xt::xtensor coor = mesh.coor(); xt::xtensor conn = mesh.conn(); xt::xtensor dofs = mesh.dofs(); xt::xtensor disp = xt::zeros(coor.shape()); xt::xtensor nodesLeft = mesh.nodesLeftEdge(); xt::xtensor nodesRight = mesh.nodesRightEdge(); xt::xtensor nodesTop = mesh.nodesTopEdge(); xt::xtensor nodesBottom = mesh.nodesBottomEdge(); // boundary displacements // ---------------------- xt::xtensor iip = xt::empty({2*nodesLeft.size()+2*nodesBottom.size()}); xt::xtensor u_p = xt::zeros(iip.shape()); size_t i = 0; for ( auto &n : nodesRight ) { iip(i) = dofs(n,0); u_p(i) = 0.1; ++i; } for ( auto &n : nodesTop ) { iip(i) = dofs(n,1); u_p(i) = -0.1; ++i; } for ( auto &n : nodesLeft ) { iip(i) = dofs(n,0); u_p(i) = 0.0; ++i; } for ( auto &n : nodesBottom ) { iip(i) = dofs(n,1); u_p(i) = 0.0; ++i; } // element definition // ------------------ - xGooseFEM::VectorPartitioned vector(conn, dofs, iip); - xGooseFEM::MatrixPartitioned K (conn, dofs, iip); + GooseFEM::VectorPartitioned vector(conn, dofs, iip); + GooseFEM::MatrixPartitioned K (conn, dofs, iip); - xGooseFEM::Element::Quad4::QuadraturePlanar elem(vector.asElement(coor)); + GooseFEM::Element::Quad4::QuadraturePlanar elem(vector.asElement(coor)); GMatLinearElastic::Cartesian3d::Material mat(mesh.nelem(), elem.nip(), 1., 1.); // solve // ----- // strain xt::xtensor Eps = elem.symGradN_vector(vector.asElement(disp)); // stress xt::xtensor Sig = mat.Sig(Eps); // tangent xt::xtensor C = mat.Tangent(); // internal force xt::xtensor fint = vector.asNode(elem.int_gradN_dot_tensor2_dV(Sig)); // stiffness matrix K.assemble(elem.int_gradN_dot_tensor4_dot_gradNT_dV(C)); // solve xt::xtensor u_u = K.solve(vector.asDofs_u(fint), u_p); // assemble to nodal vector disp = vector.asNode(u_u, u_p); // print result std::cout << disp << std::endl; return 0; } diff --git a/include/xGooseFEM/.gitignore b/include/GooseFEM/.gitignore similarity index 100% rename from include/xGooseFEM/.gitignore rename to include/GooseFEM/.gitignore diff --git a/include/xGooseFEM/Dynamics.h b/include/GooseFEM/Dynamics.h similarity index 96% rename from include/xGooseFEM/Dynamics.h rename to include/GooseFEM/Dynamics.h index 66afee2..69658c1 100644 --- a/include/xGooseFEM/Dynamics.h +++ b/include/GooseFEM/Dynamics.h @@ -1,67 +1,67 @@ /* ================================================================================================= (c - GPLv3) T.W.J. de Geus (Tom) | tom@geus.me | www.geus.me | github.com/tdegeus/GooseFEM ================================================================================================= */ -#ifndef XGOOSEFEM_DYNAMICS_H -#define XGOOSEFEM_DYNAMICS_H +#ifndef GOOSEFEM_DYNAMICS_H +#define GOOSEFEM_DYNAMICS_H // ------------------------------------------------------------------------------------------------- #include "GooseFEM.h" // ======================================= GooseFEM::Dynamics ======================================= -namespace xGooseFEM { +namespace GooseFEM { namespace Dynamics { // ------------------------------------------ dummy class ------------------------------------------ class Geometry { public: // destructor virtual ~Geometry() {}; // solve for DOF-accelerations [ndof] virtual xt::xtensor solve_A() { return xt::empty({0}); }; virtual xt::xtensor solve_V() { return xt::empty({0}); }; // return nodal vectors [nnode, ndim] virtual xt::xtensor u() const { return xt::empty({0,0}); }; virtual xt::xtensor v() const { return xt::empty({0,0}); }; virtual xt::xtensor a() const { return xt::empty({0,0}); }; // return DOF values [ndof] virtual xt::xtensor dofs_u() const { return xt::empty({0}); }; virtual xt::xtensor dofs_v() const { return xt::empty({0}); }; virtual xt::xtensor dofs_a() const { return xt::empty({0}); }; // overwrite nodal vectors [nnode, ndim] virtual void set_u(const xt::xtensor &nodevec) { UNUSED(nodevec); return; }; // overwrite nodal vectors, reconstructed from DOF values [ndof] virtual void set_u(const xt::xtensor &dofval) { UNUSED(dofval); return; }; virtual void set_v(const xt::xtensor &dofval) { UNUSED(dofval); return; }; virtual void set_a(const xt::xtensor &dofval) { UNUSED(dofval); return; }; }; // ------------------------------------ evaluate one time step ------------------------------------- inline void Verlet (Geometry &geometry, double dt, size_t nstep=1); inline void velocityVerlet(Geometry &geometry, double dt, size_t nstep=1); namespace Overdamped { inline void forwardEuler (Geometry &geometry, double dt, size_t nstep=1); } // ------------------------------------------------------------------------------------------------- }} // namespace ... // ================================================================================================= #endif diff --git a/include/xGooseFEM/Dynamics.hpp b/include/GooseFEM/Dynamics.hpp similarity index 97% rename from include/xGooseFEM/Dynamics.hpp rename to include/GooseFEM/Dynamics.hpp index 27e5654..bfe60f6 100644 --- a/include/xGooseFEM/Dynamics.hpp +++ b/include/GooseFEM/Dynamics.hpp @@ -1,124 +1,124 @@ /* ================================================================================================= (c - GPLv3) T.W.J. de Geus (Tom) | tom@geus.me | www.geus.me | github.com/tdegeus/GooseFEM ================================================================================================= */ -#ifndef XGOOSEFEM_DYNAMCS_CPP -#define XGOOSEFEM_DYNAMCS_CPP +#ifndef GOOSEFEM_DYNAMCS_CPP +#define GOOSEFEM_DYNAMCS_CPP // ------------------------------------------------------------------------------------------------- #include "Dynamics.h" // ======================================= GooseFEM::Dynamics ======================================= -namespace xGooseFEM { +namespace GooseFEM { namespace Dynamics { // ------------------------------------------------------------------------------------------------- inline void Verlet(Geometry &g, double dt, size_t nstep) { for ( size_t istep = 0 ; istep < nstep ; ++istep ) { // variables & history xt::xtensor u; xt::xtensor V; xt::xtensor A; xt::xtensor V_n = g.dofs_v(); xt::xtensor A_n = g.dofs_a(); // new displacement xt::noalias(u) = g.u() + dt * g.v() + 0.5 * std::pow(dt,2.) * g.a(); g.set_u(u); // new acceleration xt::noalias(A) = g.solve_A(); g.set_a(A); // new velocity xt::noalias(V) = V_n + .5 * dt * ( A_n + A ); g.set_v(V); } } // ------------------------------------------------------------------------------------------------- inline void velocityVerlet(Geometry &g, double dt, size_t nstep) { for ( size_t istep = 0 ; istep < nstep ; ++istep ) { // variables & history xt::xtensor u; xt::xtensor V; xt::xtensor A; xt::xtensor V_n = g.dofs_v(); xt::xtensor A_n = g.dofs_a(); // new displacement xt::noalias(u) = g.u() + dt * g.v() + 0.5 * std::pow(dt,2.) * g.a(); g.set_u(u); // estimate new velocity xt::noalias(V) = V_n + dt * A_n; g.set_v(V); xt::noalias(A) = g.solve_A(); xt::noalias(V) = V_n + .5 * dt * ( A_n + A ); g.set_v(V); // new velocity xt::noalias(A) = g.solve_A(); xt::noalias(V) = V_n + .5 * dt * ( A_n + A ); g.set_v(V); // new acceleration xt::noalias(A) = g.solve_A(); g.set_a(A); } } // ------------------------------------------------------------------------------------------------- namespace Overdamped { inline void forwardEuler(Geometry &g, double dt, size_t nstep) { xt::xtensor U; for ( size_t istep = 0 ; istep < nstep ; ++istep ) { xt::noalias(U) = g.dofs_u() + dt * g.solve_V(); g.set_u(U); } } } // ------------------------------------------------------------------------------------------------- }} // namespace ... // ================================================================================================= #endif diff --git a/include/xGooseFEM/Element.h b/include/GooseFEM/Element.h similarity index 95% rename from include/xGooseFEM/Element.h rename to include/GooseFEM/Element.h index 00a4ca2..dbb770e 100644 --- a/include/xGooseFEM/Element.h +++ b/include/GooseFEM/Element.h @@ -1,41 +1,41 @@ /* ================================================================================================= (c - GPLv3) T.W.J. de Geus (Tom) | tom@geus.me | www.geus.me | github.com/tdegeus/GooseFEM ================================================================================================= */ -#ifndef XGOOSEFEM_ELEMENT_H -#define XGOOSEFEM_ELEMENT_H +#ifndef GOOSEFEM_ELEMENT_H +#define GOOSEFEM_ELEMENT_H // ------------------------------------------------------------------------------------------------- #include "GooseFEM.h" // ======================================= GooseFEM::Element ======================================= -namespace xGooseFEM { +namespace GooseFEM { namespace Element { // ------------------------------------------------------------------------------------------------- // convert nodal vector [nnode, ndim] to nodal vector stored per element [nelem, nne, ndim] inline xt::xtensor asElementVector( const xt::xtensor &conn, const xt::xtensor &nodevec); // assemble nodal vector stored per element [nelem, nne, ndim] to nodal vector [nnode, ndim] inline xt::xtensor assembleNodeVector( const xt::xtensor &conn, const xt::xtensor &elemvec); // check DOFs to leave no holes template inline bool isSequential(const E &dofs); // check structure of the matrices stored per element [nelem, nne*ndim, nne*ndim] bool isDiagonal(const xt::xtensor &elemmat); // ------------------------------------------------------------------------------------------------- }} // namespace ... // ================================================================================================= #endif diff --git a/include/xGooseFEM/Element.hpp b/include/GooseFEM/Element.hpp similarity index 97% rename from include/xGooseFEM/Element.hpp rename to include/GooseFEM/Element.hpp index fb40a61..9cd8a32 100644 --- a/include/xGooseFEM/Element.hpp +++ b/include/GooseFEM/Element.hpp @@ -1,125 +1,125 @@ /* ================================================================================================= (c - GPLv3) T.W.J. de Geus (Tom) | tom@geus.me | www.geus.me | github.com/tdegeus/GooseFEM ================================================================================================= */ -#ifndef XGOOSEFEM_ELEMENT_CPP -#define XGOOSEFEM_ELEMENT_CPP +#ifndef GOOSEFEM_ELEMENT_CPP +#define GOOSEFEM_ELEMENT_CPP // ------------------------------------------------------------------------------------------------- #include "Element.h" // ======================================= GooseFEM::Element ======================================= -namespace xGooseFEM { +namespace GooseFEM { namespace Element { // ------------------------------------------------------------------------------------------------- inline xt::xtensor asElementVector( const xt::xtensor &conn, const xt::xtensor &nodevec) { // extract dimensions size_t nelem = conn .shape()[0]; // number of elements size_t nne = conn .shape()[1]; // number of nodes per element size_t ndim = nodevec.shape()[1]; // number of dimensions // allocate output: nodal vectors stored per element xt::xtensor elemvec = xt::empty({nelem, nne, ndim}); // read from nodal vectors #pragma omp parallel for for ( size_t e = 0 ; e < nelem ; ++e ) for ( size_t m = 0 ; m < nne ; ++m ) for ( size_t i = 0 ; i < ndim ; ++i ) elemvec(e,m,i) = nodevec(conn(e,m),i); return elemvec; } // ------------------------------------------------------------------------------------------------- inline xt::xtensor assembleNodeVector( const xt::xtensor &conn, const xt::xtensor &elemvec) { // extract dimensions size_t nelem = conn.shape()[0]; // number of elements size_t nne = conn.shape()[1]; // number of nodes per element size_t ndim = elemvec.shape()[2]; // number of dimensions size_t nnode = xt::amax(conn)[0]+1; // number of nodes // check input assert( elemvec.shape()[0] == nelem ); assert( elemvec.shape()[1] == nne ); // zero-initialize output: nodal vectors xt::xtensor nodevec = xt::zeros({nnode, ndim}); // assemble from nodal vectors stored per element for ( size_t e = 0 ; e < nelem ; ++e ) for ( size_t m = 0 ; m < nne ; ++m ) for ( size_t i = 0 ; i < ndim ; ++i ) nodevec(conn(e,m),i) += elemvec(e,m,i); return nodevec; } // ------------------------------------------------------------------------------------------------- template inline bool isSequential(const E &dofs) { // number of DOFs size_t ndof = xt::amax(dofs)[0] + 1; // list to check if all DOFs are present // - allocate xt::xtensor exists = xt::zeros({ndof}); // - fill for ( auto &i : dofs ) exists[i]++; // check for ( auto &i : dofs ) if ( exists[i] == 0 ) return false; // checks passed successfully return true; } // ------------------------------------------------------------------------------------------------- inline bool isDiagonal(const xt::xtensor &elemmat) { // check input assert( elemmat.shape()[1] == elemmat.shape()[2] ); // get dimensions size_t nelem = elemmat.shape()[0]; size_t N = elemmat.shape()[1]; // get numerical precision double eps = std::numeric_limits::epsilon(); // loop over all entries #pragma omp parallel for for ( size_t e = 0 ; e < nelem ; ++e ) for ( size_t i = 0 ; i < N ; ++i ) for ( size_t j = 0 ; j < N ; ++j ) if ( i != j ) if ( std::abs(elemmat(e,i,j)) > eps ) return false; // all checks passed successful return true; } // ------------------------------------------------------------------------------------------------- }} // namespace ... // ================================================================================================= #endif diff --git a/include/xGooseFEM/ElementHex8.h b/include/GooseFEM/ElementHex8.h similarity index 98% rename from include/xGooseFEM/ElementHex8.h rename to include/GooseFEM/ElementHex8.h index f65efbe..dd29c76 100644 --- a/include/xGooseFEM/ElementHex8.h +++ b/include/GooseFEM/ElementHex8.h @@ -1,161 +1,161 @@ /* ================================================================================================= (c - GPLv3) T.W.J. de Geus (Tom) | tom@geus.me | www.geus.me | github.com/tdegeus/GooseFEM ================================================================================================= */ -#ifndef XGOOSEFEM_ELEMENTHEX8_H -#define XGOOSEFEM_ELEMENTHEX8_H +#ifndef GOOSEFEM_ELEMENTHEX8_H +#define GOOSEFEM_ELEMENTHEX8_H // ------------------------------------------------------------------------------------------------- #include "GooseFEM.h" // ================================================================================================= -namespace xGooseFEM { +namespace GooseFEM { namespace Element { namespace Hex8 { // ================================================================================================= using T2 = xt::xtensor_fixed>; inline double inv(const T2 &A, T2 &Ainv); // ================================================================================================= namespace Gauss { inline size_t nip(); // number of integration points inline xt::xtensor xi(); // integration point coordinates (local coordinates) inline xt::xtensor w(); // integration point weights } // ================================================================================================= namespace Nodal { inline size_t nip(); // number of integration points inline xt::xtensor xi(); // integration point coordinates (local coordinates) inline xt::xtensor w(); // integration point weights } // ================================================================================================= // ------------------------------------------ quadrature ------------------------------------------- class Quadrature { public: // fixed dimensions: // ndim = 3 - number of dimensions // nne = 8 - number of nodes per element // // naming convention: // "elemmat" - matrices stored per element - [nelem, nne*ndim, nne*ndim] // "elemvec" - nodal vectors stored per element - [nelem, nne, ndim] // "qtensor" - integration point tensor - [nelem, nip, ndim, ndim] // "qscalar" - integration point scalar - [nelem, nip] // constructor: integration point coordinates and weights are optional (default: Gauss) Quadrature() = default; Quadrature(const xt::xtensor &x) : Quadrature(x, Gauss::xi(), Gauss::w()){}; Quadrature(const xt::xtensor &x, const xt::xtensor &xi, const xt::xtensor &w); // update the nodal positions (shape of "x" should match the earlier definition) void update_x(const xt::xtensor &x); // return dimensions size_t nelem() const { return m_nelem; }; // number of elements size_t nne() const { return m_nne; }; // number of nodes per element size_t ndim() const { return m_ndim; }; // number of dimension size_t nip() const { return m_nip; }; // number of integration points // return integration volume void dV(xt::xtensor &qscalar) const; void dV(xt::xtensor &qtensor) const; // same volume for all tensor components // dyadic product "qtensor(i,j) += dNdx(m,i) * elemvec(m,j)", its transpose and its symmetric part void gradN_vector(const xt::xtensor &elemvec, xt::xtensor &qtensor) const; void gradN_vector_T(const xt::xtensor &elemvec, xt::xtensor &qtensor) const; void symGradN_vector(const xt::xtensor &elemvec, xt::xtensor &qtensor) const; // integral of the scalar product "elemmat(m*ndim+i,n*ndim+i) += N(m) * qscalar * N(n) * dV" void int_N_scalar_NT_dV(const xt::xtensor &qscalar, xt::xtensor &elemmat) const; // integral of the dot product "elemvec(m,j) += dNdx(m,i) * qtensor(i,j) * dV" void int_gradN_dot_tensor2_dV(const xt::xtensor &qtensor, xt::xtensor &elemvec) const; // integral of the dot product "elemmat(m*2+j, n*2+k) += dNdx(m,i) * qtensor(i,j,k,l) * dNdx(n,l) * dV" void int_gradN_dot_tensor4_dot_gradNT_dV(const xt::xtensor &qtensor, xt::xtensor &elemmat) const; // auto allocation of the functions above xt::xtensor dV() const; xt::xtensor dVtensor() const; xt::xtensor gradN_vector(const xt::xtensor &elemvec) const; xt::xtensor gradN_vector_T(const xt::xtensor &elemvec) const; xt::xtensor symGradN_vector(const xt::xtensor &elemvec) const; xt::xtensor int_N_scalar_NT_dV(const xt::xtensor &qscalar) const; xt::xtensor int_gradN_dot_tensor2_dV(const xt::xtensor &qtensor) const; xt::xtensor int_gradN_dot_tensor4_dot_gradNT_dV(const xt::xtensor &qtensor) const; private: // compute "vol" and "dNdx" based on current "x" void compute_dN(); private: // dimensions (flexible) size_t m_nelem; // number of elements size_t m_nip; // number of integration points // dimensions (fixed for this element type) static const size_t m_nne=8; // number of nodes per element static const size_t m_ndim=3; // number of dimensions // data arrays xt::xtensor m_x; // nodal positions stored per element [nelem, nne, ndim] xt::xtensor m_w; // weight of each integration point [nip] xt::xtensor m_xi; // local coordinate of each integration point [nip, ndim] xt::xtensor m_N; // shape functions [nip, nne] xt::xtensor m_dNxi; // shape function gradients w.r.t. local coordinate [nip, nne, ndim] xt::xtensor m_dNx; // shape function gradients w.r.t. global coordinate [nelem, nip, nne, ndim] xt::xtensor m_vol; // integration point volume [nelem, nip] }; // ------------------------------------------------------------------------------------------------- }}} // namespace ... // ================================================================================================= #endif diff --git a/include/xGooseFEM/ElementHex8.hpp b/include/GooseFEM/ElementHex8.hpp similarity index 99% rename from include/xGooseFEM/ElementHex8.hpp rename to include/GooseFEM/ElementHex8.hpp index f3b4e2a..e549fc0 100644 --- a/include/xGooseFEM/ElementHex8.hpp +++ b/include/GooseFEM/ElementHex8.hpp @@ -1,676 +1,676 @@ /* ================================================================================================= (c - GPLv3) T.W.J. de Geus (Tom) | tom@geus.me | www.geus.me | github.com/tdegeus/GooseFEM ================================================================================================= */ -#ifndef XGOOSEFEM_ELEMENTHEX8_CPP -#define XGOOSEFEM_ELEMENTHEX8_CPP +#ifndef GOOSEFEM_ELEMENTHEX8_CPP +#define GOOSEFEM_ELEMENTHEX8_CPP // ------------------------------------------------------------------------------------------------- #include "ElementHex8.h" // ================================================================================================= -namespace xGooseFEM { +namespace GooseFEM { namespace Element { namespace Hex8 { // ================================================================================================= inline double inv(const T2 &A, T2 &Ainv) { // compute determinant double det = ( A(0,0) * A(1,1) * A(2,2) + A(0,1) * A(1,2) * A(2,0) + A(0,2) * A(1,0) * A(2,1) ) - ( A(0,2) * A(1,1) * A(2,0) + A(0,1) * A(1,0) * A(2,2) + A(0,0) * A(1,2) * A(2,1) ); // compute inverse Ainv(0,0) = (A(1,1)*A(2,2)-A(1,2)*A(2,1)) / det; Ainv(0,1) = (A(0,2)*A(2,1)-A(0,1)*A(2,2)) / det; Ainv(0,2) = (A(0,1)*A(1,2)-A(0,2)*A(1,1)) / det; Ainv(1,0) = (A(1,2)*A(2,0)-A(1,0)*A(2,2)) / det; Ainv(1,1) = (A(0,0)*A(2,2)-A(0,2)*A(2,0)) / det; Ainv(1,2) = (A(0,2)*A(1,0)-A(0,0)*A(1,2)) / det; Ainv(2,0) = (A(1,0)*A(2,1)-A(1,1)*A(2,0)) / det; Ainv(2,1) = (A(0,1)*A(2,0)-A(0,0)*A(2,1)) / det; Ainv(2,2) = (A(0,0)*A(1,1)-A(0,1)*A(1,0)) / det; return det; } // ================================================================================================= namespace Gauss { // ------------------------------------------------------------------------------------------------- inline size_t nip() { return 8; } // ------------------------------------------------------------------------------------------------- inline xt::xtensor xi() { size_t nip = 8; size_t ndim = 3; xt::xtensor xi = xt::empty({nip,ndim}); xi(0,0) = -1./std::sqrt(3.); xi(0,1) = -1./std::sqrt(3.); xi(0,2) = -1./std::sqrt(3.); xi(1,0) = +1./std::sqrt(3.); xi(1,1) = -1./std::sqrt(3.); xi(1,2) = -1./std::sqrt(3.); xi(2,0) = +1./std::sqrt(3.); xi(2,1) = +1./std::sqrt(3.); xi(2,2) = -1./std::sqrt(3.); xi(3,0) = -1./std::sqrt(3.); xi(3,1) = +1./std::sqrt(3.); xi(3,2) = -1./std::sqrt(3.); xi(4,0) = -1./std::sqrt(3.); xi(4,1) = -1./std::sqrt(3.); xi(4,2) = +1./std::sqrt(3.); xi(5,0) = +1./std::sqrt(3.); xi(5,1) = -1./std::sqrt(3.); xi(5,2) = +1./std::sqrt(3.); xi(6,0) = +1./std::sqrt(3.); xi(6,1) = +1./std::sqrt(3.); xi(6,2) = +1./std::sqrt(3.); xi(7,0) = -1./std::sqrt(3.); xi(7,1) = +1./std::sqrt(3.); xi(7,2) = +1./std::sqrt(3.); return xi; } // ------------------------------------------------------------------------------------------------- inline xt::xtensor w() { size_t nip = 8; xt::xtensor w = xt::empty({nip}); w(0) = 1.; w(1) = 1.; w(2) = 1.; w(3) = 1.; w(4) = 1.; w(5) = 1.; w(6) = 1.; w(7) = 1.; return w; } // ------------------------------------------------------------------------------------------------- } // ================================================================================================= namespace Nodal { // ------------------------------------------------------------------------------------------------- inline size_t nip() { return 8; } // ------------------------------------------------------------------------------------------------- inline xt::xtensor xi() { size_t nip = 8; size_t ndim = 3; xt::xtensor xi = xt::empty({nip,ndim}); xi(0,0) = -1.; xi(0,1) = -1.; xi(0,2) = -1.; xi(1,0) = +1.; xi(1,1) = -1.; xi(1,2) = -1.; xi(2,0) = +1.; xi(2,1) = +1.; xi(2,2) = -1.; xi(3,0) = -1.; xi(3,1) = +1.; xi(3,2) = -1.; xi(4,0) = -1.; xi(4,1) = -1.; xi(4,2) = +1.; xi(5,0) = +1.; xi(5,1) = -1.; xi(5,2) = +1.; xi(6,0) = +1.; xi(6,1) = +1.; xi(6,2) = +1.; xi(7,0) = -1.; xi(7,1) = +1.; xi(7,2) = +1.; return xi; } // ------------------------------------------------------------------------------------------------- inline xt::xtensor w() { size_t nip = 8; xt::xtensor w = xt::empty({nip}); w(0) = 1.; w(1) = 1.; w(2) = 1.; w(3) = 1.; w(4) = 1.; w(5) = 1.; w(6) = 1.; w(7) = 1.; return w; } // ------------------------------------------------------------------------------------------------- } // ================================================================================================= inline Quadrature::Quadrature(const xt::xtensor &x, const xt::xtensor &xi, const xt::xtensor &w) : m_x(x), m_w(w), m_xi(xi) { // check input assert( m_x.shape()[1] == m_nne ); assert( m_x.shape()[2] == m_ndim ); // extract number of elements and number of integration points m_nelem = m_x.shape()[0]; m_nip = m_w.size(); // check input assert( m_xi.shape()[0] == m_nip ); assert( m_xi.shape()[1] == m_ndim ); assert( m_w .size() == m_nip ); // allocate arrays m_N = xt::empty({ m_nip, m_nne }); m_dNxi = xt::empty({ m_nip, m_nne, m_ndim}); m_dNx = xt::empty({m_nelem, m_nip, m_nne, m_ndim}); m_vol = xt::empty({m_nelem, m_nip }); // shape functions for ( size_t q = 0 ; q < m_nip ; ++q ) { m_N(q,0) = .125 * (1.-m_xi(q,0)) * (1.-m_xi(q,1)) * (1.-m_xi(q,2)); m_N(q,1) = .125 * (1.+m_xi(q,0)) * (1.-m_xi(q,1)) * (1.-m_xi(q,2)); m_N(q,2) = .125 * (1.+m_xi(q,0)) * (1.+m_xi(q,1)) * (1.-m_xi(q,2)); m_N(q,3) = .125 * (1.-m_xi(q,0)) * (1.+m_xi(q,1)) * (1.-m_xi(q,2)); m_N(q,4) = .125 * (1.-m_xi(q,0)) * (1.-m_xi(q,1)) * (1.+m_xi(q,2)); m_N(q,5) = .125 * (1.+m_xi(q,0)) * (1.-m_xi(q,1)) * (1.+m_xi(q,2)); m_N(q,6) = .125 * (1.+m_xi(q,0)) * (1.+m_xi(q,1)) * (1.+m_xi(q,2)); m_N(q,7) = .125 * (1.-m_xi(q,0)) * (1.+m_xi(q,1)) * (1.+m_xi(q,2)); } // shape function gradients in local coordinates for ( size_t q = 0 ; q < m_nip ; ++q ) { // - dN / dxi_0 m_dNxi(q,0,0) = -.125*(1.-m_xi(q,1))*(1.-m_xi(q,2)); m_dNxi(q,1,0) = +.125*(1.-m_xi(q,1))*(1.-m_xi(q,2)); m_dNxi(q,2,0) = +.125*(1.+m_xi(q,1))*(1.-m_xi(q,2)); m_dNxi(q,3,0) = -.125*(1.+m_xi(q,1))*(1.-m_xi(q,2)); m_dNxi(q,4,0) = -.125*(1.-m_xi(q,1))*(1.+m_xi(q,2)); m_dNxi(q,5,0) = +.125*(1.-m_xi(q,1))*(1.+m_xi(q,2)); m_dNxi(q,6,0) = +.125*(1.+m_xi(q,1))*(1.+m_xi(q,2)); m_dNxi(q,7,0) = -.125*(1.+m_xi(q,1))*(1.+m_xi(q,2)); // - dN / dxi_1 m_dNxi(q,0,1) = -.125*(1.-m_xi(q,0))*(1.-m_xi(q,2)); m_dNxi(q,1,1) = -.125*(1.+m_xi(q,0))*(1.-m_xi(q,2)); m_dNxi(q,2,1) = +.125*(1.+m_xi(q,0))*(1.-m_xi(q,2)); m_dNxi(q,3,1) = +.125*(1.-m_xi(q,0))*(1.-m_xi(q,2)); m_dNxi(q,4,1) = -.125*(1.-m_xi(q,0))*(1.+m_xi(q,2)); m_dNxi(q,5,1) = -.125*(1.+m_xi(q,0))*(1.+m_xi(q,2)); m_dNxi(q,6,1) = +.125*(1.+m_xi(q,0))*(1.+m_xi(q,2)); m_dNxi(q,7,1) = +.125*(1.-m_xi(q,0))*(1.+m_xi(q,2)); // - dN / dxi_2 m_dNxi(q,0,2) = -.125*(1.-m_xi(q,0))*(1.-m_xi(q,1)); m_dNxi(q,1,2) = -.125*(1.+m_xi(q,0))*(1.-m_xi(q,1)); m_dNxi(q,2,2) = -.125*(1.+m_xi(q,0))*(1.+m_xi(q,1)); m_dNxi(q,3,2) = -.125*(1.-m_xi(q,0))*(1.+m_xi(q,1)); m_dNxi(q,4,2) = +.125*(1.-m_xi(q,0))*(1.-m_xi(q,1)); m_dNxi(q,5,2) = +.125*(1.+m_xi(q,0))*(1.-m_xi(q,1)); m_dNxi(q,6,2) = +.125*(1.+m_xi(q,0))*(1.+m_xi(q,1)); m_dNxi(q,7,2) = +.125*(1.-m_xi(q,0))*(1.+m_xi(q,1)); } // compute the shape function gradients, based on "x" compute_dN(); } // ------------------------------------------------------------------------------------------------- inline void Quadrature::dV(xt::xtensor &qscalar) const { assert( qscalar.shape()[0] == m_nelem ); assert( qscalar.shape()[1] == m_nip ); #pragma omp parallel for for ( size_t e = 0 ; e < m_nelem ; ++e ) for ( size_t q = 0 ; q < m_nip ; ++q ) qscalar(e,q) = m_vol(e,q); } // ------------------------------------------------------------------------------------------------- inline void Quadrature::dV(xt::xtensor &qtensor) const { assert( qtensor.shape()[0] == m_nelem ); assert( qtensor.shape()[1] == m_nne ); assert( qtensor.shape()[2] == m_ndim ); assert( qtensor.shape()[3] == m_ndim ); #pragma omp parallel for for ( size_t e = 0 ; e < m_nelem ; ++e ) for ( size_t q = 0 ; q < m_nip ; ++q ) for ( size_t i = 0 ; i < m_ndim ; ++i ) for ( size_t j = 0 ; j < m_ndim ; ++j ) qtensor(e,q,i,j) = m_vol(e,q); } // ------------------------------------------------------------------------------------------------- inline void Quadrature::update_x(const xt::xtensor &x) { assert( x.shape()[0] == m_nelem ); assert( x.shape()[1] == m_nne ); assert( x.shape()[2] == m_ndim ); assert( x.size() == m_x.size() ); // update positions xt::noalias(m_x) = x; // update the shape function gradients for the new "x" compute_dN(); } // ------------------------------------------------------------------------------------------------- inline void Quadrature::compute_dN() { // loop over all elements (in parallel) #pragma omp parallel { // allocate local variables T2 J, Jinv; #pragma omp for for ( size_t e = 0 ; e < m_nelem ; ++e ) { // alias nodal positions auto x = xt::adapt(&m_x(e,0,0), xt::xshape()); // loop over integration points for ( size_t q = 0 ; q < m_nip ; ++q ) { // - alias auto dNxi = xt::adapt(&m_dNxi( q,0,0), xt::xshape()); auto dNx = xt::adapt(&m_dNx (e,q,0,0), xt::xshape()); // - zero-initialize J.fill(0.0); // - Jacobian for ( size_t m = 0 ; m < m_nne ; ++m ) for ( size_t i = 0 ; i < m_ndim ; ++i ) for ( size_t j = 0 ; j < m_ndim ; ++j ) J(i,j) += dNxi(m,i) * x(m,j); // - determinant and inverse of the Jacobian double Jdet = inv(J, Jinv); // - shape function gradients wrt global coordinates (loops partly unrolled for efficiency) // dNx(m,i) += Jinv(i,j) * dNxi(m,j); for ( size_t m = 0 ; m < m_nne ; ++m ) { dNx(m,0) = Jinv(0,0) * dNxi(m,0) + Jinv(0,1) * dNxi(m,1) + Jinv(0,2) * dNxi(m,2); dNx(m,1) = Jinv(1,0) * dNxi(m,0) + Jinv(1,1) * dNxi(m,1) + Jinv(1,2) * dNxi(m,2); dNx(m,2) = Jinv(2,0) * dNxi(m,0) + Jinv(2,1) * dNxi(m,1) + Jinv(2,2) * dNxi(m,2); } // - integration point volume m_vol(e,q) = m_w(q) * Jdet; } } } } // ------------------------------------------------------------------------------------------------- inline void Quadrature::gradN_vector( const xt::xtensor &elemvec, xt::xtensor &qtensor) const { assert( elemvec.shape()[0] == m_nelem ); assert( elemvec.shape()[1] == m_nne ); assert( elemvec.shape()[2] == m_ndim ); assert( qtensor.shape()[0] == m_nelem ); assert( qtensor.shape()[1] == m_nne ); assert( qtensor.shape()[2] == m_ndim ); assert( qtensor.shape()[3] == m_ndim ); // zero-initialize output: matrix of tensors qtensor.fill(0.0); // loop over all elements (in parallel) #pragma omp parallel for for ( size_t e = 0 ; e < m_nelem ; ++e ) { // alias element vector (e.g. nodal displacements) auto u = xt::adapt(&elemvec(e,0,0), xt::xshape()); // loop over all integration points in element "e" for ( size_t q = 0 ; q < m_nip ; ++q ) { // - alias auto dNx = xt::adapt(&m_dNx (e,q,0,0), xt::xshape()); auto gradu = xt::adapt(&qtensor(e,q,0,0), xt::xshape()); // - evaluate dyadic product for ( size_t m = 0 ; m < m_nne ; ++m ) for ( size_t i = 0 ; i < m_ndim ; ++i ) for ( size_t j = 0 ; j < m_ndim ; ++j ) gradu(i,j) += dNx(m,i) * u(m,j); } } } // ------------------------------------------------------------------------------------------------- inline void Quadrature::gradN_vector_T( const xt::xtensor &elemvec, xt::xtensor &qtensor) const { assert( elemvec.shape()[0] == m_nelem ); assert( elemvec.shape()[1] == m_nne ); assert( elemvec.shape()[2] == m_ndim ); assert( qtensor.shape()[0] == m_nelem ); assert( qtensor.shape()[1] == m_nne ); assert( qtensor.shape()[2] == m_ndim ); assert( qtensor.shape()[3] == m_ndim ); // zero-initialize output: matrix of tensors qtensor.fill(0.0); // loop over all elements (in parallel) #pragma omp parallel for for ( size_t e = 0 ; e < m_nelem ; ++e ) { // alias element vector (e.g. nodal displacements) auto u = xt::adapt(&elemvec(e,0,0), xt::xshape()); // loop over all integration points in element "e" for ( size_t q = 0 ; q < m_nip ; ++q ) { // - alias auto dNx = xt::adapt(&m_dNx (e,q,0,0), xt::xshape()); auto gradu = xt::adapt(&qtensor(e,q,0,0), xt::xshape()); // - evaluate transpose of dyadic product for ( size_t m = 0 ; m < m_nne ; ++m ) for ( size_t i = 0 ; i < m_ndim ; ++i ) for ( size_t j = 0 ; j < m_ndim ; ++j ) gradu(j,i) += dNx(m,i) * u(m,j); } } } // ------------------------------------------------------------------------------------------------- inline void Quadrature::symGradN_vector( const xt::xtensor &elemvec, xt::xtensor &qtensor) const { assert( elemvec.shape()[0] == m_nelem ); assert( elemvec.shape()[1] == m_nne ); assert( elemvec.shape()[2] == m_ndim ); assert( qtensor.shape()[0] == m_nelem ); assert( qtensor.shape()[1] == m_nne ); assert( qtensor.shape()[2] == m_ndim ); assert( qtensor.shape()[3] == m_ndim ); // zero-initialize output: matrix of tensors qtensor.fill(0.0); // loop over all elements (in parallel) #pragma omp parallel for for ( size_t e = 0 ; e < m_nelem ; ++e ) { // alias element vector (e.g. nodal displacements) auto u = xt::adapt(&elemvec(e,0,0), xt::xshape()); // loop over all integration points in element "e" for ( size_t q = 0 ; q < m_nip ; ++q ) { // - alias auto dNx = xt::adapt(&m_dNx (e,q,0,0), xt::xshape()); auto eps = xt::adapt(&qtensor(e,q,0,0), xt::xshape()); // - evaluate symmetrized dyadic product for ( size_t m = 0 ; m < m_nne ; ++m ) { for ( size_t i = 0 ; i < m_ndim ; ++i ) { for ( size_t j = 0 ; j < m_ndim ; ++j ) { eps(i,j) += dNx(m,i) * u(m,j) / 2.; eps(j,i) += dNx(m,i) * u(m,j) / 2.; } } } } } } // ------------------------------------------------------------------------------------------------- inline void Quadrature::int_N_scalar_NT_dV( const xt::xtensor &qscalar, xt::xtensor &elemmat) const { assert( qscalar.shape()[0] == m_nelem ); assert( qscalar.shape()[1] == m_nip ); assert( elemmat.shape()[0] == m_nelem ); assert( elemmat.shape()[1] == m_nne*m_ndim ); assert( elemmat.shape()[2] == m_nne*m_ndim ); // zero-initialize: matrix of matrices elemmat.fill(0.0); // loop over all elements (in parallel) #pragma omp parallel for for ( size_t e = 0 ; e < m_nelem ; ++e ) { // alias (e.g. mass matrix) auto M = xt::adapt(&elemmat(e,0,0), xt::xshape()); // loop over all integration points in element "e" for ( size_t q = 0 ; q < m_nip ; ++q ) { // - alias auto N = xt::adapt(&m_N(q,0), xt::xshape()); auto& vol = m_vol (e,q); auto& rho = qscalar(e,q); // - evaluate scalar product, for all dimensions, and assemble // M(m*ndim+i,n*ndim+i) += N(m) * scalar * N(n) * dV for ( size_t m = 0 ; m < m_nne ; ++m ) { for ( size_t n = 0 ; n < m_nne ; ++n ) { M(m*m_ndim+0, n*m_ndim+0) += N(m) * rho * N(n) * vol; M(m*m_ndim+1, n*m_ndim+1) += N(m) * rho * N(n) * vol; M(m*m_ndim+2, n*m_ndim+2) += N(m) * rho * N(n) * vol; } } } } } // ------------------------------------------------------------------------------------------------- inline void Quadrature::int_gradN_dot_tensor2_dV(const xt::xtensor &qtensor, xt::xtensor &elemvec) const { assert( qtensor.shape()[0] == m_nelem ); assert( qtensor.shape()[1] == m_nip ); assert( qtensor.shape()[2] == m_ndim ); assert( qtensor.shape()[3] == m_ndim ); assert( elemvec.shape()[0] == m_nelem ); assert( elemvec.shape()[1] == m_nne ); assert( elemvec.shape()[2] == m_ndim ); // zero-initialize output: matrix of vectors elemvec.fill(0.0); // loop over all elements (in parallel) #pragma omp parallel for for ( size_t e = 0 ; e < m_nelem ; ++e ) { // alias (e.g. nodal force) auto f = xt::adapt(&elemvec(e,0,0), xt::xshape()); // loop over all integration points in element "e" for ( size_t q = 0 ; q < m_nip ; ++q ) { // - alias auto dNx = xt::adapt(&m_dNx (e,q,0,0), xt::xshape()); auto sig = xt::adapt(&qtensor(e,q,0,0), xt::xshape()); auto& vol = m_vol(e,q); // - evaluate dot product, and assemble for ( size_t m = 0 ; m < m_nne ; ++m ) { f(m,0) += ( dNx(m,0) * sig(0,0) + dNx(m,1) * sig(1,0) + dNx(m,2) * sig(2,0) ) * vol; f(m,1) += ( dNx(m,0) * sig(0,1) + dNx(m,1) * sig(1,1) + dNx(m,2) * sig(2,1) ) * vol; f(m,2) += ( dNx(m,0) * sig(0,2) + dNx(m,1) * sig(1,2) + dNx(m,2) * sig(2,2) ) * vol; } } } } // ------------------------------------------------------------------------------------------------- inline void Quadrature::int_gradN_dot_tensor4_dot_gradNT_dV(const xt::xtensor &qtensor, xt::xtensor &elemmat) const { assert( qtensor.shape()[0] == m_nelem ); assert( qtensor.shape()[1] == m_nip ); assert( qtensor.shape()[2] == m_ndim ); assert( qtensor.shape()[3] == m_ndim ); assert( qtensor.shape()[4] == m_ndim ); assert( qtensor.shape()[5] == m_ndim ); assert( elemmat.shape()[0] == m_nelem ); assert( elemmat.shape()[1] == m_nne*m_ndim ); assert( elemmat.shape()[2] == m_nne*m_ndim ); // zero-initialize output: matrix of vector elemmat.fill(0.0); // loop over all elements (in parallel) #pragma omp parallel for for ( size_t e = 0 ; e < m_nelem ; ++e ) { // alias (e.g. nodal force) auto K = xt::adapt(&elemmat(e,0,0), xt::xshape()); // loop over all integration points in element "e" for ( size_t q = 0 ; q < m_nip ; ++q ){ // - alias auto dNx = xt::adapt(&m_dNx(e,q,0,0), xt::xshape()); auto C = xt::adapt(&qtensor(e,q,0,0,0,0), xt::xshape()); auto& vol = m_vol(e,q); // - evaluate dot product, and assemble for ( size_t m = 0 ; m < m_nne ; ++m ) for ( size_t n = 0 ; n < m_nne ; ++n ) for ( size_t i = 0 ; i < m_ndim ; ++i ) for ( size_t j = 0 ; j < m_ndim ; ++j ) for ( size_t k = 0 ; k < m_ndim ; ++k ) for ( size_t l = 0 ; l < m_ndim ; ++l ) K(m*m_ndim+j, n*m_ndim+k) += dNx(m,i) * C(i,j,k,l) * dNx(n,l) * vol; } } } // ------------------------------------------------------------------------------------------------- inline xt::xtensor Quadrature::dV() const { xt::xtensor out = xt::empty({m_nelem, m_nip}); this->dV(out); return out; } // ------------------------------------------------------------------------------------------------- inline xt::xtensor Quadrature::dVtensor() const { xt::xtensor out = xt::empty({m_nelem, m_nip, m_ndim, m_ndim}); this->dV(out); return out; } // ------------------------------------------------------------------------------------------------- inline xt::xtensor Quadrature::gradN_vector(const xt::xtensor &elemvec) const { xt::xtensor qtensor = xt::empty({m_nelem, m_nip, m_ndim, m_ndim}); this->gradN_vector(elemvec, qtensor); return qtensor; } // ------------------------------------------------------------------------------------------------- inline xt::xtensor Quadrature::gradN_vector_T(const xt::xtensor &elemvec) const { xt::xtensor qtensor = xt::empty({m_nelem, m_nip, m_ndim, m_ndim}); this->gradN_vector_T(elemvec, qtensor); return qtensor; } // ------------------------------------------------------------------------------------------------- inline xt::xtensor Quadrature::symGradN_vector(const xt::xtensor &elemvec) const { xt::xtensor qtensor = xt::empty({m_nelem, m_nip, m_ndim, m_ndim}); this->symGradN_vector(elemvec, qtensor); return qtensor; } // ------------------------------------------------------------------------------------------------- inline xt::xtensor Quadrature::int_N_scalar_NT_dV( const xt::xtensor &qscalar) const { xt::xtensor elemmat = xt::empty({m_nelem, m_nne*m_ndim, m_nne*m_ndim}); this->int_N_scalar_NT_dV(qscalar, elemmat); return elemmat; } // ------------------------------------------------------------------------------------------------- inline xt::xtensor Quadrature::int_gradN_dot_tensor2_dV( const xt::xtensor &qtensor) const { xt::xtensor elemvec = xt::empty({m_nelem, m_nne, m_ndim}); this->int_gradN_dot_tensor2_dV(qtensor, elemvec); return elemvec; } // ------------------------------------------------------------------------------------------------- inline xt::xtensor Quadrature::int_gradN_dot_tensor4_dot_gradNT_dV( const xt::xtensor &qtensor) const { xt::xtensor elemmat = xt::empty({m_nelem, m_ndim*m_nne, m_ndim*m_nne}); this->int_gradN_dot_tensor4_dot_gradNT_dV(qtensor, elemmat); return elemmat; } // ------------------------------------------------------------------------------------------------- }}} // namespace ... // ================================================================================================= #endif diff --git a/include/xGooseFEM/ElementQuad4.h b/include/GooseFEM/ElementQuad4.h similarity index 98% rename from include/xGooseFEM/ElementQuad4.h rename to include/GooseFEM/ElementQuad4.h index 79ad9ad..641f89f 100644 --- a/include/xGooseFEM/ElementQuad4.h +++ b/include/GooseFEM/ElementQuad4.h @@ -1,161 +1,161 @@ /* ================================================================================================= (c - GPLv3) T.W.J. de Geus (Tom) | tom@geus.me | www.geus.me | github.com/tdegeus/GooseFEM ================================================================================================= */ -#ifndef XGOOSEFEM_ELEMENTQUAD4_H -#define XGOOSEFEM_ELEMENTQUAD4_H +#ifndef GOOSEFEM_ELEMENTQUAD4_H +#define GOOSEFEM_ELEMENTQUAD4_H // ------------------------------------------------------------------------------------------------- #include "GooseFEM.h" // ================================================================================================= -namespace xGooseFEM { +namespace GooseFEM { namespace Element { namespace Quad4 { // ================================================================================================= using T2 = xt::xtensor_fixed>; inline double inv(const T2 &A, T2 &Ainv); // ================================================================================================= namespace Gauss { inline size_t nip(); // number of integration points inline xt::xtensor xi(); // integration point coordinates (local coordinates) inline xt::xtensor w(); // integration point weights } // ================================================================================================= namespace Nodal { inline size_t nip(); // number of integration points inline xt::xtensor xi(); // integration point coordinates (local coordinates) inline xt::xtensor w(); // integration point weights } // ================================================================================================= // ------------------------------------------------------------------------------------------------- class Quadrature { public: // fixed dimensions: // ndim = 2 - number of dimensions // nne = 4 - number of nodes per element // // naming convention: // "elemmat" - matrices stored per element - [nelem, nne*ndim, nne*ndim] // "elemvec" - nodal vectors stored per element - [nelem, nne, ndim] // "qtensor" - integration point tensor - [nelem, nip, ndim, ndim] // "qscalar" - integration point scalar - [nelem, nip] // constructor: integration point coordinates and weights are optional (default: Gauss) Quadrature() = default; Quadrature(const xt::xtensor &x) : Quadrature(x, Gauss::xi(), Gauss::w()){}; Quadrature(const xt::xtensor &x, const xt::xtensor &xi, const xt::xtensor &w); // update the nodal positions (shape of "x" should match the earlier definition) void update_x(const xt::xtensor &x); // return dimensions size_t nelem() const { return m_nelem; }; // number of elements size_t nne() const { return m_nne; }; // number of nodes per element size_t ndim() const { return m_ndim; }; // number of dimension size_t nip() const { return m_nip; }; // number of integration points // return integration volume void dV(xt::xtensor &qscalar) const; void dV(xt::xtensor &qtensor) const; // same volume for all tensor components // dyadic product "qtensor(i,j) += dNdx(m,i) * elemvec(m,j)", its transpose and its symmetric part void gradN_vector(const xt::xtensor &elemvec, xt::xtensor &qtensor) const; void gradN_vector_T(const xt::xtensor &elemvec, xt::xtensor &qtensor) const; void symGradN_vector(const xt::xtensor &elemvec, xt::xtensor &qtensor) const; // integral of the scalar product "elemmat(m*ndim+i,n*ndim+i) += N(m) * qscalar * N(n) * dV" void int_N_scalar_NT_dV(const xt::xtensor &qscalar, xt::xtensor &elemmat) const; // integral of the dot product "elemvec(m,j) += dNdx(m,i) * qtensor(i,j) * dV" void int_gradN_dot_tensor2_dV(const xt::xtensor &qtensor, xt::xtensor &elemvec) const; // integral of the dot product "elemmat(m*2+j, n*2+k) += dNdx(m,i) * qtensor(i,j,k,l) * dNdx(n,l) * dV" void int_gradN_dot_tensor4_dot_gradNT_dV(const xt::xtensor &qtensor, xt::xtensor &elemmat) const; // auto allocation of the functions above xt::xtensor dV() const; xt::xtensor dVtensor() const; xt::xtensor gradN_vector(const xt::xtensor &elemvec) const; xt::xtensor gradN_vector_T(const xt::xtensor &elemvec) const; xt::xtensor symGradN_vector(const xt::xtensor &elemvec) const; xt::xtensor int_N_scalar_NT_dV(const xt::xtensor &qscalar) const; xt::xtensor int_gradN_dot_tensor2_dV(const xt::xtensor &qtensor) const; xt::xtensor int_gradN_dot_tensor4_dot_gradNT_dV(const xt::xtensor &qtensor) const; private: // compute "vol" and "dNdx" based on current "x" void compute_dN(); private: // dimensions (flexible) size_t m_nelem; // number of elements size_t m_nip; // number of integration points // dimensions (fixed for this element type) static const size_t m_nne=4; // number of nodes per element static const size_t m_ndim=2; // number of dimensions // data arrays xt::xtensor m_x; // nodal positions stored per element [nelem, nne, ndim] xt::xtensor m_w; // weight of each integration point [nip] xt::xtensor m_xi; // local coordinate of each integration point [nip, ndim] xt::xtensor m_N; // shape functions [nip, nne] xt::xtensor m_dNxi; // shape function gradients w.r.t. local coordinate [nip, nne, ndim] xt::xtensor m_dNx; // shape function gradients w.r.t. global coordinate [nelem, nip, nne, ndim] xt::xtensor m_vol; // integration point volume [nelem, nip] }; // ------------------------------------------------------------------------------------------------- }}} // namespace ... // ================================================================================================= #endif diff --git a/include/xGooseFEM/ElementQuad4.hpp b/include/GooseFEM/ElementQuad4.hpp similarity index 99% rename from include/xGooseFEM/ElementQuad4.hpp rename to include/GooseFEM/ElementQuad4.hpp index 2e8637a..af9b004 100644 --- a/include/xGooseFEM/ElementQuad4.hpp +++ b/include/GooseFEM/ElementQuad4.hpp @@ -1,625 +1,625 @@ /* ================================================================================================= (c - GPLv3) T.W.J. de Geus (Tom) | tom@geus.me | www.geus.me | github.com/tdegeus/GooseFEM ================================================================================================= */ -#ifndef XGOOSEFEM_ELEMENTQUAD4_CPP -#define XGOOSEFEM_ELEMENTQUAD4_CPP +#ifndef GOOSEFEM_ELEMENTQUAD4_CPP +#define GOOSEFEM_ELEMENTQUAD4_CPP // ------------------------------------------------------------------------------------------------- #include "ElementQuad4.h" // ================================================================================================= -namespace xGooseFEM { +namespace GooseFEM { namespace Element { namespace Quad4 { // ================================================================================================= inline double inv(const T2 &A, T2 &Ainv) { // compute determinant double det = A(0,0) * A(1,1) - A(0,1) * A(1,0); // compute inverse Ainv(0,0) = A(1,1) / det; Ainv(0,1) = -1. * A(0,1) / det; Ainv(1,0) = -1. * A(1,0) / det; Ainv(1,1) = A(0,0) / det; return det; } // ================================================================================================= namespace Gauss { // ------------------------------------------------------------------------------------------------- inline size_t nip() { return 4; } // ------------------------------------------------------------------------------------------------- inline xt::xtensor xi() { size_t nip = 4; size_t ndim = 2; xt::xtensor xi = xt::empty({nip,ndim}); xi(0,0) = -1./std::sqrt(3.); xi(0,1) = -1./std::sqrt(3.); xi(1,0) = +1./std::sqrt(3.); xi(1,1) = -1./std::sqrt(3.); xi(2,0) = +1./std::sqrt(3.); xi(2,1) = +1./std::sqrt(3.); xi(3,0) = -1./std::sqrt(3.); xi(3,1) = +1./std::sqrt(3.); return xi; } // ------------------------------------------------------------------------------------------------- inline xt::xtensor w() { size_t nip = 4; xt::xtensor w = xt::empty({nip}); w(0) = 1.; w(1) = 1.; w(2) = 1.; w(3) = 1.; return w; } // ------------------------------------------------------------------------------------------------- } // ================================================================================================= namespace Nodal { // ------------------------------------------------------------------------------------------------- inline size_t nip() { return 4; } // ------------------------------------------------------------------------------------------------- inline xt::xtensor xi() { size_t nip = 4; size_t ndim = 2; xt::xtensor xi = xt::empty({nip,ndim}); xi(0,0) = -1.; xi(0,1) = -1.; xi(1,0) = +1.; xi(1,1) = -1.; xi(2,0) = +1.; xi(2,1) = +1.; xi(3,0) = -1.; xi(3,1) = +1.; return xi; } // ------------------------------------------------------------------------------------------------- inline xt::xtensor w() { size_t nip = 4; xt::xtensor w = xt::empty({nip}); w(0) = 1.; w(1) = 1.; w(2) = 1.; w(3) = 1.; return w; } // ------------------------------------------------------------------------------------------------- } // ================================================================================================= inline Quadrature::Quadrature(const xt::xtensor &x, const xt::xtensor &xi, const xt::xtensor &w) : m_x(x), m_w(w), m_xi(xi) { // check input assert( m_x.shape()[1] == m_nne ); assert( m_x.shape()[2] == m_ndim ); // extract number of elements and number of integration points m_nelem = m_x.shape()[0]; m_nip = m_w.size(); // check input assert( m_xi.shape()[0] == m_nip ); assert( m_xi.shape()[1] == m_ndim ); assert( m_w .size() == m_nip ); // allocate arrays m_N = xt::empty({ m_nip, m_nne }); m_dNxi = xt::empty({ m_nip, m_nne, m_ndim}); m_dNx = xt::empty({m_nelem, m_nip, m_nne, m_ndim}); m_vol = xt::empty({m_nelem, m_nip }); // shape functions for ( size_t q = 0 ; q < m_nip ; ++q ) { m_N(q,0) = .25 * (1.-m_xi(q,0)) * (1.-m_xi(q,1)); m_N(q,1) = .25 * (1.+m_xi(q,0)) * (1.-m_xi(q,1)); m_N(q,2) = .25 * (1.+m_xi(q,0)) * (1.+m_xi(q,1)); m_N(q,3) = .25 * (1.-m_xi(q,0)) * (1.+m_xi(q,1)); } // shape function gradients in local coordinates for ( size_t q = 0 ; q < m_nip ; ++q ) { // - dN / dxi_0 m_dNxi(q,0,0) = -.25*(1.-m_xi(q,1)); m_dNxi(q,1,0) = +.25*(1.-m_xi(q,1)); m_dNxi(q,2,0) = +.25*(1.+m_xi(q,1)); m_dNxi(q,3,0) = -.25*(1.+m_xi(q,1)); // - dN / dxi_1 m_dNxi(q,0,1) = -.25*(1.-m_xi(q,0)); m_dNxi(q,1,1) = -.25*(1.+m_xi(q,0)); m_dNxi(q,2,1) = +.25*(1.+m_xi(q,0)); m_dNxi(q,3,1) = +.25*(1.-m_xi(q,0)); } // compute the shape function gradients, based on "x" compute_dN(); } // ------------------------------------------------------------------------------------------------- inline void Quadrature::dV(xt::xtensor &qscalar) const { assert( qscalar.shape()[0] == m_nelem ); assert( qscalar.shape()[1] == m_nip ); #pragma omp parallel for for ( size_t e = 0 ; e < m_nelem ; ++e ) for ( size_t q = 0 ; q < m_nip ; ++q ) qscalar(e,q) = m_vol(e,q); } // ------------------------------------------------------------------------------------------------- inline void Quadrature::dV(xt::xtensor &qtensor) const { assert( qtensor.shape()[0] == m_nelem ); assert( qtensor.shape()[1] == m_nne ); assert( qtensor.shape()[2] == m_ndim ); assert( qtensor.shape()[3] == m_ndim ); #pragma omp parallel for for ( size_t e = 0 ; e < m_nelem ; ++e ) for ( size_t q = 0 ; q < m_nip ; ++q ) for ( size_t i = 0 ; i < m_ndim ; ++i ) for ( size_t j = 0 ; j < m_ndim ; ++j ) qtensor(e,q,i,j) = m_vol(e,q); } // ------------------------------------------------------------------------------------------------- inline void Quadrature::update_x(const xt::xtensor &x) { assert( x.shape()[0] == m_nelem ); assert( x.shape()[1] == m_nne ); assert( x.shape()[2] == m_ndim ); assert( x.size() == m_x.size() ); // update positions xt::noalias(m_x) = x; // update the shape function gradients for the new "x" compute_dN(); } // ------------------------------------------------------------------------------------------------- inline void Quadrature::compute_dN() { // loop over all elements (in parallel) #pragma omp parallel { // allocate local variables T2 J, Jinv; #pragma omp for for ( size_t e = 0 ; e < m_nelem ; ++e ) { // alias nodal positions auto x = xt::adapt(&m_x(e,0,0), xt::xshape()); // loop over integration points for ( size_t q = 0 ; q < m_nip ; ++q ) { // - alias auto dNxi = xt::adapt(&m_dNxi( q,0,0), xt::xshape()); auto dNx = xt::adapt(&m_dNx (e,q,0,0), xt::xshape()); // - Jacobian (loops unrolled for efficiency) // J(i,j) += dNxi(m,i) * x(m,j); J(0,0) = dNxi(0,0)*x(0,0) + dNxi(1,0)*x(1,0) + dNxi(2,0)*x(2,0) + dNxi(3,0)*x(3,0); J(0,1) = dNxi(0,0)*x(0,1) + dNxi(1,0)*x(1,1) + dNxi(2,0)*x(2,1) + dNxi(3,0)*x(3,1); J(1,0) = dNxi(0,1)*x(0,0) + dNxi(1,1)*x(1,0) + dNxi(2,1)*x(2,0) + dNxi(3,1)*x(3,0); J(1,1) = dNxi(0,1)*x(0,1) + dNxi(1,1)*x(1,1) + dNxi(2,1)*x(2,1) + dNxi(3,1)*x(3,1); // - determinant and inverse of the Jacobian double Jdet = inv(J, Jinv); // - shape function gradients wrt global coordinates (loops partly unrolled for efficiency) // dNx(m,i) += Jinv(i,j) * dNxi(m,j); for ( size_t m = 0 ; m < m_nne ; ++m ) { dNx(m,0) = Jinv(0,0) * dNxi(m,0) + Jinv(0,1) * dNxi(m,1); dNx(m,1) = Jinv(1,0) * dNxi(m,0) + Jinv(1,1) * dNxi(m,1); } // - integration point volume m_vol(e,q) = m_w(q) * Jdet; } } } } // ------------------------------------------------------------------------------------------------- inline void Quadrature::gradN_vector( const xt::xtensor &elemvec, xt::xtensor &qtensor) const { assert( elemvec.shape()[0] == m_nelem ); assert( elemvec.shape()[1] == m_nne ); assert( elemvec.shape()[2] == m_ndim ); assert( qtensor.shape()[0] == m_nelem ); assert( qtensor.shape()[1] == m_nne ); assert( qtensor.shape()[2] == m_ndim ); assert( qtensor.shape()[3] == m_ndim ); // zero-initialize output: matrix of tensors qtensor.fill(0.0); // loop over all elements (in parallel) #pragma omp parallel for for ( size_t e = 0 ; e < m_nelem ; ++e ) { // alias element vector (e.g. nodal displacements) auto u = xt::adapt(&elemvec(e,0,0), xt::xshape()); // loop over all integration points in element "e" for ( size_t q = 0 ; q < m_nip ; ++q ) { // - alias auto dNx = xt::adapt(&m_dNx (e,q,0,0), xt::xshape()); auto gradu = xt::adapt(&qtensor(e,q,0,0), xt::xshape()); // - evaluate dyadic product (loops unrolled for efficiency) // gradu(i,j) += dNx(m,i) * u(m,j) gradu(0,0) = dNx(0,0)*u(0,0) + dNx(1,0)*u(1,0) + dNx(2,0)*u(2,0) + dNx(3,0)*u(3,0); gradu(0,1) = dNx(0,0)*u(0,1) + dNx(1,0)*u(1,1) + dNx(2,0)*u(2,1) + dNx(3,0)*u(3,1); gradu(1,0) = dNx(0,1)*u(0,0) + dNx(1,1)*u(1,0) + dNx(2,1)*u(2,0) + dNx(3,1)*u(3,0); gradu(1,1) = dNx(0,1)*u(0,1) + dNx(1,1)*u(1,1) + dNx(2,1)*u(2,1) + dNx(3,1)*u(3,1); } } } // ------------------------------------------------------------------------------------------------- inline void Quadrature::gradN_vector_T( const xt::xtensor &elemvec, xt::xtensor &qtensor) const { assert( elemvec.shape()[0] == m_nelem ); assert( elemvec.shape()[1] == m_nne ); assert( elemvec.shape()[2] == m_ndim ); assert( qtensor.shape()[0] == m_nelem ); assert( qtensor.shape()[1] == m_nne ); assert( qtensor.shape()[2] == m_ndim ); assert( qtensor.shape()[3] == m_ndim ); // zero-initialize output: matrix of tensors qtensor.fill(0.0); // loop over all elements (in parallel) #pragma omp parallel for for ( size_t e = 0 ; e < m_nelem ; ++e ) { // alias element vector (e.g. nodal displacements) auto u = xt::adapt(&elemvec(e,0,0), xt::xshape()); // loop over all integration points in element "e" for ( size_t q = 0 ; q < m_nip ; ++q ) { // - alias auto dNx = xt::adapt(&m_dNx (e,q,0,0), xt::xshape()); auto gradu = xt::adapt(&qtensor(e,q,0,0), xt::xshape()); // - evaluate transpose of dyadic product (loops unrolled for efficiency) // gradu(j,i) += dNx(m,i) * u(m,j) gradu(0,0) = dNx(0,0)*u(0,0) + dNx(1,0)*u(1,0) + dNx(2,0)*u(2,0) + dNx(3,0)*u(3,0); gradu(1,0) = dNx(0,0)*u(0,1) + dNx(1,0)*u(1,1) + dNx(2,0)*u(2,1) + dNx(3,0)*u(3,1); gradu(0,1) = dNx(0,1)*u(0,0) + dNx(1,1)*u(1,0) + dNx(2,1)*u(2,0) + dNx(3,1)*u(3,0); gradu(1,1) = dNx(0,1)*u(0,1) + dNx(1,1)*u(1,1) + dNx(2,1)*u(2,1) + dNx(3,1)*u(3,1); } } } // ------------------------------------------------------------------------------------------------- inline void Quadrature::symGradN_vector( const xt::xtensor &elemvec, xt::xtensor &qtensor) const { assert( elemvec.shape()[0] == m_nelem ); assert( elemvec.shape()[1] == m_nne ); assert( elemvec.shape()[2] == m_ndim ); assert( qtensor.shape()[0] == m_nelem ); assert( qtensor.shape()[1] == m_nne ); assert( qtensor.shape()[2] == m_ndim ); assert( qtensor.shape()[3] == m_ndim ); // zero-initialize output: matrix of tensors qtensor.fill(0.0); // loop over all elements (in parallel) #pragma omp parallel for for ( size_t e = 0 ; e < m_nelem ; ++e ) { // alias element vector (e.g. nodal displacements) auto u = xt::adapt(&elemvec(e,0,0), xt::xshape()); // loop over all integration points in element "e" for ( size_t q = 0 ; q < m_nip ; ++q ) { // - alias auto dNx = xt::adapt(&m_dNx (e,q,0,0), xt::xshape()); auto eps = xt::adapt(&qtensor(e,q,0,0), xt::xshape()); // - evaluate symmetrized dyadic product (loops unrolled for efficiency) // grad(i,j) += dNx(m,i) * u(m,j) // eps (j,i) = 0.5 * ( grad(i,j) + grad(j,i) ) eps(0,0) = dNx(0,0)*u(0,0) + dNx(1,0)*u(1,0) + dNx(2,0)*u(2,0) + dNx(3,0)*u(3,0); eps(1,1) = dNx(0,1)*u(0,1) + dNx(1,1)*u(1,1) + dNx(2,1)*u(2,1) + dNx(3,1)*u(3,1); eps(0,1) = ( dNx(0,0)*u(0,1) + dNx(1,0)*u(1,1) + dNx(2,0)*u(2,1) + dNx(3,0)*u(3,1) + dNx(0,1)*u(0,0) + dNx(1,1)*u(1,0) + dNx(2,1)*u(2,0) + dNx(3,1)*u(3,0) ) * 0.5; eps(1,0) = eps(0,1); } } } // ------------------------------------------------------------------------------------------------- inline void Quadrature::int_N_scalar_NT_dV( const xt::xtensor &qscalar, xt::xtensor &elemmat) const { assert( qscalar.shape()[0] == m_nelem ); assert( qscalar.shape()[1] == m_nip ); assert( elemmat.shape()[0] == m_nelem ); assert( elemmat.shape()[1] == m_nne*m_ndim ); assert( elemmat.shape()[2] == m_nne*m_ndim ); // zero-initialize: matrix of matrices elemmat.fill(0.0); // loop over all elements (in parallel) #pragma omp parallel for for ( size_t e = 0 ; e < m_nelem ; ++e ) { // alias (e.g. mass matrix) auto M = xt::adapt(&elemmat(e,0,0), xt::xshape()); // loop over all integration points in element "e" for ( size_t q = 0 ; q < m_nip ; ++q ) { // - alias auto N = xt::adapt(&m_N(q,0), xt::xshape()); auto& vol = m_vol (e,q); auto& rho = qscalar(e,q); // - evaluate scalar product, for all dimensions, and assemble // M(m*ndim+i,n*ndim+i) += N(m) * scalar * N(n) * dV for ( size_t m = 0 ; m < m_nne ; ++m ) { for ( size_t n = 0 ; n < m_nne ; ++n ) { M(m*m_ndim+0, n*m_ndim+0) += N(m) * rho * N(n) * vol; M(m*m_ndim+1, n*m_ndim+1) += N(m) * rho * N(n) * vol; } } } } } // ------------------------------------------------------------------------------------------------- inline void Quadrature::int_gradN_dot_tensor2_dV(const xt::xtensor &qtensor, xt::xtensor &elemvec) const { assert( qtensor.shape()[0] == m_nelem ); assert( qtensor.shape()[1] == m_nip ); assert( qtensor.shape()[2] == m_ndim ); assert( qtensor.shape()[3] == m_ndim ); assert( elemvec.shape()[0] == m_nelem ); assert( elemvec.shape()[1] == m_nne ); assert( elemvec.shape()[2] == m_ndim ); // zero-initialize output: matrix of vectors elemvec.fill(0.0); // loop over all elements (in parallel) #pragma omp parallel for for ( size_t e = 0 ; e < m_nelem ; ++e ) { // alias (e.g. nodal force) auto f = xt::adapt(&elemvec(e,0,0), xt::xshape()); // loop over all integration points in element "e" for ( size_t q = 0 ; q < m_nip ; ++q ) { // - alias auto dNx = xt::adapt(&m_dNx (e,q,0,0), xt::xshape()); auto sig = xt::adapt(&qtensor(e,q,0,0), xt::xshape()); auto& vol = m_vol(e,q); // - evaluate dot product, and assemble for ( size_t m = 0 ; m < m_nne ; ++m ) { f(m,0) += ( dNx(m,0) * sig(0,0) + dNx(m,1) * sig(1,0) ) * vol; f(m,1) += ( dNx(m,0) * sig(0,1) + dNx(m,1) * sig(1,1) ) * vol; } } } } // ------------------------------------------------------------------------------------------------- inline void Quadrature::int_gradN_dot_tensor4_dot_gradNT_dV(const xt::xtensor &qtensor, xt::xtensor &elemmat) const { assert( qtensor.shape()[0] == m_nelem ); assert( qtensor.shape()[1] == m_nip ); assert( qtensor.shape()[2] == m_ndim ); assert( qtensor.shape()[3] == m_ndim ); assert( qtensor.shape()[4] == m_ndim ); assert( qtensor.shape()[5] == m_ndim ); assert( elemmat.shape()[0] == m_nelem ); assert( elemmat.shape()[1] == m_nne*m_ndim ); assert( elemmat.shape()[2] == m_nne*m_ndim ); // zero-initialize output: matrix of vector elemmat.fill(0.0); // loop over all elements (in parallel) #pragma omp parallel for for ( size_t e = 0 ; e < m_nelem ; ++e ) { // alias (e.g. nodal force) auto K = xt::adapt(&elemmat(e,0,0), xt::xshape()); // loop over all integration points in element "e" for ( size_t q = 0 ; q < m_nip ; ++q ){ // - alias auto dNx = xt::adapt(&m_dNx(e,q,0,0), xt::xshape()); auto C = xt::adapt(&qtensor(e,q,0,0,0,0), xt::xshape()); auto& vol = m_vol(e,q); // - evaluate dot product, and assemble for ( size_t m = 0 ; m < m_nne ; ++m ) for ( size_t n = 0 ; n < m_nne ; ++n ) for ( size_t i = 0 ; i < m_ndim ; ++i ) for ( size_t j = 0 ; j < m_ndim ; ++j ) for ( size_t k = 0 ; k < m_ndim ; ++k ) for ( size_t l = 0 ; l < m_ndim ; ++l ) K(m*m_ndim+j, n*m_ndim+k) += dNx(m,i) * C(i,j,k,l) * dNx(n,l) * vol; } } } // ------------------------------------------------------------------------------------------------- inline xt::xtensor Quadrature::dV() const { xt::xtensor out = xt::empty({m_nelem, m_nip}); this->dV(out); return out; } // ------------------------------------------------------------------------------------------------- inline xt::xtensor Quadrature::dVtensor() const { xt::xtensor out = xt::empty({m_nelem, m_nip, m_ndim, m_ndim}); this->dV(out); return out; } // ------------------------------------------------------------------------------------------------- inline xt::xtensor Quadrature::gradN_vector(const xt::xtensor &elemvec) const { xt::xtensor qtensor = xt::empty({m_nelem, m_nip, m_ndim, m_ndim}); this->gradN_vector(elemvec, qtensor); return qtensor; } // ------------------------------------------------------------------------------------------------- inline xt::xtensor Quadrature::gradN_vector_T(const xt::xtensor &elemvec) const { xt::xtensor qtensor = xt::empty({m_nelem, m_nip, m_ndim, m_ndim}); this->gradN_vector_T(elemvec, qtensor); return qtensor; } // ------------------------------------------------------------------------------------------------- inline xt::xtensor Quadrature::symGradN_vector(const xt::xtensor &elemvec) const { xt::xtensor qtensor = xt::empty({m_nelem, m_nip, m_ndim, m_ndim}); this->symGradN_vector(elemvec, qtensor); return qtensor; } // ------------------------------------------------------------------------------------------------- inline xt::xtensor Quadrature::int_N_scalar_NT_dV( const xt::xtensor &qscalar) const { xt::xtensor elemmat = xt::empty({m_nelem, m_nne*m_ndim, m_nne*m_ndim}); this->int_N_scalar_NT_dV(qscalar, elemmat); return elemmat; } // ------------------------------------------------------------------------------------------------- inline xt::xtensor Quadrature::int_gradN_dot_tensor2_dV( const xt::xtensor &qtensor) const { xt::xtensor elemvec = xt::empty({m_nelem, m_nne, m_ndim}); this->int_gradN_dot_tensor2_dV(qtensor, elemvec); return elemvec; } // ------------------------------------------------------------------------------------------------- inline xt::xtensor Quadrature::int_gradN_dot_tensor4_dot_gradNT_dV( const xt::xtensor &qtensor) const { xt::xtensor elemmat = xt::empty({m_nelem, m_ndim*m_nne, m_ndim*m_nne}); this->int_gradN_dot_tensor4_dot_gradNT_dV(qtensor, elemmat); return elemmat; } // ------------------------------------------------------------------------------------------------- }}} // namespace ... // ================================================================================================= #endif diff --git a/include/xGooseFEM/ElementQuad4Planar.h b/include/GooseFEM/ElementQuad4Planar.h similarity index 97% rename from include/xGooseFEM/ElementQuad4Planar.h rename to include/GooseFEM/ElementQuad4Planar.h index 02c8868..486e3bf 100644 --- a/include/xGooseFEM/ElementQuad4Planar.h +++ b/include/GooseFEM/ElementQuad4Planar.h @@ -1,142 +1,142 @@ /* ================================================================================================= (c - GPLv3) T.W.J. de Geus (Tom) | tom@geus.me | www.geus.me | github.com/tdegeus/GooseFEM ================================================================================================= */ -#ifndef XGOOSEFEM_ELEMENTQUAD4PLANAR_H -#define XGOOSEFEM_ELEMENTQUAD4PLANAR_H +#ifndef GOOSEFEM_ELEMENTQUAD4PLANAR_H +#define GOOSEFEM_ELEMENTQUAD4PLANAR_H // ------------------------------------------------------------------------------------------------- #include "GooseFEM.h" // ================================================================================================= -namespace xGooseFEM { +namespace GooseFEM { namespace Element { namespace Quad4 { // ------------------------------------------------------------------------------------------------- class QuadraturePlanar { public: // fixed dimensions: // ndim = 2 - number of dimensions // nne = 4 - number of nodes per element // tdim = 3 - number of dimensions of tensors // // naming convention: // "elemmat" - matrices stored per element - [nelem, nne*ndim, nne*ndim] // "elemvec" - nodal vectors stored per element - [nelem, nne, ndim] // "qtensor" - integration point tensor - [nelem, nip, tdim, tdim] // "qscalar" - integration point scalar - [nelem, nip] // constructor: integration point coordinates and weights are optional (default: Gauss) QuadraturePlanar() = default; - QuadraturePlanar(const xt::xtensor &x, double thick=1.) : QuadraturePlanar(x, Gauss::xi(), Gauss::w()){}; + QuadraturePlanar(const xt::xtensor &x, double thick=1.) : QuadraturePlanar(x, Gauss::xi(), Gauss::w(), thick){}; QuadraturePlanar(const xt::xtensor &x, const xt::xtensor &xi, const xt::xtensor &w, double thick=1.); // update the nodal positions (shape of "x" should match the earlier definition) void update_x(const xt::xtensor &x); // return dimensions size_t nelem() const { return m_nelem; }; // number of elements size_t nne() const { return m_nne; }; // number of nodes per element size_t ndim() const { return m_ndim; }; // number of dimension size_t nip() const { return m_nip; }; // number of integration points // return integration volume void dV(xt::xtensor &qscalar) const; void dV(xt::xtensor &qtensor) const; // same volume for all tensor components // dyadic product "qtensor(i,j) += dNdx(m,i) * elemvec(m,j)", its transpose and its symmetric part void gradN_vector(const xt::xtensor &elemvec, xt::xtensor &qtensor) const; void gradN_vector_T(const xt::xtensor &elemvec, xt::xtensor &qtensor) const; void symGradN_vector(const xt::xtensor &elemvec, xt::xtensor &qtensor) const; // integral of the scalar product "elemmat(m*ndim+i,n*ndim+i) += N(m) * qscalar * N(n) * dV" void int_N_scalar_NT_dV(const xt::xtensor &qscalar, xt::xtensor &elemmat) const; // integral of the dot product "elemvec(m,j) += dNdx(m,i) * qtensor(i,j) * dV" void int_gradN_dot_tensor2_dV(const xt::xtensor &qtensor, xt::xtensor &elemvec) const; // integral of the dot product "elemmat(m*2+j, n*2+k) += dNdx(m,i) * qtensor(i,j,k,l) * dNdx(n,l) * dV" void int_gradN_dot_tensor4_dot_gradNT_dV(const xt::xtensor &qtensor, xt::xtensor &elemmat) const; // auto allocation of the functions above xt::xtensor dV() const; xt::xtensor dVtensor() const; xt::xtensor gradN_vector(const xt::xtensor &elemvec) const; xt::xtensor gradN_vector_T(const xt::xtensor &elemvec) const; xt::xtensor symGradN_vector(const xt::xtensor &elemvec) const; xt::xtensor int_N_scalar_NT_dV(const xt::xtensor &qscalar) const; xt::xtensor int_gradN_dot_tensor2_dV(const xt::xtensor &qtensor) const; xt::xtensor int_gradN_dot_tensor4_dot_gradNT_dV(const xt::xtensor &qtensor) const; private: // compute "vol" and "dNdx" based on current "x" void compute_dN(); private: // dimensions (flexible) size_t m_nelem; // number of elements size_t m_nip; // number of integration points // dimensions (fixed for this element type) static const size_t m_nne=4; // number of nodes per element static const size_t m_ndim=2; // number of dimensions static const size_t m_tdim=3; // number of dimensions of tensors // data arrays xt::xtensor m_x; // nodal positions stored per element [nelem, nne, ndim] xt::xtensor m_w; // weight of each integration point [nip] xt::xtensor m_xi; // local coordinate of each integration point [nip, ndim] xt::xtensor m_N; // shape functions [nip, nne] xt::xtensor m_dNxi; // shape function gradients w.r.t. local coordinate [nip, nne, ndim] xt::xtensor m_dNx; // shape function gradients w.r.t. global coordinate [nelem, nip, nne, ndim] xt::xtensor m_vol; // integration point volume [nelem, nip] // thickness double m_thick; }; // ------------------------------------------------------------------------------------------------- }}} // namespace ... // ================================================================================================= #endif diff --git a/include/xGooseFEM/ElementQuad4Planar.hpp b/include/GooseFEM/ElementQuad4Planar.hpp similarity index 99% rename from include/xGooseFEM/ElementQuad4Planar.hpp rename to include/GooseFEM/ElementQuad4Planar.hpp index 9e0dbbc..c6169d7 100644 --- a/include/xGooseFEM/ElementQuad4Planar.hpp +++ b/include/GooseFEM/ElementQuad4Planar.hpp @@ -1,514 +1,514 @@ /* ================================================================================================= (c - GPLv3) T.W.J. de Geus (Tom) | tom@geus.me | www.geus.me | github.com/tdegeus/GooseFEM ================================================================================================= */ -#ifndef XGOOSEFEM_ELEMENTQUAD4PLANAR_CPP -#define XGOOSEFEM_ELEMENTQUAD4PLANAR_CPP +#ifndef GOOSEFEM_ELEMENTQUAD4PLANAR_CPP +#define GOOSEFEM_ELEMENTQUAD4PLANAR_CPP // ------------------------------------------------------------------------------------------------- #include "GooseFEM.h" // ================================================================================================= -namespace xGooseFEM { +namespace GooseFEM { namespace Element { namespace Quad4 { // ================================================================================================= inline QuadraturePlanar::QuadraturePlanar(const xt::xtensor &x, const xt::xtensor &xi, const xt::xtensor &w, double thick) : m_x(x), m_w(w), m_xi(xi), m_thick(thick) { // check input assert( m_x.shape()[1] == m_nne ); assert( m_x.shape()[2] == m_ndim ); // extract number of elements and number of integration points m_nelem = m_x.shape()[0]; m_nip = m_w.size(); // check input assert( m_xi.shape()[0] == m_nip ); assert( m_xi.shape()[1] == m_ndim ); assert( m_w .size() == m_nip ); // allocate arrays m_N = xt::empty({ m_nip, m_nne }); m_dNxi = xt::empty({ m_nip, m_nne, m_ndim}); m_dNx = xt::empty({m_nelem, m_nip, m_nne, m_ndim}); m_vol = xt::empty({m_nelem, m_nip }); // shape functions for ( size_t q = 0 ; q < m_nip ; ++q ) { m_N(q,0) = .25 * (1.-m_xi(q,0)) * (1.-m_xi(q,1)); m_N(q,1) = .25 * (1.+m_xi(q,0)) * (1.-m_xi(q,1)); m_N(q,2) = .25 * (1.+m_xi(q,0)) * (1.+m_xi(q,1)); m_N(q,3) = .25 * (1.-m_xi(q,0)) * (1.+m_xi(q,1)); } // shape function gradients in local coordinates for ( size_t q = 0 ; q < m_nip ; ++q ) { // - dN / dxi_0 m_dNxi(q,0,0) = -.25*(1.-m_xi(q,1)); m_dNxi(q,1,0) = +.25*(1.-m_xi(q,1)); m_dNxi(q,2,0) = +.25*(1.+m_xi(q,1)); m_dNxi(q,3,0) = -.25*(1.+m_xi(q,1)); // - dN / dxi_1 m_dNxi(q,0,1) = -.25*(1.-m_xi(q,0)); m_dNxi(q,1,1) = -.25*(1.+m_xi(q,0)); m_dNxi(q,2,1) = +.25*(1.+m_xi(q,0)); m_dNxi(q,3,1) = +.25*(1.-m_xi(q,0)); } // compute the shape function gradients, based on "x" compute_dN(); } // ------------------------------------------------------------------------------------------------- inline void QuadraturePlanar::dV(xt::xtensor &qscalar) const { assert( qscalar.shape()[0] == m_nelem ); assert( qscalar.shape()[1] == m_nip ); #pragma omp parallel for for ( size_t e = 0 ; e < m_nelem ; ++e ) for ( size_t q = 0 ; q < m_nip ; ++q ) qscalar(e,q) = m_vol(e,q); } // ------------------------------------------------------------------------------------------------- inline void QuadraturePlanar::dV(xt::xtensor &qtensor) const { assert( qtensor.shape()[0] == m_nelem ); assert( qtensor.shape()[1] == m_nne ); assert( qtensor.shape()[2] == m_tdim ); assert( qtensor.shape()[3] == m_tdim ); #pragma omp parallel for for ( size_t e = 0 ; e < m_nelem ; ++e ) for ( size_t q = 0 ; q < m_nip ; ++q ) for ( size_t i = 0 ; i < m_tdim ; ++i ) for ( size_t j = 0 ; j < m_tdim ; ++j ) qtensor(e,q,i,j) = m_vol(e,q); } // ------------------------------------------------------------------------------------------------- inline void QuadraturePlanar::update_x(const xt::xtensor &x) { assert( x.shape()[0] == m_nelem ); assert( x.shape()[1] == m_nne ); assert( x.shape()[2] == m_ndim ); assert( x.size() == m_x.size() ); // update positions xt::noalias(m_x) = x; // update the shape function gradients for the new "x" compute_dN(); } // ------------------------------------------------------------------------------------------------- inline void QuadraturePlanar::compute_dN() { // loop over all elements (in parallel) #pragma omp parallel { // allocate local variables T2 J, Jinv; #pragma omp for for ( size_t e = 0 ; e < m_nelem ; ++e ) { // alias nodal positions auto x = xt::adapt(&m_x(e,0,0), xt::xshape()); // loop over integration points for ( size_t q = 0 ; q < m_nip ; ++q ) { // - alias auto dNxi = xt::adapt(&m_dNxi( q,0,0), xt::xshape()); auto dNx = xt::adapt(&m_dNx (e,q,0,0), xt::xshape()); // - Jacobian (loops unrolled for efficiency) // J(i,j) += dNxi(m,i) * x(m,j); J(0,0) = dNxi(0,0)*x(0,0) + dNxi(1,0)*x(1,0) + dNxi(2,0)*x(2,0) + dNxi(3,0)*x(3,0); J(0,1) = dNxi(0,0)*x(0,1) + dNxi(1,0)*x(1,1) + dNxi(2,0)*x(2,1) + dNxi(3,0)*x(3,1); J(1,0) = dNxi(0,1)*x(0,0) + dNxi(1,1)*x(1,0) + dNxi(2,1)*x(2,0) + dNxi(3,1)*x(3,0); J(1,1) = dNxi(0,1)*x(0,1) + dNxi(1,1)*x(1,1) + dNxi(2,1)*x(2,1) + dNxi(3,1)*x(3,1); // - determinant and inverse of the Jacobian double Jdet = inv(J, Jinv); // - shape function gradients wrt global coordinates (loops partly unrolled for efficiency) // dNx(m,i) += Jinv(i,j) * dNxi(m,j); for ( size_t m = 0 ; m < m_nne ; ++m ) { dNx(m,0) = Jinv(0,0) * dNxi(m,0) + Jinv(0,1) * dNxi(m,1); dNx(m,1) = Jinv(1,0) * dNxi(m,0) + Jinv(1,1) * dNxi(m,1); } // - integration point volume m_vol(e,q) = m_w(q) * Jdet * m_thick; } } } } // ------------------------------------------------------------------------------------------------- inline void QuadraturePlanar::gradN_vector( const xt::xtensor &elemvec, xt::xtensor &qtensor) const { assert( elemvec.shape()[0] == m_nelem ); assert( elemvec.shape()[1] == m_nne ); assert( elemvec.shape()[2] == m_ndim ); assert( qtensor.shape()[0] == m_nelem ); assert( qtensor.shape()[1] == m_nne ); assert( qtensor.shape()[2] == m_tdim ); assert( qtensor.shape()[3] == m_tdim ); // zero-initialize output: matrix of tensors qtensor.fill(0.0); // loop over all elements (in parallel) #pragma omp parallel for for ( size_t e = 0 ; e < m_nelem ; ++e ) { // alias element vector (e.g. nodal displacements) auto u = xt::adapt(&elemvec(e,0,0), xt::xshape()); // loop over all integration points in element "e" for ( size_t q = 0 ; q < m_nip ; ++q ) { // - alias auto dNx = xt::adapt(&m_dNx (e,q,0,0), xt::xshape()); auto gradu = xt::adapt(&qtensor(e,q,0,0), xt::xshape()); // - evaluate dyadic product (loops unrolled for efficiency) // gradu(i,j) += dNx(m,i) * u(m,j) gradu(0,0) = dNx(0,0)*u(0,0) + dNx(1,0)*u(1,0) + dNx(2,0)*u(2,0) + dNx(3,0)*u(3,0); gradu(0,1) = dNx(0,0)*u(0,1) + dNx(1,0)*u(1,1) + dNx(2,0)*u(2,1) + dNx(3,0)*u(3,1); gradu(1,0) = dNx(0,1)*u(0,0) + dNx(1,1)*u(1,0) + dNx(2,1)*u(2,0) + dNx(3,1)*u(3,0); gradu(1,1) = dNx(0,1)*u(0,1) + dNx(1,1)*u(1,1) + dNx(2,1)*u(2,1) + dNx(3,1)*u(3,1); } } } // ------------------------------------------------------------------------------------------------- inline void QuadraturePlanar::gradN_vector_T( const xt::xtensor &elemvec, xt::xtensor &qtensor) const { assert( elemvec.shape()[0] == m_nelem ); assert( elemvec.shape()[1] == m_nne ); assert( elemvec.shape()[2] == m_ndim ); assert( qtensor.shape()[0] == m_nelem ); assert( qtensor.shape()[1] == m_nne ); assert( qtensor.shape()[2] == m_tdim ); assert( qtensor.shape()[3] == m_tdim ); // zero-initialize output: matrix of tensors qtensor.fill(0.0); // loop over all elements (in parallel) #pragma omp parallel for for ( size_t e = 0 ; e < m_nelem ; ++e ) { // alias element vector (e.g. nodal displacements) auto u = xt::adapt(&elemvec(e,0,0), xt::xshape()); // loop over all integration points in element "e" for ( size_t q = 0 ; q < m_nip ; ++q ) { // - alias auto dNx = xt::adapt(&m_dNx (e,q,0,0), xt::xshape()); auto gradu = xt::adapt(&qtensor(e,q,0,0), xt::xshape()); // - evaluate transpose of dyadic product (loops unrolled for efficiency) // gradu(j,i) += dNx(m,i) * u(m,j) gradu(0,0) = dNx(0,0)*u(0,0) + dNx(1,0)*u(1,0) + dNx(2,0)*u(2,0) + dNx(3,0)*u(3,0); gradu(1,0) = dNx(0,0)*u(0,1) + dNx(1,0)*u(1,1) + dNx(2,0)*u(2,1) + dNx(3,0)*u(3,1); gradu(0,1) = dNx(0,1)*u(0,0) + dNx(1,1)*u(1,0) + dNx(2,1)*u(2,0) + dNx(3,1)*u(3,0); gradu(1,1) = dNx(0,1)*u(0,1) + dNx(1,1)*u(1,1) + dNx(2,1)*u(2,1) + dNx(3,1)*u(3,1); } } } // ------------------------------------------------------------------------------------------------- inline void QuadraturePlanar::symGradN_vector( const xt::xtensor &elemvec, xt::xtensor &qtensor) const { assert( elemvec.shape()[0] == m_nelem ); assert( elemvec.shape()[1] == m_nne ); assert( elemvec.shape()[2] == m_ndim ); assert( qtensor.shape()[0] == m_nelem ); assert( qtensor.shape()[1] == m_nne ); assert( qtensor.shape()[2] == m_tdim ); assert( qtensor.shape()[3] == m_tdim ); // zero-initialize output: matrix of tensors qtensor.fill(0.0); // loop over all elements (in parallel) #pragma omp parallel for for ( size_t e = 0 ; e < m_nelem ; ++e ) { // alias element vector (e.g. nodal displacements) auto u = xt::adapt(&elemvec(e,0,0), xt::xshape()); // loop over all integration points in element "e" for ( size_t q = 0 ; q < m_nip ; ++q ) { // - alias auto dNx = xt::adapt(&m_dNx (e,q,0,0), xt::xshape()); auto eps = xt::adapt(&qtensor(e,q,0,0), xt::xshape()); // - evaluate symmetrized dyadic product (loops unrolled for efficiency) // grad(i,j) += dNx(m,i) * u(m,j) // eps (j,i) = 0.5 * ( grad(i,j) + grad(j,i) ) eps(0,0) = dNx(0,0)*u(0,0) + dNx(1,0)*u(1,0) + dNx(2,0)*u(2,0) + dNx(3,0)*u(3,0); eps(1,1) = dNx(0,1)*u(0,1) + dNx(1,1)*u(1,1) + dNx(2,1)*u(2,1) + dNx(3,1)*u(3,1); eps(0,1) = ( dNx(0,0)*u(0,1) + dNx(1,0)*u(1,1) + dNx(2,0)*u(2,1) + dNx(3,0)*u(3,1) + dNx(0,1)*u(0,0) + dNx(1,1)*u(1,0) + dNx(2,1)*u(2,0) + dNx(3,1)*u(3,0) ) * 0.5; eps(1,0) = eps(0,1); } } } // ------------------------------------------------------------------------------------------------- inline void QuadraturePlanar::int_N_scalar_NT_dV( const xt::xtensor &qscalar, xt::xtensor &elemmat) const { assert( qscalar.shape()[0] == m_nelem ); assert( qscalar.shape()[1] == m_nip ); assert( elemmat.shape()[0] == m_nelem ); assert( elemmat.shape()[1] == m_nne*m_ndim ); assert( elemmat.shape()[2] == m_nne*m_ndim ); // zero-initialize: matrix of matrices elemmat.fill(0.0); // loop over all elements (in parallel) #pragma omp parallel for for ( size_t e = 0 ; e < m_nelem ; ++e ) { // alias (e.g. mass matrix) auto M = xt::adapt(&elemmat(e,0,0), xt::xshape()); // loop over all integration points in element "e" for ( size_t q = 0 ; q < m_nip ; ++q ) { // - alias auto N = xt::adapt(&m_N(q,0), xt::xshape()); auto& vol = m_vol (e,q); auto& rho = qscalar(e,q); // - evaluate scalar product, for all dimensions, and assemble // M(m*ndim+i,n*ndim+i) += N(m) * scalar * N(n) * dV for ( size_t m = 0 ; m < m_nne ; ++m ) { for ( size_t n = 0 ; n < m_nne ; ++n ) { M(m*m_ndim+0, n*m_ndim+0) += N(m) * rho * N(n) * vol; M(m*m_ndim+1, n*m_ndim+1) += N(m) * rho * N(n) * vol; } } } } } // ------------------------------------------------------------------------------------------------- inline void QuadraturePlanar::int_gradN_dot_tensor2_dV(const xt::xtensor &qtensor, xt::xtensor &elemvec) const { assert( qtensor.shape()[0] == m_nelem ); assert( qtensor.shape()[1] == m_nip ); assert( qtensor.shape()[2] == m_tdim ); assert( qtensor.shape()[3] == m_tdim ); assert( elemvec.shape()[0] == m_nelem ); assert( elemvec.shape()[1] == m_nne ); assert( elemvec.shape()[2] == m_ndim ); // zero-initialize output: matrix of vectors elemvec.fill(0.0); // loop over all elements (in parallel) #pragma omp parallel for for ( size_t e = 0 ; e < m_nelem ; ++e ) { // alias (e.g. nodal force) auto f = xt::adapt(&elemvec(e,0,0), xt::xshape()); // loop over all integration points in element "e" for ( size_t q = 0 ; q < m_nip ; ++q ) { // - alias auto dNx = xt::adapt(&m_dNx (e,q,0,0), xt::xshape()); auto sig = xt::adapt(&qtensor(e,q,0,0), xt::xshape()); auto& vol = m_vol(e,q); // - evaluate dot product, and assemble for ( size_t m = 0 ; m < m_nne ; ++m ) { f(m,0) += ( dNx(m,0) * sig(0,0) + dNx(m,1) * sig(1,0) ) * vol; f(m,1) += ( dNx(m,0) * sig(0,1) + dNx(m,1) * sig(1,1) ) * vol; } } } } // ------------------------------------------------------------------------------------------------- inline void QuadraturePlanar::int_gradN_dot_tensor4_dot_gradNT_dV(const xt::xtensor &qtensor, xt::xtensor &elemmat) const { assert( qtensor.shape()[0] == m_nelem ); assert( qtensor.shape()[1] == m_nip ); assert( qtensor.shape()[2] == m_tdim ); assert( qtensor.shape()[3] == m_tdim ); assert( qtensor.shape()[4] == m_tdim ); assert( qtensor.shape()[5] == m_tdim ); assert( elemmat.shape()[0] == m_nelem ); assert( elemmat.shape()[1] == m_nne*m_ndim ); assert( elemmat.shape()[2] == m_nne*m_ndim ); // zero-initialize output: matrix of vector elemmat.fill(0.0); // loop over all elements (in parallel) #pragma omp parallel for for ( size_t e = 0 ; e < m_nelem ; ++e ) { // alias (e.g. nodal force) auto K = xt::adapt(&elemmat(e,0,0), xt::xshape()); // loop over all integration points in element "e" for ( size_t q = 0 ; q < m_nip ; ++q ){ // - alias auto dNx = xt::adapt(&m_dNx(e,q,0,0), xt::xshape()); auto C = xt::adapt(&qtensor(e,q,0,0,0,0), xt::xshape()); auto& vol = m_vol(e,q); // - evaluate dot product, and assemble for ( size_t m = 0 ; m < m_nne ; ++m ) for ( size_t n = 0 ; n < m_nne ; ++n ) for ( size_t i = 0 ; i < m_ndim ; ++i ) for ( size_t j = 0 ; j < m_ndim ; ++j ) for ( size_t k = 0 ; k < m_ndim ; ++k ) for ( size_t l = 0 ; l < m_ndim ; ++l ) K(m*m_ndim+j, n*m_ndim+k) += dNx(m,i) * C(i,j,k,l) * dNx(n,l) * vol; } } } // ------------------------------------------------------------------------------------------------- inline xt::xtensor QuadraturePlanar::dV() const { xt::xtensor out = xt::empty({m_nelem, m_nip}); this->dV(out); return out; } // ------------------------------------------------------------------------------------------------- inline xt::xtensor QuadraturePlanar::dVtensor() const { xt::xtensor out = xt::empty({m_nelem, m_nip, m_tdim, m_tdim}); this->dV(out); return out; } // ------------------------------------------------------------------------------------------------- inline xt::xtensor QuadraturePlanar::gradN_vector(const xt::xtensor &elemvec) const { xt::xtensor qtensor = xt::empty({m_nelem, m_nip, m_tdim, m_tdim}); this->gradN_vector(elemvec, qtensor); return qtensor; } // ------------------------------------------------------------------------------------------------- inline xt::xtensor QuadraturePlanar::gradN_vector_T(const xt::xtensor &elemvec) const { xt::xtensor qtensor = xt::empty({m_nelem, m_nip, m_tdim, m_tdim}); this->gradN_vector_T(elemvec, qtensor); return qtensor; } // ------------------------------------------------------------------------------------------------- inline xt::xtensor QuadraturePlanar::symGradN_vector(const xt::xtensor &elemvec) const { xt::xtensor qtensor = xt::empty({m_nelem, m_nip, m_tdim, m_tdim}); this->symGradN_vector(elemvec, qtensor); return qtensor; } // ------------------------------------------------------------------------------------------------- inline xt::xtensor QuadraturePlanar::int_N_scalar_NT_dV( const xt::xtensor &qscalar) const { xt::xtensor elemmat = xt::empty({m_nelem, m_nne*m_ndim, m_nne*m_ndim}); this->int_N_scalar_NT_dV(qscalar, elemmat); return elemmat; } // ------------------------------------------------------------------------------------------------- inline xt::xtensor QuadraturePlanar::int_gradN_dot_tensor2_dV( const xt::xtensor &qtensor) const { xt::xtensor elemvec = xt::empty({m_nelem, m_nne, m_ndim}); this->int_gradN_dot_tensor2_dV(qtensor, elemvec); return elemvec; } // ------------------------------------------------------------------------------------------------- inline xt::xtensor QuadraturePlanar::int_gradN_dot_tensor4_dot_gradNT_dV( const xt::xtensor &qtensor) const { xt::xtensor elemmat = xt::empty({m_nelem, m_ndim*m_nne, m_ndim*m_nne}); this->int_gradN_dot_tensor4_dot_gradNT_dV(qtensor, elemmat); return elemmat; } // ------------------------------------------------------------------------------------------------- }}} // namespace ... // ================================================================================================= #endif diff --git a/include/xGooseFEM/GooseFEM.h b/include/GooseFEM/GooseFEM.h similarity index 98% rename from include/xGooseFEM/GooseFEM.h rename to include/GooseFEM/GooseFEM.h index 4c1f4ee..3772938 100644 --- a/include/xGooseFEM/GooseFEM.h +++ b/include/GooseFEM/GooseFEM.h @@ -1,112 +1,112 @@ /* ================================================================================================= (c - GPLv3) T.W.J. de Geus (Tom) | tom@geus.me | www.geus.me | github.com/tdegeus/GooseFEM ================================================================================================= */ -#ifndef XGOOSEFEM_H -#define XGOOSEFEM_H +#ifndef GOOSEFEM_H +#define GOOSEFEM_H // ================================================================================================= #define _USE_MATH_DEFINES // to use "M_PI" from "math.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace xt::placeholders; // ================================================================================================= #define GOOSEFEM_WORLD_VERSION 0 #define GOOSEFEM_MAJOR_VERSION 1 #define GOOSEFEM_MINOR_VERSION 0 #define GOOSEFEM_VERSION_AT_LEAST(x,y,z) \ (GOOSEFEM_WORLD_VERSION>x || (GOOSEFEM_WORLD_VERSION>=x && \ (GOOSEFEM_MAJOR_VERSION>y || (GOOSEFEM_MAJOR_VERSION>=y && \ GOOSEFEM_MINOR_VERSION>=z)))) #define GOOSEFEM_VERSION(x,y,z) \ (GOOSEFEM_WORLD_VERSION==x && \ GOOSEFEM_MAJOR_VERSION==y && \ GOOSEFEM_MINOR_VERSION==z) // ================================================================================================= // dummy operation that can be use to suppress the "unused parameter" warnings #define UNUSED(p) ( (void)(p) ) // ================================================================================================= // alias Eigen sparse matrices -namespace xGooseFEM +namespace GooseFEM { typedef Eigen::SparseMatrix SpMatD; typedef Eigen::SparseMatrix SpMatS; typedef Eigen::Triplet TripD; } // ================================================================================================= #include "Mesh.h" #include "Mesh.hpp" #include "MeshTri3.h" #include "MeshTri3.hpp" #include "MeshQuad4.h" #include "MeshQuad4.hpp" #include "MeshHex8.h" #include "MeshHex8.hpp" #include "Element.h" #include "Element.hpp" #include "ElementQuad4.h" #include "ElementQuad4.hpp" #include "ElementQuad4Planar.h" #include "ElementQuad4Planar.hpp" #include "ElementHex8.h" #include "ElementHex8.hpp" #include "Vector.h" #include "Vector.hpp" #include "VectorPartitioned.h" #include "VectorPartitioned.hpp" #include "MatrixPartitioned.h" #include "MatrixPartitioned.hpp" #include "MatrixDiagonal.h" #include "MatrixDiagonal.hpp" #include "MatrixDiagonalPartitioned.h" #include "MatrixDiagonalPartitioned.hpp" #include "Iterate.h" #include "Iterate.hpp" #include "Dynamics.h" #include "Dynamics.hpp" // ================================================================================================= #endif diff --git a/include/xGooseFEM/Iterate.h b/include/GooseFEM/Iterate.h similarity index 94% rename from include/xGooseFEM/Iterate.h rename to include/GooseFEM/Iterate.h index dd1bd29..59287cd 100644 --- a/include/xGooseFEM/Iterate.h +++ b/include/GooseFEM/Iterate.h @@ -1,48 +1,48 @@ /* ================================================================================================= (c - GPLv3) T.W.J. de Geus (Tom) | tom@geus.me | www.geus.me | github.com/tdegeus/GooseFEM ================================================================================================= */ -#ifndef XGOOSEFEM_ITERATE_H -#define XGOOSEFEM_ITERATE_H +#ifndef GOOSEFEM_ITERATE_H +#define GOOSEFEM_ITERATE_H // ------------------------------------------------------------------------------------------------- #include "GooseFEM.h" // ======================================= GooseFEM::Iterate ======================================= -namespace xGooseFEM { +namespace GooseFEM { namespace Iterate { // ------------------------------------------------------------------------------------------------- class StopList { private: // list with residuals std::vector m_res; public: // constructors StopList(size_t n=1); // reset all residuals to infinity (and change the number of residuals to check) void reset(); void reset(size_t n); // update list of residuals, return true if all residuals are below the tolerance bool stop(double res, double tol); }; // ------------------------------------------------------------------------------------------------- }} // namespace ... // ================================================================================================= #endif diff --git a/include/xGooseFEM/Iterate.hpp b/include/GooseFEM/Iterate.hpp similarity index 96% rename from include/xGooseFEM/Iterate.hpp rename to include/GooseFEM/Iterate.hpp index fc8487a..b465daa 100644 --- a/include/xGooseFEM/Iterate.hpp +++ b/include/GooseFEM/Iterate.hpp @@ -1,81 +1,81 @@ /* ================================================================================================= (c - GPLv3) T.W.J. de Geus (Tom) | tom@geus.me | www.geus.me | github.com/tdegeus/GooseFEM ================================================================================================= */ -#ifndef XGOOSEFEM_ITERATE_CPP -#define XGOOSEFEM_ITERATE_CPP +#ifndef GOOSEFEM_ITERATE_CPP +#define GOOSEFEM_ITERATE_CPP // ------------------------------------------------------------------------------------------------- #include "Iterate.h" // ======================================= GooseFEM::Iterate ======================================= -namespace xGooseFEM { +namespace GooseFEM { namespace Iterate { // ------------------------------------------------------------------------------------------------- inline StopList::StopList(size_t n) { // resize list m_res.resize(n); // set all residual to infinity reset(); } // ------------------------------------------------------------------------------------------------- inline void StopList::reset() { // set all residual to infinity for ( auto &i : m_res ) i = std::numeric_limits::infinity(); } // ------------------------------------------------------------------------------------------------- inline void StopList::reset(size_t n) { // resize list m_res.resize(n); // set all residual to infinity reset(); } // ------------------------------------------------------------------------------------------------- inline bool StopList::stop(double res, double tol) { // move residual one place back (forgetting the first) for ( size_t i = 1 ; i < m_res.size() ; ++i ) m_res[i-1] = m_res[i]; // add new residual to the end m_res[m_res.size()-1] = res; // check for convergence: all residuals should be below the tolerance for ( size_t i = 0 ; i < m_res.size() ; ++i ) if ( m_res[i] > tol ) return false; // check for convergence: all residuals should be decreasing for ( size_t i = 1 ; i < m_res.size() ; ++i ) if ( m_res[i] > m_res[i-1] ) return false; // all checks passed: signal convergence return true; } // ------------------------------------------------------------------------------------------------- }} // namespace ... // ================================================================================================= #endif diff --git a/include/xGooseFEM/MatrixDiagonal.h b/include/GooseFEM/MatrixDiagonal.h similarity index 96% rename from include/xGooseFEM/MatrixDiagonal.h rename to include/GooseFEM/MatrixDiagonal.h index f469286..f557569 100644 --- a/include/xGooseFEM/MatrixDiagonal.h +++ b/include/GooseFEM/MatrixDiagonal.h @@ -1,84 +1,84 @@ /* ================================================================================================= (c - GPLv3) T.W.J. de Geus (Tom) | tom@geus.me | www.geus.me | github.com/tdegeus/GooseFEM ================================================================================================= */ -#ifndef XGOOSEFEM_MATRIXDIAGONAL_H -#define XGOOSEFEM_MATRIXDIAGONAL_H +#ifndef GOOSEFEM_MATRIXDIAGONAL_H +#define GOOSEFEM_MATRIXDIAGONAL_H // ------------------------------------------------------------------------------------------------- #include "GooseFEM.h" // =========================================== GooseFEM ============================================ -namespace xGooseFEM { +namespace GooseFEM { // ------------------------------------------------------------------------------------------------- class MatrixDiagonal { public: // constructor MatrixDiagonal() = default; MatrixDiagonal(const xt::xtensor &conn, const xt::xtensor &dofs); // dimensions size_t nelem() const; // number of elements size_t nne() const; // number of nodes per element size_t nnode() const; // number of nodes size_t ndim() const; // number of dimensions size_t ndof() const; // number of DOFs // DOF lists xt::xtensor dofs() const; // DOFs // product: b_i = A_ij * x_j xt::xtensor dot(const xt::xtensor &x) const; // assemble from matrices stored per element [nelem, nne*ndim, nne*ndim] // WARNING: ignores any off-diagonal terms void assemble(const xt::xtensor &elemmat); // set void set(const xt::xtensor &A); // solve: x = A \ b xt::xtensor solve(const xt::xtensor &b); // return matrix as diagonal matrix (column) xt::xtensor asDiagonal() const; private: // the diagonal matrix (not-partitioned), and its inverse (re-used to solve different RHS) xt::xtensor m_data; xt::xtensor m_inv; // signal changes to data compare to the last inverse bool m_change=false; // bookkeeping xt::xtensor m_conn; // connectivity [nelem, nne ] xt::xtensor m_dofs; // DOF-numbers per node [nnode, ndim] // dimensions size_t m_nelem; // number of elements size_t m_nne; // number of nodes per element size_t m_nnode; // number of nodes size_t m_ndim; // number of dimensions size_t m_ndof; // number of DOFs // compute inverse (automatically evaluated by "solve") void factorize(); }; // ------------------------------------------------------------------------------------------------- } // namespace ... // ================================================================================================= #endif diff --git a/include/xGooseFEM/MatrixDiagonal.hpp b/include/GooseFEM/MatrixDiagonal.hpp similarity index 98% rename from include/xGooseFEM/MatrixDiagonal.hpp rename to include/GooseFEM/MatrixDiagonal.hpp index 955a795..b7c54da 100644 --- a/include/xGooseFEM/MatrixDiagonal.hpp +++ b/include/GooseFEM/MatrixDiagonal.hpp @@ -1,177 +1,177 @@ /* ================================================================================================= (c - GPLv3) T.W.J. de Geus (Tom) | tom@geus.me | www.geus.me | github.com/tdegeus/GooseFEM ================================================================================================= */ -#ifndef XGOOSEFEM_MATRIXDIAGONAL_CPP -#define XGOOSEFEM_MATRIXDIAGONAL_CPP +#ifndef GOOSEFEM_MATRIXDIAGONAL_CPP +#define GOOSEFEM_MATRIXDIAGONAL_CPP // ------------------------------------------------------------------------------------------------- #include "MatrixDiagonal.h" // ================================================================================================= -namespace xGooseFEM { +namespace GooseFEM { // ------------------------------------------------------------------------------------------------- inline MatrixDiagonal::MatrixDiagonal(const xt::xtensor &conn, const xt::xtensor &dofs) : m_conn(conn), m_dofs(dofs) { // mesh dimensions m_nelem = m_conn.shape()[0]; m_nne = m_conn.shape()[1]; m_nnode = m_dofs.shape()[0]; m_ndim = m_dofs.shape()[1]; // dimensions of the system m_ndof = xt::amax(m_dofs)[0] + 1; // allocate matrix and its inverse m_data = xt::empty({m_ndof}); m_inv = xt::empty({m_ndof}); // check consistency assert( xt::amax(m_conn)[0] + 1 == m_nnode ); assert( m_ndof <= m_nnode * m_ndim ); } // ------------------------------------------------------------------------------------------------- inline size_t MatrixDiagonal::nelem() const { return m_nelem; } // ------------------------------------------------------------------------------------------------- inline size_t MatrixDiagonal::nne() const { return m_nne; } // ------------------------------------------------------------------------------------------------- inline size_t MatrixDiagonal::nnode() const { return m_nnode; } // ------------------------------------------------------------------------------------------------- inline size_t MatrixDiagonal::ndim() const { return m_ndim; } // ------------------------------------------------------------------------------------------------- inline size_t MatrixDiagonal::ndof() const { return m_ndof; } // ------------------------------------------------------------------------------------------------- inline xt::xtensor MatrixDiagonal::dofs() const { return m_dofs; } // ------------------------------------------------------------------------------------------------- inline xt::xtensor MatrixDiagonal::dot(const xt::xtensor &x) const { // check input assert( x.size() == m_ndof ); // compute product return m_data * x; } // ------------------------------------------------------------------------------------------------- inline void MatrixDiagonal::assemble(const xt::xtensor &elemmat) { // check input assert( elemmat.shape()[0] == m_nelem ); assert( elemmat.shape()[1] == m_nne*m_ndim ); assert( elemmat.shape()[2] == m_nne*m_ndim ); assert( Element::isDiagonal(elemmat) ); // zero-initialize matrix m_data.fill(0.0); // assemble for ( size_t e = 0 ; e < m_nelem ; ++e ) for ( size_t m = 0 ; m < m_nne ; ++m ) for ( size_t i = 0 ; i < m_ndim ; ++i ) m_data(m_dofs(m_conn(e,m),i)) += elemmat(e,m*m_ndim+i,m*m_ndim+i); // signal change m_change = true; } // ------------------------------------------------------------------------------------------------- inline void MatrixDiagonal::set(const xt::xtensor &A) { // check input assert( A.shape()[0] == m_ndof ); // copy std::copy(A.begin(), A.end(), m_data.begin()); // signal change m_change = true; } // ------------------------------------------------------------------------------------------------- inline void MatrixDiagonal::factorize() { // skip for unchanged "m_data" if ( ! m_change ) return; // invert #pragma omp parallel for for ( size_t i = 0 ; i < m_ndof ; ++i ) m_inv(i) = 1. / m_data(i); // reset signal m_change = false; } // ------------------------------------------------------------------------------------------------- inline xt::xtensor MatrixDiagonal::solve(const xt::xtensor &b) { // check input assert( b.size() == m_ndof ); // factorise (if needed) this->factorize(); // solve xt::xtensor x = m_inv * b; // return output return x; } // ------------------------------------------------------------------------------------------------- inline xt::xtensor MatrixDiagonal::asDiagonal() const { return m_data; } // ------------------------------------------------------------------------------------------------- } // namespace ... // ================================================================================================= #endif diff --git a/include/xGooseFEM/MatrixDiagonalPartitioned.h b/include/GooseFEM/MatrixDiagonalPartitioned.h similarity index 96% rename from include/xGooseFEM/MatrixDiagonalPartitioned.h rename to include/GooseFEM/MatrixDiagonalPartitioned.h index c372bb9..2713f93 100644 --- a/include/xGooseFEM/MatrixDiagonalPartitioned.h +++ b/include/GooseFEM/MatrixDiagonalPartitioned.h @@ -1,99 +1,99 @@ /* ================================================================================================= (c - GPLv3) T.W.J. de Geus (Tom) | tom@geus.me | www.geus.me | github.com/tdegeus/GooseFEM ================================================================================================= */ -#ifndef XGOOSEFEM_MATRIXDIAGONALPARTITIONED_H -#define XGOOSEFEM_MATRIXDIAGONALPARTITIONED_H +#ifndef GOOSEFEM_MATRIXDIAGONALPARTITIONED_H +#define GOOSEFEM_MATRIXDIAGONALPARTITIONED_H // ------------------------------------------------------------------------------------------------- #include "GooseFEM.h" // =========================================== GooseFEM ============================================ -namespace xGooseFEM { +namespace GooseFEM { // ------------------------------------------------------------------------------------------------- class MatrixDiagonalPartitioned { public: // default constructor MatrixDiagonalPartitioned() = default; // constructor MatrixDiagonalPartitioned(const xt::xtensor &conn, const xt::xtensor &dofs, const xt::xtensor &iip); // dimensions size_t nelem() const; // number of elements size_t nne() const; // number of nodes per element size_t nnode() const; // number of nodes size_t ndim() const; // number of dimensions size_t ndof() const; // number of DOFs size_t nnu() const; // number of unknown DOFs size_t nnp() const; // number of prescribed DOFs // DOF lists xt::xtensor dofs() const; // DOFs xt::xtensor iiu() const; // unknown DOFs xt::xtensor iip() const; // prescribed DOFs // product: b_i = A_ij * x_j // b = A * x xt::xtensor dot (const xt::xtensor &x ) const; // b_u = A_uu * x_u + A_up * x_p xt::xtensor dot_u(const xt::xtensor &x_u, const xt::xtensor &x_p) const; // b_p = A_pu * x_u + A_pp * x_p xt::xtensor dot_p(const xt::xtensor &x_u, const xt::xtensor &x_p) const; // assemble from matrices stored per element [nelem, nne*ndim, nne*ndim] // WARNING: ignores any off-diagonal terms void assemble(const xt::xtensor &elemmat); // solve: x_u = A_uu \ ( b_u - A_up * x_p ) xt::xtensor solve(const xt::xtensor &b_u, const xt::xtensor &x_p); // return matrix as diagonal matrix xt::xtensor asDiagonal() const; private: // the diagonal matrix, and its inverse (re-used to solve different RHS) xt::xtensor m_data_uu; xt::xtensor m_data_pp; xt::xtensor m_inv_uu; // signal changes to data compare to the last inverse bool m_change=false; // bookkeeping xt::xtensor m_conn; // connectivity [nelem, nne ] xt::xtensor m_dofs; // DOF-numbers per node [nnode, ndim] xt::xtensor m_part; // DOF-numbers per node, renumbered [nnode, ndim] xt::xtensor m_iiu; // DOF-numbers that are unknown [nnu] xt::xtensor m_iip; // DOF-numbers that are prescribed [nnp] // dimensions size_t m_nelem; // number of elements size_t m_nne; // number of nodes per element size_t m_nnode; // number of nodes size_t m_ndim; // number of dimensions size_t m_ndof; // number of DOFs size_t m_nnu; // number of unknown DOFs size_t m_nnp; // number of prescribed DOFs // compute inverse (automatically evaluated by "solve") void factorize(); }; // ------------------------------------------------------------------------------------------------- } // namespace ... // ================================================================================================= #endif diff --git a/include/xGooseFEM/MatrixDiagonalPartitioned.hpp b/include/GooseFEM/MatrixDiagonalPartitioned.hpp similarity index 98% rename from include/xGooseFEM/MatrixDiagonalPartitioned.hpp rename to include/GooseFEM/MatrixDiagonalPartitioned.hpp index aa19c00..18b179c 100644 --- a/include/xGooseFEM/MatrixDiagonalPartitioned.hpp +++ b/include/GooseFEM/MatrixDiagonalPartitioned.hpp @@ -1,297 +1,297 @@ /* ================================================================================================= (c - GPLv3) T.W.J. de Geus (Tom) | tom@geus.me | www.geus.me | github.com/tdegeus/GooseFEM ================================================================================================= */ -#ifndef XGOOSEFEM_MATRIXDIAGONALPARTITIONED_CPP -#define XGOOSEFEM_MATRIXDIAGONALPARTITIONED_CPP +#ifndef GOOSEFEM_MATRIXDIAGONALPARTITIONED_CPP +#define GOOSEFEM_MATRIXDIAGONALPARTITIONED_CPP // ------------------------------------------------------------------------------------------------- #include "MatrixDiagonalPartitioned.h" // ================================================================================================= -namespace xGooseFEM { +namespace GooseFEM { // ------------------------------------------------------------------------------------------------- inline MatrixDiagonalPartitioned::MatrixDiagonalPartitioned(const xt::xtensor &conn, const xt::xtensor &dofs, const xt::xtensor &iip) : m_conn(conn), m_dofs(dofs), m_iip(iip) { // mesh dimensions m_nelem = m_conn.shape()[0]; m_nne = m_conn.shape()[1]; m_nnode = m_dofs.shape()[0]; m_ndim = m_dofs.shape()[1]; // list with unknown DOFs m_iiu = xt::setdiff1d(dofs, iip); // dimensions of the system m_ndof = xt::amax(m_dofs)[0] + 1; m_nnp = m_iip.size(); m_nnu = m_iiu.size(); // DOFs per node, such that iiu = arange(nnu), iip = nnu + arange(nnp) m_part = Mesh::reorder(m_dofs, m_iip, "end"); // allocate matrix and its inverse m_data_uu = xt::empty({m_nnu}); m_data_pp = xt::empty({m_nnp}); m_inv_uu = xt::empty({m_nnu}); // check consistency assert( xt::amax(m_conn)[0] + 1 == m_nnode ); assert( xt::amax(m_iip)[0] <= xt::amax(m_dofs)[0] ); assert( m_ndof <= m_nnode * m_ndim ); } // ------------------------------------------------------------------------------------------------- inline size_t MatrixDiagonalPartitioned::nelem() const { return m_nelem; } // ------------------------------------------------------------------------------------------------- inline size_t MatrixDiagonalPartitioned::nne() const { return m_nne; } // ------------------------------------------------------------------------------------------------- inline size_t MatrixDiagonalPartitioned::nnode() const { return m_nnode; } // ------------------------------------------------------------------------------------------------- inline size_t MatrixDiagonalPartitioned::ndim() const { return m_ndim; } // ------------------------------------------------------------------------------------------------- inline size_t MatrixDiagonalPartitioned::ndof() const { return m_ndof; } // ------------------------------------------------------------------------------------------------- inline size_t MatrixDiagonalPartitioned::nnu() const { return m_nnu; } // ------------------------------------------------------------------------------------------------- inline size_t MatrixDiagonalPartitioned::nnp() const { return m_nnp; } // ------------------------------------------------------------------------------------------------- inline xt::xtensor MatrixDiagonalPartitioned::dofs() const { return m_dofs; } // ------------------------------------------------------------------------------------------------- inline xt::xtensor MatrixDiagonalPartitioned::iiu() const { return m_iiu; } // ------------------------------------------------------------------------------------------------- inline xt::xtensor MatrixDiagonalPartitioned::iip() const { return m_iip; } // ------------------------------------------------------------------------------------------------- inline xt::xtensor MatrixDiagonalPartitioned::dot(const xt::xtensor &x) const { // check input assert( x.size() == m_ndof ); // allocate output xt::xtensor b = xt::empty({m_ndof}); // compute product // - #pragma omp parallel for for ( size_t i = 0 ; i < m_nnu ; ++i ) b(m_iiu(i)) = m_data_uu(i) * x(m_iiu(i)); // - #pragma omp parallel for for ( size_t i = 0 ; i < m_nnp ; ++i ) b(m_iip(i)) = m_data_pp(i) * x(m_iip(i)); // return output return b; } // ------------------------------------------------------------------------------------------------- inline xt::xtensor MatrixDiagonalPartitioned::dot_u( const xt::xtensor &x_u, const xt::xtensor &x_p) const { // suppress warning UNUSED(x_p); // check input assert( x_u.size() == m_nnu ); assert( x_p.size() == m_nnp ); // allocate output xt::xtensor b_u = xt::empty({m_nnu}); // compute product #pragma omp parallel for for ( size_t i = 0 ; i < m_nnu ; ++i ) b_u(i) = m_data_uu(i) * x_u(i); return b_u; } // ------------------------------------------------------------------------------------------------- inline xt::xtensor MatrixDiagonalPartitioned::dot_p( const xt::xtensor &x_u, const xt::xtensor &x_p) const { // suppress warning UNUSED(x_u); // check input assert( x_u.size() == m_nnu ); assert( x_p.size() == m_nnp ); // allocate output xt::xtensor b_p = xt::empty({m_nnp}); // compute product #pragma omp parallel for for ( size_t i = 0 ; i < m_nnp ; ++i ) b_p(i) = m_data_pp(i) * x_p(i); return b_p; } // ------------------------------------------------------------------------------------------------- inline void MatrixDiagonalPartitioned::assemble(const xt::xtensor &elemmat) { // check input assert( elemmat.shape()[0] == m_nelem ); assert( elemmat.shape()[1] == m_nne*m_ndim ); assert( elemmat.shape()[2] == m_nne*m_ndim ); assert( Element::isDiagonal(elemmat) ); // zero-initialize matrix m_data_uu.fill(0.0); m_data_pp.fill(0.0); // assemble for ( size_t e = 0 ; e < m_nelem ; ++e ) { for ( size_t m = 0 ; m < m_nne ; ++m ) { for ( size_t i = 0 ; i < m_ndim ; ++i ) { size_t di = m_part(m_conn(e,m),i); if ( di < m_nnu ) m_data_uu(di ) += elemmat(e,m*m_ndim+i,m*m_ndim+i); else m_data_pp(di-m_nnu) += elemmat(e,m*m_ndim+i,m*m_ndim+i); } } } // signal change m_change = true; } // ------------------------------------------------------------------------------------------------- inline void MatrixDiagonalPartitioned::factorize() { // skip for unchanged "m_data" if ( ! m_change ) return; // invert #pragma omp parallel for for ( size_t i = 0 ; i < m_nnu ; ++i ) m_inv_uu(i) = 1. / m_data_uu(i); // reset signal m_change = false; } // ------------------------------------------------------------------------------------------------- inline xt::xtensor MatrixDiagonalPartitioned::solve( const xt::xtensor &b_u, const xt::xtensor &x_p) { // suppress warning UNUSED(x_p); // check input assert( b_u.shape()[0] == m_nnu ); assert( x_p.shape()[0] == m_nnp ); // factorise (if needed) this->factorize(); // allocate output xt::xtensor x_u = xt::empty({m_nnu}); // solve #pragma omp parallel for for ( size_t i = 0 ; i < m_nnu ; ++i ) x_u(i) = m_inv_uu(i) * b_u(i); // return output return x_u; } // ------------------------------------------------------------------------------------------------- inline xt::xtensor MatrixDiagonalPartitioned::asDiagonal() const { // allocate output xt::xtensor out = xt::zeros({m_ndof}); // assemble output // - #pragma omp parallel for for ( size_t i = 0 ; i < m_nnu ; ++i ) out(m_iiu(i)) = m_data_uu(i); // - #pragma omp parallel for for ( size_t i = 0 ; i < m_nnp ; ++i ) out(m_iip(i)) = m_data_pp(i); // return output return out; } // ------------------------------------------------------------------------------------------------- } // namespace ... // ================================================================================================= #endif diff --git a/include/xGooseFEM/MatrixPartitioned.h b/include/GooseFEM/MatrixPartitioned.h similarity index 97% rename from include/xGooseFEM/MatrixPartitioned.h rename to include/GooseFEM/MatrixPartitioned.h index c7d7644..3e1e7c9 100644 --- a/include/xGooseFEM/MatrixPartitioned.h +++ b/include/GooseFEM/MatrixPartitioned.h @@ -1,97 +1,97 @@ /* ================================================================================================= (c - GPLv3) T.W.J. de Geus (Tom) | tom@geus.me | www.geus.me | github.com/tdegeus/GooseFEM ================================================================================================= */ -#ifndef XGOOSEFEM_MATRIXPARTITIONED_H -#define XGOOSEFEM_MATRIXPARTITIONED_H +#ifndef GOOSEFEM_MATRIXPARTITIONED_H +#define GOOSEFEM_MATRIXPARTITIONED_H // ------------------------------------------------------------------------------------------------- #include "GooseFEM.h" // =========================================== GooseFEM ============================================ -namespace xGooseFEM { +namespace GooseFEM { // ------------------------------------------------------------------------------------------------- class MatrixPartitioned { public: // default constructor MatrixPartitioned() = default; // constructor MatrixPartitioned(const xt::xtensor &conn, const xt::xtensor &dofs, const xt::xtensor &iip); // dimensions size_t nelem() const; // number of elements size_t nne() const; // number of nodes per element size_t nnode() const; // number of nodes size_t ndim() const; // number of dimensions size_t ndof() const; // number of DOFs size_t nnu() const; // number of unknown DOFs size_t nnp() const; // number of prescribed DOFs // DOF lists xt::xtensor dofs() const; // DOFs xt::xtensor iiu() const; // unknown DOFs xt::xtensor iip() const; // prescribed DOFs // assemble from matrices stored per element [nelem, nne*ndim, nne*ndim] void assemble(const xt::xtensor &elemmat); // solve: x_u = A_uu \ ( b_u - A_up * x_p ) xt::xtensor solve(const xt::xtensor &b_u, const xt::xtensor &x_p); private: // the matrix Eigen::SparseMatrix m_data_uu; Eigen::SparseMatrix m_data_up; Eigen::SparseMatrix m_data_pu; Eigen::SparseMatrix m_data_pp; // the matrix to assemble std::vector m_trip_uu; std::vector m_trip_up; std::vector m_trip_pu; std::vector m_trip_pp; // solver (re-used to solve different RHS) Eigen::SimplicialLDLT> m_solver; // signal changes to data compare to the last inverse bool m_change=false; // bookkeeping xt::xtensor m_conn; // connectivity [nelem, nne ] xt::xtensor m_dofs; // DOF-numbers per node [nnode, ndim] xt::xtensor m_part; // DOF-numbers per node, renumbered [nnode, ndim] xt::xtensor m_iiu; // DOF-numbers that are unknown [nnu] xt::xtensor m_iip; // DOF-numbers that are prescribed [nnp] // dimensions size_t m_nelem; // number of elements size_t m_nne; // number of nodes per element size_t m_nnode; // number of nodes size_t m_ndim; // number of dimensions size_t m_ndof; // number of DOFs size_t m_nnu; // number of unknown DOFs size_t m_nnp; // number of prescribed DOFs // compute inverse (automatically evaluated by "solve") void factorize(); }; // ------------------------------------------------------------------------------------------------- } // namespace ... // ================================================================================================= #endif diff --git a/include/xGooseFEM/MatrixPartitioned.hpp b/include/GooseFEM/MatrixPartitioned.hpp similarity index 98% rename from include/xGooseFEM/MatrixPartitioned.hpp rename to include/GooseFEM/MatrixPartitioned.hpp index 880e2ad..fd7e706 100644 --- a/include/xGooseFEM/MatrixPartitioned.hpp +++ b/include/GooseFEM/MatrixPartitioned.hpp @@ -1,238 +1,238 @@ /* ================================================================================================= (c - GPLv3) T.W.J. de Geus (Tom) | tom@geus.me | www.geus.me | github.com/tdegeus/GooseFEM ================================================================================================= */ -#ifndef XGOOSEFEM_MATRIXPARTITIONED_CPP -#define XGOOSEFEM_MATRIXPARTITIONED_CPP +#ifndef GOOSEFEM_MATRIXPARTITIONED_CPP +#define GOOSEFEM_MATRIXPARTITIONED_CPP // ------------------------------------------------------------------------------------------------- #include "MatrixPartitioned.h" #include // ================================================================================================= -namespace xGooseFEM { +namespace GooseFEM { // ------------------------------------------------------------------------------------------------- inline MatrixPartitioned::MatrixPartitioned(const xt::xtensor &conn, const xt::xtensor &dofs, const xt::xtensor &iip) : m_conn(conn), m_dofs(dofs), m_iip(iip) { // mesh dimensions m_nelem = m_conn.shape()[0]; m_nne = m_conn.shape()[1]; m_nnode = m_dofs.shape()[0]; m_ndim = m_dofs.shape()[1]; // list with unknown DOFs m_iiu = xt::setdiff1d(dofs, iip); // dimensions of the system m_ndof = xt::amax(m_dofs)[0] + 1; m_nnp = m_iip.size(); m_nnu = m_iiu.size(); // DOFs per node, such that iiu = arange(nnu), iip = nnu + arange(nnp) m_part = Mesh::reorder(m_dofs, m_iip, "end"); // allocate triplet list m_trip_uu.reserve(m_nelem*m_nne*m_ndim*m_nne*m_ndim); m_trip_up.reserve(m_nelem*m_nne*m_ndim*m_nne*m_ndim); m_trip_pu.reserve(m_nelem*m_nne*m_ndim*m_nne*m_ndim); m_trip_pp.reserve(m_nelem*m_nne*m_ndim*m_nne*m_ndim); // allocate sparse matrices m_data_uu.resize(m_nnu,m_nnu); m_data_up.resize(m_nnu,m_nnp); m_data_pu.resize(m_nnp,m_nnu); m_data_pp.resize(m_nnp,m_nnp); // check consistency assert( xt::amax(m_conn)[0] + 1 == m_nnode ); assert( xt::amax(m_iip)[0] <= xt::amax(m_dofs)[0] ); assert( m_ndof <= m_nnode * m_ndim ); } // ------------------------------------------------------------------------------------------------- inline size_t MatrixPartitioned::nelem() const { return m_nelem; } // ------------------------------------------------------------------------------------------------- inline size_t MatrixPartitioned::nne() const { return m_nne; } // ------------------------------------------------------------------------------------------------- inline size_t MatrixPartitioned::nnode() const { return m_nnode; } // ------------------------------------------------------------------------------------------------- inline size_t MatrixPartitioned::ndim() const { return m_ndim; } // ------------------------------------------------------------------------------------------------- inline size_t MatrixPartitioned::ndof() const { return m_ndof; } // ------------------------------------------------------------------------------------------------- inline size_t MatrixPartitioned::nnu() const { return m_nnu; } // ------------------------------------------------------------------------------------------------- inline size_t MatrixPartitioned::nnp() const { return m_nnp; } // ------------------------------------------------------------------------------------------------- inline xt::xtensor MatrixPartitioned::dofs() const { return m_dofs; } // ------------------------------------------------------------------------------------------------- inline xt::xtensor MatrixPartitioned::iiu() const { return m_iiu; } // ------------------------------------------------------------------------------------------------- inline xt::xtensor MatrixPartitioned::iip() const { return m_iip; } // ------------------------------------------------------------------------------------------------- inline void MatrixPartitioned::assemble(const xt::xtensor &elemmat) { // check input assert( elemmat.shape()[0] == m_nelem ); assert( elemmat.shape()[1] == m_nne*m_ndim ); assert( elemmat.shape()[2] == m_nne*m_ndim ); // initialize triplet list m_trip_uu.clear(); m_trip_up.clear(); m_trip_pu.clear(); m_trip_pp.clear(); // assemble to triplet list for ( size_t e = 0 ; e < m_nelem ; ++e ) { for ( size_t m = 0 ; m < m_nne ; ++m ) { for ( size_t i = 0 ; i < m_ndim ; ++i ) { size_t di = m_part(m_conn(e,m),i); for ( size_t n = 0 ; n < m_nne ; ++n ) { for ( size_t j = 0 ; j < m_ndim ; ++j ) { size_t dj = m_part(m_conn(e,n),j); if ( di < m_nnu and dj < m_nnu ) m_trip_uu.push_back(TripD(di ,dj ,elemmat(e,m*m_ndim+i,n*m_ndim+j))); else if ( di < m_nnu ) m_trip_up.push_back(TripD(di ,dj-m_nnu,elemmat(e,m*m_ndim+i,n*m_ndim+j))); else if ( dj < m_nnu ) m_trip_pu.push_back(TripD(di-m_nnu,dj ,elemmat(e,m*m_ndim+i,n*m_ndim+j))); else m_trip_pp.push_back(TripD(di-m_nnu,dj-m_nnu,elemmat(e,m*m_ndim+i,n*m_ndim+j))); } } } } } // convert to sparse matrix m_data_uu.setFromTriplets(m_trip_uu.begin(), m_trip_uu.end()); m_data_up.setFromTriplets(m_trip_up.begin(), m_trip_up.end()); m_data_pu.setFromTriplets(m_trip_pu.begin(), m_trip_pu.end()); m_data_pp.setFromTriplets(m_trip_pp.begin(), m_trip_pp.end()); // signal change m_change = true; } // ------------------------------------------------------------------------------------------------- inline void MatrixPartitioned::factorize() { // skip for unchanged "m_data" if ( ! m_change ) return; // factorise m_solver.compute(m_data_uu); // reset signal m_change = false; } // ------------------------------------------------------------------------------------------------- inline xt::xtensor MatrixPartitioned::solve( const xt::xtensor &b_u, const xt::xtensor &x_p) { // check input assert( b_u.shape()[0] == m_nnu ); assert( x_p.shape()[0] == m_nnp ); // factorise (if needed) this->factorize(); // copy of input as Eigen objects // - allocate Eigen::VectorXd B_u(m_nnu,1); Eigen::VectorXd X_p(m_nnp,1); // - copy std::copy(b_u.begin(), b_u.end(), B_u.data()); std::copy(x_p.begin(), x_p.end(), X_p.data()); // solve Eigen::VectorXd X_u = m_solver.solve(Eigen::VectorXd(B_u - m_data_up * X_p)); // copy of output from Eigen object // - allocate xt::xtensor x_u = xt::empty({m_nnu}); // - copy std::copy(X_u.data(), X_u.data()+m_nnu, x_u.begin()); // return output return x_u; } // ------------------------------------------------------------------------------------------------- } // namespace ... // ================================================================================================= #endif diff --git a/include/xGooseFEM/Mesh.h b/include/GooseFEM/Mesh.h similarity index 96% rename from include/xGooseFEM/Mesh.h rename to include/GooseFEM/Mesh.h index 3be2568..ad2d395 100644 --- a/include/xGooseFEM/Mesh.h +++ b/include/GooseFEM/Mesh.h @@ -1,52 +1,52 @@ /* ================================================================================================= (c - GPLv3) T.W.J. de Geus (Tom) | tom@geus.me | www.geus.me | github.com/tdegeus/GooseFEM ================================================================================================= */ -#ifndef XGOOSEFEM_MESH_H -#define XGOOSEFEM_MESH_H +#ifndef GOOSEFEM_MESH_H +#define GOOSEFEM_MESH_H // ------------------------------------------------------------------------------------------------- #include "GooseFEM.h" // ======================================== GooseFEM::Mesh ========================================= -namespace xGooseFEM { +namespace GooseFEM { namespace Mesh { // ------------------------------------------------------------------------------------------------- // list with DOF-numbers in sequential order inline xt::xtensor dofs(size_t nnode, size_t ndim); // renumber to lowest possible numbers (e.g. [0,3,4,2] -> [0,2,3,1]) inline xt::xtensor renumber(const xt::xtensor &dofs); // get the list needed to renumber: dofs_renumbered(i,j) = index(dofs(i,j)) inline xt::xtensor renumber_index(const xt::xtensor &dofs); // renumber such that certain indices "iip" are are moved to the beginning or the end // (get the lowest or the highest indices); if "iiu" are the remaining indices, after renumbering: // iiu = arange(nnu), iip = nnu + arange(nnp) inline xt::xtensor reorder(const xt::xtensor &dofs, const xt::xtensor &iip, const std::string &location="end"); // get the list needed to reorder: dofs_reordered(i,j) = index(dofs(i,j)) inline xt::xtensor reorder_index(const xt::xtensor &dofs, const xt::xtensor &iip, const std::string &location="end"); // number of elements connected to each node inline xt::xtensor coordination(const xt::xtensor &conn); // elements connected to each node inline SpMatS elem2node(const xt::xtensor &conn); // ------------------------------------------------------------------------------------------------- }} // namespace ... // ================================================================================================= #endif diff --git a/include/xGooseFEM/Mesh.hpp b/include/GooseFEM/Mesh.hpp similarity index 98% rename from include/xGooseFEM/Mesh.hpp rename to include/GooseFEM/Mesh.hpp index 0823d55..b53eaef 100644 --- a/include/xGooseFEM/Mesh.hpp +++ b/include/GooseFEM/Mesh.hpp @@ -1,186 +1,186 @@ /* ================================================================================================= (c - GPLv3) T.W.J. de Geus (Tom) | tom@geus.me | www.geus.me | github.com/tdegeus/GooseFEM ================================================================================================= */ -#ifndef XGOOSEFEM_MESH_CPP -#define XGOOSEFEM_MESH_CPP +#ifndef GOOSEFEM_MESH_CPP +#define GOOSEFEM_MESH_CPP // ------------------------------------------------------------------------------------------------- #include "Mesh.h" // ======================================== GooseFEM::Mesh ========================================= -namespace xGooseFEM { +namespace GooseFEM { namespace Mesh { // ------------------------------------------------------------------------------------------------- inline xt::xtensor dofs(size_t nnode, size_t ndim) { return xt::reshape_view(xt::arange(nnode*ndim),{nnode,ndim}); } // ------------------------------------------------------------------------------------------------- inline xt::xtensor renumber_index(const xt::xtensor &dofs) { // get unique list of DOFs xt::xtensor unique = xt::unique(dofs); // allocate list to renumber "dofs" xt::xtensor renum = xt::empty({xt::amax(dofs)[0]+1}); // define renumbering for ( size_t i = 0 ; i < unique.size() ; ++i ) renum[unique[i]] = i; return renum; } // ------------------------------------------------------------------------------------------------- inline xt::xtensor renumber(const xt::xtensor &dofs) { // list to renumber "dofs" auto renum = renumber_index(dofs); // allocate reordered DOFs xt::xtensor dofs_renumbered(dofs.shape()); // iterator for loop below auto jt = dofs_renumbered.begin(); // loop to renumber: dofs_renumbered(i,j) = renum(dofs(i,j)) for ( auto it = dofs.begin() ; it != dofs.end() ; ++it, ++jt ) (*jt) = renum((*it)); return dofs_renumbered; } // ------------------------------------------------------------------------------------------------- inline xt::xtensor reorder_index(const xt::xtensor &dofs, const xt::xtensor &iip, const std::string &location) { // check "iip" to be a unique set assert( xt::unique(iip).size() == iip.size() ); // get remaining DOFs auto iiu = xt::setdiff1d(dofs, iip); // get sizes auto nnu = iiu.size(); auto nnp = iip.size(); // original set of DOFs auto old = xt::unique(dofs); // sanity check assert( iiu.size() + iip.size() == dofs.size() ); // list to renumber "dofs" // - allocate xt::xtensor renum = xt::empty({xt::amax(dofs)[0]+1}); // - fill if ( location == "end" ) { for ( size_t i = 0 ; i < iiu.size() ; ++i ) renum(iiu(i)) = i ; for ( size_t i = 0 ; i < iip.size() ; ++i ) renum(iip(i)) = i+nnu; } else if ( location == "begin" or location == "beginning" ) { for ( size_t i = 0 ; i < iip.size() ; ++i ) renum(iip(i)) = i ; for ( size_t i = 0 ; i < iiu.size() ; ++i ) renum(iiu(i)) = i+nnp; } else { throw std::runtime_error("Unknown reorder location '" + location + "'"); } return renum; } // ------------------------------------------------------------------------------------------------- inline xt::xtensor reorder(const xt::xtensor &dofs, const xt::xtensor &iip, const std::string &location) { // list to renumber "dofs" auto renum = reorder_index(dofs, iip, location); // allocate reordered DOFs xt::xtensor dofs_reordered(dofs.shape()); // iterator for loop below auto jt = dofs_reordered.begin(); // loop to renumber: dofs_reordered(i,j) = renum(dofs(i,j)) for ( auto it = dofs.begin() ; it != dofs.end() ; ++it, ++jt ) *jt = renum(*it); return dofs_reordered; } // ------------------------------------------------------------------------------------------------- inline xt::xtensor coordination(const xt::xtensor &conn) { // get number of nodes size_t nnode = xt::amax(conn)[0] + 1; // number of elements connected to each node // - allocate xt::xtensor N = xt::zeros({nnode}); // - fill from connectivity for ( auto it = conn.begin(); it != conn.end(); ++it ) N(*it) += 1; return N; } // ------------------------------------------------------------------------------------------------- inline SpMatS elem2node(const xt::xtensor &conn) { // get coordination auto N = coordination(conn); // get number of nodes auto nnode = N.size(); // triplet list, with elements per node // - allocate xt::xtensor idx = xt::zeros({nnode}); // - type typedef Eigen::Triplet T; // - allocate std::vector triplets; // - predict size triplets.reserve(xt::sum(N)[0]); // - fill for ( size_t e = 0 ; e < conn.shape()[0] ; ++e ) { for ( size_t m = 0 ; m < conn.shape()[1] ; ++m ) { size_t node = conn(e,m); triplets.push_back(T(node, idx(node), e)); idx(node)++; } } // spare matrix // - allocate SpMatS mat(nnode, xt::amax(N)[0]); // - fill mat.setFromTriplets(triplets.begin(), triplets.end()); return mat; } // ------------------------------------------------------------------------------------------------- }} // namespace ... // ================================================================================================= #endif diff --git a/include/xGooseFEM/MeshHex8.h b/include/GooseFEM/MeshHex8.h similarity index 99% rename from include/xGooseFEM/MeshHex8.h rename to include/GooseFEM/MeshHex8.h index 916037d..0bcf602 100644 --- a/include/xGooseFEM/MeshHex8.h +++ b/include/GooseFEM/MeshHex8.h @@ -1,329 +1,329 @@ /* ================================================================================================= (c - GPLv3) T.W.J. de Geus (Tom) | tom@geus.me | www.geus.me | github.com/tdegeus/GooseFEM ================================================================================================= */ -#ifndef XGOOSEFEM_MESHHEX8_H -#define XGOOSEFEM_MESHHEX8_H +#ifndef GOOSEFEM_MESHHEX8_H +#define GOOSEFEM_MESHHEX8_H // ------------------------------------------------------------------------------------------------- #include "GooseFEM.h" // ===================================== GooseFEM::Mesh::Hex8 ====================================== -namespace xGooseFEM { +namespace GooseFEM { namespace Mesh { namespace Hex8 { // ----------------------------------------- regular mesh ------------------------------------------ class Regular { private: double m_h; // elementary element edge-size (in all directions) size_t m_nelx; // number of elements in x-direction (length == "m_nelx * m_h") size_t m_nely; // number of elements in y-direction (length == "m_nely * m_h") size_t m_nelz; // number of elements in z-direction (length == "m_nely * m_h") size_t m_nelem; // number of elements size_t m_nnode; // number of nodes static const size_t m_nne=8; // number of nodes-per-element static const size_t m_ndim=3; // number of dimensions public: // mesh with "nelx*nely*nelz" 'elements' of edge size "h" Regular(size_t nelx, size_t nely, size_t nelz, double h=1.); // sizes 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 // mesh xt::xtensor coor() const; // nodal positions [nnode ,ndim] xt::xtensor conn() const; // connectivity [nelem ,nne ] // boundary nodes: planes xt::xtensor nodesFront() const; // node-numbers along the front plane xt::xtensor nodesBack() const; // node-numbers along the back plane xt::xtensor nodesLeft() const; // node-numbers along the left plane xt::xtensor nodesRight() const; // node-numbers along the right plane xt::xtensor nodesBottom() const; // node-numbers along the bottom plane xt::xtensor nodesTop() const; // node-numbers along the top plane // boundary nodes: faces xt::xtensor nodesFrontFace() const; // node-numbers along the front face xt::xtensor nodesBackFace() const; // node-numbers along the back face xt::xtensor nodesLeftFace() const; // node-numbers along the left face xt::xtensor nodesRightFace() const; // node-numbers along the right face xt::xtensor nodesBottomFace() const; // node-numbers along the bottom face xt::xtensor nodesTopFace() const; // node-numbers along the top face // boundary nodes: edges xt::xtensor nodesFrontBottomEdge() const; // node-numbers along the front - bottom edge xt::xtensor nodesFrontTopEdge() const; // node-numbers along the front - top edge xt::xtensor nodesFrontLeftEdge() const; // node-numbers along the front - left edge xt::xtensor nodesFrontRightEdge() const; // node-numbers along the front - right edge xt::xtensor nodesBackBottomEdge() const; // node-numbers along the back - bottom edge xt::xtensor nodesBackTopEdge() const; // node-numbers along the back - top edge xt::xtensor nodesBackLeftEdge() const; // node-numbers along the back - left edge xt::xtensor nodesBackRightEdge() const; // node-numbers along the back - right edge xt::xtensor nodesBottomLeftEdge() const; // node-numbers along the bottom - left edge xt::xtensor nodesBottomRightEdge() const; // node-numbers along the bottom - right edge xt::xtensor nodesTopLeftEdge() const; // node-numbers along the top - left edge xt::xtensor nodesTopRightEdge() const; // node-numbers along the top - right edge // boundary nodes: edges (aliases) xt::xtensor nodesBottomFrontEdge() const; // alias, see above: nodesFrontBottomEdge xt::xtensor nodesBottomBackEdge() const; // alias, see above: nodesBackBottomEdge xt::xtensor nodesTopFrontEdge() const; // alias, see above: nodesFrontTopEdge xt::xtensor nodesTopBackEdge() const; // alias, see above: nodesBackTopEdge xt::xtensor nodesLeftBottomEdge() const; // alias, see above: nodesBottomLeftEdge xt::xtensor nodesLeftFrontEdge() const; // alias, see above: nodesFrontLeftEdge xt::xtensor nodesLeftBackEdge() const; // alias, see above: nodesBackLeftEdge xt::xtensor nodesLeftTopEdge() const; // alias, see above: nodesTopLeftEdge xt::xtensor nodesRightBottomEdge() const; // alias, see above: nodesBottomRightEdge xt::xtensor nodesRightTopEdge() const; // alias, see above: nodesTopRightEdge xt::xtensor nodesRightFrontEdge() const; // alias, see above: nodesFrontRightEdge xt::xtensor nodesRightBackEdge() const; // alias, see above: nodesBackRightEdge // boundary nodes: edges, without corners xt::xtensor nodesFrontBottomOpenEdge() const; // node-numbers along the front - bottom edge xt::xtensor nodesFrontTopOpenEdge() const; // node-numbers along the front - top edge xt::xtensor nodesFrontLeftOpenEdge() const; // node-numbers along the front - left edge xt::xtensor nodesFrontRightOpenEdge() const; // node-numbers along the front - right edge xt::xtensor nodesBackBottomOpenEdge() const; // node-numbers along the back - bottom edge xt::xtensor nodesBackTopOpenEdge() const; // node-numbers along the back - top edge xt::xtensor nodesBackLeftOpenEdge() const; // node-numbers along the back - left edge xt::xtensor nodesBackRightOpenEdge() const; // node-numbers along the back - right edge xt::xtensor nodesBottomLeftOpenEdge() const; // node-numbers along the bottom - left edge xt::xtensor nodesBottomRightOpenEdge() const; // node-numbers along the bottom - right edge xt::xtensor nodesTopLeftOpenEdge() const; // node-numbers along the top - left edge xt::xtensor nodesTopRightOpenEdge() const; // node-numbers along the top - right edge // boundary nodes: edges, without corners (aliases) xt::xtensor nodesBottomFrontOpenEdge() const; // alias, see above: nodesFrontBottomOpenEdge xt::xtensor nodesBottomBackOpenEdge() const; // alias, see above: nodesBackBottomOpenEdge xt::xtensor nodesTopFrontOpenEdge() const; // alias, see above: nodesFrontTopOpenEdge xt::xtensor nodesTopBackOpenEdge() const; // alias, see above: nodesBackTopOpenEdge xt::xtensor nodesLeftBottomOpenEdge() const; // alias, see above: nodesBottomLeftOpenEdge xt::xtensor nodesLeftFrontOpenEdge() const; // alias, see above: nodesFrontLeftOpenEdge xt::xtensor nodesLeftBackOpenEdge() const; // alias, see above: nodesBackLeftOpenEdge xt::xtensor nodesLeftTopOpenEdge() const; // alias, see above: nodesTopLeftOpenEdge xt::xtensor nodesRightBottomOpenEdge() const; // alias, see above: nodesBottomRightOpenEdge xt::xtensor nodesRightTopOpenEdge() const; // alias, see above: nodesTopRightOpenEdge xt::xtensor nodesRightFrontOpenEdge() const; // alias, see above: nodesFrontRightOpenEdge xt::xtensor nodesRightBackOpenEdge() const; // alias, see above: nodesBackRightOpenEdge // boundary nodes: corners size_t nodesFrontBottomLeftCorner() const; // node-number of the front - bottom - left corner size_t nodesFrontBottomRightCorner() const; // node-number of the front - bottom - right corner size_t nodesFrontTopLeftCorner() const; // node-number of the front - top - left corner size_t nodesFrontTopRightCorner() const; // node-number of the front - top - right corner size_t nodesBackBottomLeftCorner() const; // node-number of the back - bottom - left corner size_t nodesBackBottomRightCorner() const; // node-number of the back - bottom - right corner size_t nodesBackTopLeftCorner() const; // node-number of the back - top - left corner size_t nodesBackTopRightCorner() const; // node-number of the back - top - right corner // boundary nodes: corners (aliases) size_t nodesFrontLeftBottomCorner() const; // alias, see above: nodesFrontBottomLeftCorner size_t nodesBottomFrontLeftCorner() const; // alias, see above: nodesFrontBottomLeftCorner size_t nodesBottomLeftFrontCorner() const; // alias, see above: nodesFrontBottomLeftCorner size_t nodesLeftFrontBottomCorner() const; // alias, see above: nodesFrontBottomLeftCorner size_t nodesLeftBottomFrontCorner() const; // alias, see above: nodesFrontBottomLeftCorner size_t nodesFrontRightBottomCorner() const; // alias, see above: nodesFrontBottomRightCorner size_t nodesBottomFrontRightCorner() const; // alias, see above: nodesFrontBottomRightCorner size_t nodesBottomRightFrontCorner() const; // alias, see above: nodesFrontBottomRightCorner size_t nodesRightFrontBottomCorner() const; // alias, see above: nodesFrontBottomRightCorner size_t nodesRightBottomFrontCorner() const; // alias, see above: nodesFrontBottomRightCorner size_t nodesFrontLeftTopCorner() const; // alias, see above: nodesFrontTopLeftCorner size_t nodesTopFrontLeftCorner() const; // alias, see above: nodesFrontTopLeftCorner size_t nodesTopLeftFrontCorner() const; // alias, see above: nodesFrontTopLeftCorner size_t nodesLeftFrontTopCorner() const; // alias, see above: nodesFrontTopLeftCorner size_t nodesLeftTopFrontCorner() const; // alias, see above: nodesFrontTopLeftCorner size_t nodesFrontRightTopCorner() const; // alias, see above: nodesFrontTopRightCorner size_t nodesTopFrontRightCorner() const; // alias, see above: nodesFrontTopRightCorner size_t nodesTopRightFrontCorner() const; // alias, see above: nodesFrontTopRightCorner size_t nodesRightFrontTopCorner() const; // alias, see above: nodesFrontTopRightCorner size_t nodesRightTopFrontCorner() const; // alias, see above: nodesFrontTopRightCorner size_t nodesBackLeftBottomCorner() const; // alias, see above: nodesBackBottomLeftCorner size_t nodesBottomBackLeftCorner() const; // alias, see above: nodesBackBottomLeftCorner size_t nodesBottomLeftBackCorner() const; // alias, see above: nodesBackBottomLeftCorner size_t nodesLeftBackBottomCorner() const; // alias, see above: nodesBackBottomLeftCorner size_t nodesLeftBottomBackCorner() const; // alias, see above: nodesBackBottomLeftCorner size_t nodesBackRightBottomCorner() const; // alias, see above: nodesBackBottomRightCorner size_t nodesBottomBackRightCorner() const; // alias, see above: nodesBackBottomRightCorner size_t nodesBottomRightBackCorner() const; // alias, see above: nodesBackBottomRightCorner size_t nodesRightBackBottomCorner() const; // alias, see above: nodesBackBottomRightCorner size_t nodesRightBottomBackCorner() const; // alias, see above: nodesBackBottomRightCorner size_t nodesBackLeftTopCorner() const; // alias, see above: nodesBackTopLeftCorner size_t nodesTopBackLeftCorner() const; // alias, see above: nodesBackTopLeftCorner size_t nodesTopLeftBackCorner() const; // alias, see above: nodesBackTopLeftCorner size_t nodesLeftBackTopCorner() const; // alias, see above: nodesBackTopLeftCorner size_t nodesLeftTopBackCorner() const; // alias, see above: nodesBackTopLeftCorner size_t nodesBackRightTopCorner() const; // alias, see above: nodesBackTopRightCorner size_t nodesTopBackRightCorner() const; // alias, see above: nodesBackTopRightCorner size_t nodesTopRightBackCorner() const; // alias, see above: nodesBackTopRightCorner size_t nodesRightBackTopCorner() const; // alias, see above: nodesBackTopRightCorner size_t nodesRightTopBackCorner() const; // alias, see above: nodesBackTopRightCorner // periodicity xt::xtensor nodesPeriodic() const; // periodic node pairs [:,2]: (independent, dependent) size_t nodesOrigin() const; // front-bottom-left node, used as reference for periodicity xt::xtensor dofs() const; // DOF-numbers for each component of each node (sequential) xt::xtensor dofsPeriodic() const; // ,, for the case that the periodicity if fully eliminated }; // ---------------------- mesh with a fine layer that exponentially coarsens ----------------------- class FineLayer { private: double m_h; // elementary element edge-size (in all directions) double m_Lx, m_Lz; // mesh size in "x" and "z" size_t m_nelem; // number of elements size_t m_nnode; // number of nodes static const size_t m_nne=8; // number of nodes-per-element static const size_t m_ndim=3; // number of dimensions xt::xtensor m_nelx, m_nelz; // number of elements in "x" and "z" (per el.layer in "y") xt::xtensor m_nnd; // total number of nodes in the main node layer (per nd.layer in "y") xt::xtensor m_nhx, m_nhy, m_nhz; // element size in each direction (per el.layer in "y") xt::xtensor m_refine; // refine direction (-1:no refine, 0:"x", 2:"z") (per el.layer in "y") xt::xtensor m_startElem; // start element (per el.layer in "y") xt::xtensor m_startNode; // start node (per nd.layer in "y") public: // mesh with "nelx*nely*nelz" elements of edge size "h"; elements are coarsened in "y"-direction FineLayer(size_t nelx, size_t nely, size_t nelz, double h=1., size_t nfine=1); // sizes 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 shape(size_t i) const; // actual shape in a certain direction // mesh xt::xtensor coor() const; // nodal positions [nnode ,ndim] xt::xtensor conn() const; // connectivity [nelem ,nne ] // element sets xt::xtensor elementsMiddleLayer() const; // elements in the middle, fine, layer // boundary nodes: planes xt::xtensor nodesFront() const; // node-numbers along the front plane xt::xtensor nodesBack() const; // node-numbers along the back plane xt::xtensor nodesLeft() const; // node-numbers along the left plane xt::xtensor nodesRight() const; // node-numbers along the right plane xt::xtensor nodesBottom() const; // node-numbers along the bottom plane xt::xtensor nodesTop() const; // node-numbers along the top plane // boundary nodes: faces xt::xtensor nodesFrontFace() const; // node-numbers along the front face xt::xtensor nodesBackFace() const; // node-numbers along the back face xt::xtensor nodesLeftFace() const; // node-numbers along the left face xt::xtensor nodesRightFace() const; // node-numbers along the right face xt::xtensor nodesBottomFace() const; // node-numbers along the bottom face xt::xtensor nodesTopFace() const; // node-numbers along the top face // boundary nodes: edges xt::xtensor nodesFrontBottomEdge() const; // node-numbers along the front - bottom edge xt::xtensor nodesFrontTopEdge() const; // node-numbers along the front - top edge xt::xtensor nodesFrontLeftEdge() const; // node-numbers along the front - left edge xt::xtensor nodesFrontRightEdge() const; // node-numbers along the front - right edge xt::xtensor nodesBackBottomEdge() const; // node-numbers along the back - bottom edge xt::xtensor nodesBackTopEdge() const; // node-numbers along the back - top edge xt::xtensor nodesBackLeftEdge() const; // node-numbers along the back - left edge xt::xtensor nodesBackRightEdge() const; // node-numbers along the back - right edge xt::xtensor nodesBottomLeftEdge() const; // node-numbers along the bottom - left edge xt::xtensor nodesBottomRightEdge() const; // node-numbers along the bottom - right edge xt::xtensor nodesTopLeftEdge() const; // node-numbers along the top - left edge xt::xtensor nodesTopRightEdge() const; // node-numbers along the top - right edge // boundary nodes: edges (aliases) xt::xtensor nodesBottomFrontEdge() const; // alias, see above: nodesFrontBottomEdge xt::xtensor nodesBottomBackEdge() const; // alias, see above: nodesBackBottomEdge xt::xtensor nodesTopFrontEdge() const; // alias, see above: nodesFrontTopEdge xt::xtensor nodesTopBackEdge() const; // alias, see above: nodesBackTopEdge xt::xtensor nodesLeftBottomEdge() const; // alias, see above: nodesBottomLeftEdge xt::xtensor nodesLeftFrontEdge() const; // alias, see above: nodesFrontLeftEdge xt::xtensor nodesLeftBackEdge() const; // alias, see above: nodesBackLeftEdge xt::xtensor nodesLeftTopEdge() const; // alias, see above: nodesTopLeftEdge xt::xtensor nodesRightBottomEdge() const; // alias, see above: nodesBottomRightEdge xt::xtensor nodesRightTopEdge() const; // alias, see above: nodesTopRightEdge xt::xtensor nodesRightFrontEdge() const; // alias, see above: nodesFrontRightEdge xt::xtensor nodesRightBackEdge() const; // alias, see above: nodesBackRightEdge // boundary nodes: edges, without corners xt::xtensor nodesFrontBottomOpenEdge() const; // node-numbers along the front - bottom edge xt::xtensor nodesFrontTopOpenEdge() const; // node-numbers along the front - top edge xt::xtensor nodesFrontLeftOpenEdge() const; // node-numbers along the front - left edge xt::xtensor nodesFrontRightOpenEdge() const; // node-numbers along the front - right edge xt::xtensor nodesBackBottomOpenEdge() const; // node-numbers along the back - bottom edge xt::xtensor nodesBackTopOpenEdge() const; // node-numbers along the back - top edge xt::xtensor nodesBackLeftOpenEdge() const; // node-numbers along the back - left edge xt::xtensor nodesBackRightOpenEdge() const; // node-numbers along the back - right edge xt::xtensor nodesBottomLeftOpenEdge() const; // node-numbers along the bottom - left edge xt::xtensor nodesBottomRightOpenEdge() const; // node-numbers along the bottom - right edge xt::xtensor nodesTopLeftOpenEdge() const; // node-numbers along the top - left edge xt::xtensor nodesTopRightOpenEdge() const; // node-numbers along the top - right edge // boundary nodes: edges, without corners (aliases) xt::xtensor nodesBottomFrontOpenEdge() const; // alias, see above: nodesFrontBottomOpenEdge xt::xtensor nodesBottomBackOpenEdge() const; // alias, see above: nodesBackBottomOpenEdge xt::xtensor nodesTopFrontOpenEdge() const; // alias, see above: nodesFrontTopOpenEdge xt::xtensor nodesTopBackOpenEdge() const; // alias, see above: nodesBackTopOpenEdge xt::xtensor nodesLeftBottomOpenEdge() const; // alias, see above: nodesBottomLeftOpenEdge xt::xtensor nodesLeftFrontOpenEdge() const; // alias, see above: nodesFrontLeftOpenEdge xt::xtensor nodesLeftBackOpenEdge() const; // alias, see above: nodesBackLeftOpenEdge xt::xtensor nodesLeftTopOpenEdge() const; // alias, see above: nodesTopLeftOpenEdge xt::xtensor nodesRightBottomOpenEdge() const; // alias, see above: nodesBottomRightOpenEdge xt::xtensor nodesRightTopOpenEdge() const; // alias, see above: nodesTopRightOpenEdge xt::xtensor nodesRightFrontOpenEdge() const; // alias, see above: nodesFrontRightOpenEdge xt::xtensor nodesRightBackOpenEdge() const; // alias, see above: nodesBackRightOpenEdge // boundary nodes: corners size_t nodesFrontBottomLeftCorner() const; // node-number of the front - bottom - left corner size_t nodesFrontBottomRightCorner() const; // node-number of the front - bottom - right corner size_t nodesFrontTopLeftCorner() const; // node-number of the front - top - left corner size_t nodesFrontTopRightCorner() const; // node-number of the front - top - right corner size_t nodesBackBottomLeftCorner() const; // node-number of the back - bottom - left corner size_t nodesBackBottomRightCorner() const; // node-number of the back - bottom - right corner size_t nodesBackTopLeftCorner() const; // node-number of the back - top - left corner size_t nodesBackTopRightCorner() const; // node-number of the back - top - right corner // boundary nodes: corners (aliases) size_t nodesFrontLeftBottomCorner() const; // alias, see above: nodesFrontBottomLeftCorner size_t nodesBottomFrontLeftCorner() const; // alias, see above: nodesFrontBottomLeftCorner size_t nodesBottomLeftFrontCorner() const; // alias, see above: nodesFrontBottomLeftCorner size_t nodesLeftFrontBottomCorner() const; // alias, see above: nodesFrontBottomLeftCorner size_t nodesLeftBottomFrontCorner() const; // alias, see above: nodesFrontBottomLeftCorner size_t nodesFrontRightBottomCorner() const; // alias, see above: nodesFrontBottomRightCorner size_t nodesBottomFrontRightCorner() const; // alias, see above: nodesFrontBottomRightCorner size_t nodesBottomRightFrontCorner() const; // alias, see above: nodesFrontBottomRightCorner size_t nodesRightFrontBottomCorner() const; // alias, see above: nodesFrontBottomRightCorner size_t nodesRightBottomFrontCorner() const; // alias, see above: nodesFrontBottomRightCorner size_t nodesFrontLeftTopCorner() const; // alias, see above: nodesFrontTopLeftCorner size_t nodesTopFrontLeftCorner() const; // alias, see above: nodesFrontTopLeftCorner size_t nodesTopLeftFrontCorner() const; // alias, see above: nodesFrontTopLeftCorner size_t nodesLeftFrontTopCorner() const; // alias, see above: nodesFrontTopLeftCorner size_t nodesLeftTopFrontCorner() const; // alias, see above: nodesFrontTopLeftCorner size_t nodesFrontRightTopCorner() const; // alias, see above: nodesFrontTopRightCorner size_t nodesTopFrontRightCorner() const; // alias, see above: nodesFrontTopRightCorner size_t nodesTopRightFrontCorner() const; // alias, see above: nodesFrontTopRightCorner size_t nodesRightFrontTopCorner() const; // alias, see above: nodesFrontTopRightCorner size_t nodesRightTopFrontCorner() const; // alias, see above: nodesFrontTopRightCorner size_t nodesBackLeftBottomCorner() const; // alias, see above: nodesBackBottomLeftCorner size_t nodesBottomBackLeftCorner() const; // alias, see above: nodesBackBottomLeftCorner size_t nodesBottomLeftBackCorner() const; // alias, see above: nodesBackBottomLeftCorner size_t nodesLeftBackBottomCorner() const; // alias, see above: nodesBackBottomLeftCorner size_t nodesLeftBottomBackCorner() const; // alias, see above: nodesBackBottomLeftCorner size_t nodesBackRightBottomCorner() const; // alias, see above: nodesBackBottomRightCorner size_t nodesBottomBackRightCorner() const; // alias, see above: nodesBackBottomRightCorner size_t nodesBottomRightBackCorner() const; // alias, see above: nodesBackBottomRightCorner size_t nodesRightBackBottomCorner() const; // alias, see above: nodesBackBottomRightCorner size_t nodesRightBottomBackCorner() const; // alias, see above: nodesBackBottomRightCorner size_t nodesBackLeftTopCorner() const; // alias, see above: nodesBackTopLeftCorner size_t nodesTopBackLeftCorner() const; // alias, see above: nodesBackTopLeftCorner size_t nodesTopLeftBackCorner() const; // alias, see above: nodesBackTopLeftCorner size_t nodesLeftBackTopCorner() const; // alias, see above: nodesBackTopLeftCorner size_t nodesLeftTopBackCorner() const; // alias, see above: nodesBackTopLeftCorner size_t nodesBackRightTopCorner() const; // alias, see above: nodesBackTopRightCorner size_t nodesTopBackRightCorner() const; // alias, see above: nodesBackTopRightCorner size_t nodesTopRightBackCorner() const; // alias, see above: nodesBackTopRightCorner size_t nodesRightBackTopCorner() const; // alias, see above: nodesBackTopRightCorner size_t nodesRightTopBackCorner() const; // alias, see above: nodesBackTopRightCorner // periodicity xt::xtensor nodesPeriodic() const; // periodic node pairs [:,2]: (independent, dependent) size_t nodesOrigin() const; // front-bottom-left node, used as reference for periodicity xt::xtensor dofs() const; // DOF-numbers for each component of each node (sequential) xt::xtensor dofsPeriodic() const; // ,, for the case that the periodicity if fully eliminated }; // ------------------------------------------------------------------------------------------------- }}} // namespace ... // ================================================================================================= #endif diff --git a/include/xGooseFEM/MeshHex8.hpp b/include/GooseFEM/MeshHex8.hpp similarity index 99% rename from include/xGooseFEM/MeshHex8.hpp rename to include/GooseFEM/MeshHex8.hpp index 85d1fbc..d731b81 100644 --- a/include/xGooseFEM/MeshHex8.hpp +++ b/include/GooseFEM/MeshHex8.hpp @@ -1,2620 +1,2620 @@ /* ================================================================================================= (c - GPLv3) T.W.J. de Geus (Tom) | tom@geus.me | www.geus.me | github.com/tdegeus/GooseFEM ================================================================================================= */ -#ifndef XGOOSEFEM_MESHHEX8_CPP -#define XGOOSEFEM_MESHHEX8_CPP +#ifndef GOOSEFEM_MESHHEX8_CPP +#define GOOSEFEM_MESHHEX8_CPP // ------------------------------------------------------------------------------------------------- #include "MeshHex8.h" // ===================================== GooseFEM::Mesh::Hex8 ====================================== -namespace xGooseFEM { +namespace GooseFEM { namespace Mesh { namespace Hex8 { // ------------------------------------------ constructor ------------------------------------------ inline Regular::Regular(size_t nelx, size_t nely, size_t nelz, double h): m_h(h), m_nelx(nelx), m_nely(nely), m_nelz(nelz) { assert( m_nelx >= 1 ); assert( m_nely >= 1 ); assert( m_nelz >= 1 ); m_nnode = (m_nelx+1) * (m_nely+1) * (m_nelz+1); m_nelem = m_nelx * m_nely * m_nelz ; } // -------------------------------------- number of elements --------------------------------------- inline size_t Regular::nelem() const { return m_nelem; } // ---------------------------------------- number of nodes ---------------------------------------- inline size_t Regular::nnode() const { return m_nnode; } // ---------------------------------- number of nodes per element ---------------------------------- inline size_t Regular::nne() const { return m_nne; } // ------------------------------------- number of dimensions -------------------------------------- inline size_t Regular::ndim() const { return m_ndim; } // --------------------------------- coordinates (nodal positions) --------------------------------- inline xt::xtensor Regular::coor() const { xt::xtensor out = xt::empty({m_nnode, m_ndim}); xt::xtensor x = xt::linspace(0.0, m_h*static_cast(m_nelx), m_nelx+1); xt::xtensor y = xt::linspace(0.0, m_h*static_cast(m_nely), m_nely+1); xt::xtensor z = xt::linspace(0.0, m_h*static_cast(m_nelz), m_nelz+1); size_t inode = 0; for ( size_t iz = 0 ; iz < m_nelz+1 ; ++iz ) { for ( size_t iy = 0 ; iy < m_nely+1 ; ++iy ) { for ( size_t ix = 0 ; ix < m_nelx+1 ; ++ix ) { out(inode,0) = x(ix); out(inode,1) = y(iy); out(inode,2) = z(iz); ++inode; } } } return out; } // ---------------------------- connectivity (node-numbers per element) ---------------------------- inline xt::xtensor Regular::conn() const { xt::xtensor out = xt::empty({m_nelem,m_nne}); size_t ielem = 0; for ( size_t iz = 0 ; iz < m_nelz ; ++iz ) { for ( size_t iy = 0 ; iy < m_nely ; ++iy ) { for ( size_t ix = 0 ; ix < m_nelx ; ++ix ) { out(ielem,0) = (iy )*(m_nelx+1) + (ix ) + (iz )*(m_nely+1)*(m_nelx+1); out(ielem,1) = (iy )*(m_nelx+1) + (ix+1) + (iz )*(m_nely+1)*(m_nelx+1); out(ielem,3) = (iy+1)*(m_nelx+1) + (ix ) + (iz )*(m_nely+1)*(m_nelx+1); out(ielem,2) = (iy+1)*(m_nelx+1) + (ix+1) + (iz )*(m_nely+1)*(m_nelx+1); out(ielem,4) = (iy )*(m_nelx+1) + (ix ) + (iz+1)*(m_nely+1)*(m_nelx+1); out(ielem,5) = (iy )*(m_nelx+1) + (ix+1) + (iz+1)*(m_nely+1)*(m_nelx+1); out(ielem,7) = (iy+1)*(m_nelx+1) + (ix ) + (iz+1)*(m_nely+1)*(m_nelx+1); out(ielem,6) = (iy+1)*(m_nelx+1) + (ix+1) + (iz+1)*(m_nely+1)*(m_nelx+1); ++ielem; } } } return out; } // ------------------------------ node-numbers along the front plane ------------------------------- inline xt::xtensor Regular::nodesFront() const { xt::xtensor out = xt::empty({(m_nelx+1)*(m_nely+1)}); for ( size_t iy = 0 ; iy < m_nely+1 ; ++iy ) for ( size_t ix = 0 ; ix < m_nelx+1 ; ++ix ) out(iy*(m_nelx+1)+ix) = iy*(m_nelx+1) + ix; return out; } // ------------------------------- node-numbers along the back plane ------------------------------- inline xt::xtensor Regular::nodesBack() const { xt::xtensor out = xt::empty({(m_nelx+1)*(m_nely+1)}); for ( size_t iy = 0 ; iy < m_nely+1 ; ++iy ) for ( size_t ix = 0 ; ix < m_nelx+1 ; ++ix ) out(iy*(m_nelx+1)+ix) = iy*(m_nelx+1) + ix + m_nelz*(m_nely+1)*(m_nelx+1); return out; } // ------------------------------- node-numbers along the left plane ------------------------------- inline xt::xtensor Regular::nodesLeft() const { xt::xtensor out = xt::empty({(m_nely+1)*(m_nelz+1)}); for ( size_t iz = 0 ; iz < m_nelz+1 ; ++iz ) for ( size_t iy = 0 ; iy < m_nely+1 ; ++iy ) out(iz*(m_nely+1)+iy) = iy*(m_nelx+1) + iz*(m_nelx+1)*(m_nely+1); return out; } // ------------------------------ node-numbers along the right plane ------------------------------- inline xt::xtensor Regular::nodesRight() const { xt::xtensor out = xt::empty({(m_nely+1)*(m_nelz+1)}); for ( size_t iz = 0 ; iz < m_nelz+1 ; ++iz ) for ( size_t iy = 0 ; iy < m_nely+1 ; ++iy ) out(iz*(m_nely+1)+iy) = iy*(m_nelx+1) + iz*(m_nelx+1)*(m_nely+1) + m_nelx; return out; } // ------------------------------ node-numbers along the bottom plane ------------------------------ inline xt::xtensor Regular::nodesBottom() const { xt::xtensor out = xt::empty({(m_nelx+1)*(m_nelz+1)}); for ( size_t iz = 0 ; iz < m_nelz+1 ; ++iz ) for ( size_t ix = 0 ; ix < m_nelx+1 ; ++ix ) out(iz*(m_nelx+1)+ix) = ix + iz*(m_nelx+1)*(m_nely+1); return out; } // ------------------------------- node-numbers along the top plane -------------------------------- inline xt::xtensor Regular::nodesTop() const { xt::xtensor out = xt::empty({(m_nelx+1)*(m_nelz+1)}); for ( size_t iz = 0 ; iz < m_nelz+1 ; ++iz ) for ( size_t ix = 0 ; ix < m_nelx+1 ; ++ix ) out(iz*(m_nelx+1)+ix) = ix + m_nely*(m_nelx+1) + iz*(m_nelx+1)*(m_nely+1); return out; } // ------------------------------- node-numbers along the front face ------------------------------- inline xt::xtensor Regular::nodesFrontFace() const { xt::xtensor out = xt::empty({(m_nelx-1)*(m_nely-1)}); for ( size_t iy = 1 ; iy < m_nely ; ++iy ) for ( size_t ix = 1 ; ix < m_nelx ; ++ix ) out((iy-1)*(m_nelx-1)+(ix-1)) = iy*(m_nelx+1) + ix; return out; } // ------------------------------- node-numbers along the back face -------------------------------- inline xt::xtensor Regular::nodesBackFace() const { xt::xtensor out = xt::empty({(m_nelx-1)*(m_nely-1)}); for ( size_t iy = 1 ; iy < m_nely ; ++iy ) { for ( size_t ix = 1 ; ix < m_nelx ; ++ix ) { out((iy-1)*(m_nelx-1)+(ix-1)) = iy*(m_nelx+1) + ix + m_nelz*(m_nely+1)*(m_nelx+1); } } return out; } // ------------------------------- node-numbers along the left face -------------------------------- inline xt::xtensor Regular::nodesLeftFace() const { xt::xtensor out = xt::empty({(m_nely-1)*(m_nelz-1)}); for ( size_t iz = 1 ; iz < m_nelz ; ++iz ) for ( size_t iy = 1 ; iy < m_nely ; ++iy ) out((iz-1)*(m_nely-1)+(iy-1)) = iy*(m_nelx+1) + iz*(m_nelx+1)*(m_nely+1); return out; } // ------------------------------- node-numbers along the right face ------------------------------- inline xt::xtensor Regular::nodesRightFace() const { xt::xtensor out = xt::empty({(m_nely-1)*(m_nelz-1)}); for ( size_t iz = 1 ; iz < m_nelz ; ++iz ) for ( size_t iy = 1 ; iy < m_nely ; ++iy ) out((iz-1)*(m_nely-1)+(iy-1)) = iy*(m_nelx+1) + iz*(m_nelx+1)*(m_nely+1) + m_nelx; return out; } // ------------------------------ node-numbers along the bottom face ------------------------------- inline xt::xtensor Regular::nodesBottomFace() const { xt::xtensor out = xt::empty({(m_nelx-1)*(m_nelz-1)}); for ( size_t iz = 1 ; iz < m_nelz ; ++iz ) for ( size_t ix = 1 ; ix < m_nelx ; ++ix ) out((iz-1)*(m_nelx-1)+(ix-1)) = ix + iz*(m_nelx+1)*(m_nely+1); return out; } // -------------------------------- node-numbers along the top face -------------------------------- inline xt::xtensor Regular::nodesTopFace() const { xt::xtensor out = xt::empty({(m_nelx-1)*(m_nelz-1)}); for ( size_t iz = 1 ; iz < m_nelz ; ++iz ) for ( size_t ix = 1 ; ix < m_nelx ; ++ix ) out((iz-1)*(m_nelx-1)+(ix-1)) = ix + m_nely*(m_nelx+1) + iz*(m_nelx+1)*(m_nely+1); return out; } // --------------------------- node-numbers along the front-bottom edge ---------------------------- inline xt::xtensor Regular::nodesFrontBottomEdge() const { xt::xtensor out = xt::empty({m_nelx+1}); for ( size_t ix = 0 ; ix < m_nelx+1 ; ++ix ) out(ix) = ix; return out; } // ----------------------------- node-numbers along the front-top edge ----------------------------- inline xt::xtensor Regular::nodesFrontTopEdge() const { xt::xtensor out = xt::empty({m_nelx+1}); for ( size_t ix = 0 ; ix < m_nelx+1 ; ++ix ) out(ix) = ix + m_nely*(m_nelx+1); return out; } // ---------------------------- node-numbers along the front-left edge ----------------------------- inline xt::xtensor Regular::nodesFrontLeftEdge() const { xt::xtensor out = xt::empty({m_nely+1}); for ( size_t iy = 0 ; iy < m_nely+1 ; ++iy ) out(iy) = iy*(m_nelx+1); return out; } // ---------------------------- node-numbers along the front-right edge ---------------------------- inline xt::xtensor Regular::nodesFrontRightEdge() const { xt::xtensor out = xt::empty({m_nely+1}); for ( size_t iy = 0 ; iy < m_nely+1 ; ++iy ) out(iy) = iy*(m_nelx+1) + m_nelx; return out; } // ---------------------------- node-numbers along the back-bottom edge ---------------------------- inline xt::xtensor Regular::nodesBackBottomEdge() const { xt::xtensor out = xt::empty({m_nelx+1}); for ( size_t ix = 0 ; ix < m_nelx+1 ; ++ix ) out(ix) = ix + m_nelz*(m_nely+1)*(m_nelx+1); return out; } // ----------------------------- node-numbers along the back-top edge ------------------------------ inline xt::xtensor Regular::nodesBackTopEdge() const { xt::xtensor out = xt::empty({m_nelx+1}); for ( size_t ix = 0 ; ix < m_nelx+1 ; ++ix ) out(ix) = m_nely*(m_nelx+1) + ix + m_nelz*(m_nely+1)*(m_nelx+1); return out; } // ----------------------------- node-numbers along the back-left edge ----------------------------- inline xt::xtensor Regular::nodesBackLeftEdge() const { xt::xtensor out = xt::empty({m_nely+1}); for ( size_t iy = 0 ; iy < m_nely+1 ; ++iy ) out(iy) = iy*(m_nelx+1) + m_nelz*(m_nelx+1)*(m_nely+1); return out; } // ---------------------------- node-numbers along the back-right edge ----------------------------- inline xt::xtensor Regular::nodesBackRightEdge() const { xt::xtensor out = xt::empty({m_nely+1}); for ( size_t iy = 0 ; iy < m_nely+1 ; ++iy ) out(iy) = iy*(m_nelx+1) + m_nelz*(m_nelx+1)*(m_nely+1) + m_nelx; return out; } // ---------------------------- node-numbers along the bottom-left edge ---------------------------- inline xt::xtensor Regular::nodesBottomLeftEdge() const { xt::xtensor out = xt::empty({m_nelz+1}); for ( size_t iz = 0 ; iz < m_nelz+1 ; ++iz ) out(iz) = iz*(m_nelx+1)*(m_nely+1); return out; } // --------------------------- node-numbers along the bottom-right edge ---------------------------- inline xt::xtensor Regular::nodesBottomRightEdge() const { xt::xtensor out = xt::empty({m_nelz+1}); for ( size_t iz = 0 ; iz < m_nelz+1 ; ++iz ) out(iz) = iz*(m_nelx+1)*(m_nely+1) + m_nelx; return out; } // ----------------------------- node-numbers along the top-left edge ------------------------------ inline xt::xtensor Regular::nodesTopLeftEdge() const { xt::xtensor out = xt::empty({m_nelz+1}); for ( size_t iz = 0 ; iz < m_nelz+1 ; ++iz ) out(iz) = m_nely*(m_nelx+1) + iz*(m_nelx+1)*(m_nely+1); return out; } // ----------------------------- node-numbers along the top-right edge ----------------------------- inline xt::xtensor Regular::nodesTopRightEdge() const { xt::xtensor out = xt::empty({m_nelz+1}); for ( size_t iz = 0 ; iz < m_nelz+1 ; ++iz ) out(iz) = m_nely*(m_nelx+1) + iz*(m_nelx+1)*(m_nely+1) + m_nelx; return out; } // -------------------------------------------- aliases -------------------------------------------- inline xt::xtensor Regular::nodesBottomFrontEdge() const { return nodesFrontBottomEdge(); } inline xt::xtensor Regular::nodesBottomBackEdge() const { return nodesBackBottomEdge(); } inline xt::xtensor Regular::nodesTopFrontEdge() const { return nodesFrontTopEdge(); } inline xt::xtensor Regular::nodesTopBackEdge() const { return nodesBackTopEdge(); } inline xt::xtensor Regular::nodesLeftBottomEdge() const { return nodesBottomLeftEdge(); } inline xt::xtensor Regular::nodesLeftFrontEdge() const { return nodesFrontLeftEdge(); } inline xt::xtensor Regular::nodesLeftBackEdge() const { return nodesBackLeftEdge(); } inline xt::xtensor Regular::nodesLeftTopEdge() const { return nodesTopLeftEdge(); } inline xt::xtensor Regular::nodesRightBottomEdge() const { return nodesBottomRightEdge(); } inline xt::xtensor Regular::nodesRightTopEdge() const { return nodesTopRightEdge(); } inline xt::xtensor Regular::nodesRightFrontEdge() const { return nodesFrontRightEdge(); } inline xt::xtensor Regular::nodesRightBackEdge() const { return nodesBackRightEdge(); } // ------------------- node-numbers along the front-bottom edge, without corners ------------------- inline xt::xtensor Regular::nodesFrontBottomOpenEdge() const { xt::xtensor out = xt::empty({m_nelx-1}); for ( size_t ix = 1 ; ix < m_nelx ; ++ix ) out(ix-1) = ix; return out; } // -------------------- node-numbers along the front-top edge, without corners --------------------- inline xt::xtensor Regular::nodesFrontTopOpenEdge() const { xt::xtensor out = xt::empty({m_nelx-1}); for ( size_t ix = 1 ; ix < m_nelx ; ++ix ) out(ix-1) = ix + m_nely*(m_nelx+1); return out; } // -------------------- node-numbers along the front-left edge, without corners -------------------- inline xt::xtensor Regular::nodesFrontLeftOpenEdge() const { xt::xtensor out = xt::empty({m_nely-1}); for ( size_t iy = 1 ; iy < m_nely ; ++iy ) out(iy-1) = iy*(m_nelx+1); return out; } // ------------------- node-numbers along the front-right edge, without corners -------------------- inline xt::xtensor Regular::nodesFrontRightOpenEdge() const { xt::xtensor out = xt::empty({m_nely-1}); for ( size_t iy = 1 ; iy < m_nely ; ++iy ) out(iy-1) = iy*(m_nelx+1) + m_nelx; return out; } // ------------------- node-numbers along the back-bottom edge, without corners -------------------- inline xt::xtensor Regular::nodesBackBottomOpenEdge() const { xt::xtensor out = xt::empty({m_nelx-1}); for ( size_t ix = 1 ; ix < m_nelx ; ++ix ) out(ix-1) = ix + m_nelz*(m_nely+1)*(m_nelx+1); return out; } // --------------------- node-numbers along the back-top edge, without corners --------------------- inline xt::xtensor Regular::nodesBackTopOpenEdge() const { xt::xtensor out = xt::empty({m_nelx-1}); for ( size_t ix = 1 ; ix < m_nelx ; ++ix ) out(ix-1) = m_nely*(m_nelx+1) + ix + m_nelz*(m_nely+1)*(m_nelx+1); return out; } // -------------------- node-numbers along the back-left edge, without corners --------------------- inline xt::xtensor Regular::nodesBackLeftOpenEdge() const { xt::xtensor out = xt::empty({m_nely-1}); for ( size_t iy = 1 ; iy < m_nely ; ++iy ) out(iy-1) = iy*(m_nelx+1) + m_nelz*(m_nelx+1)*(m_nely+1); return out; } // -------------------- node-numbers along the back-right edge, without corners -------------------- inline xt::xtensor Regular::nodesBackRightOpenEdge() const { xt::xtensor out = xt::empty({m_nely-1}); for ( size_t iy = 1 ; iy < m_nely ; ++iy ) out(iy-1) = iy*(m_nelx+1) + m_nelz*(m_nelx+1)*(m_nely+1) + m_nelx; return out; } // ------------------- node-numbers along the bottom-left edge, without corners -------------------- inline xt::xtensor Regular::nodesBottomLeftOpenEdge() const { xt::xtensor out = xt::empty({m_nelz-1}); for ( size_t iz = 1 ; iz < m_nelz ; ++iz ) out(iz-1) = iz*(m_nelx+1)*(m_nely+1); return out; } // ------------------- node-numbers along the bottom-right edge, without corners ------------------- inline xt::xtensor Regular::nodesBottomRightOpenEdge() const { xt::xtensor out = xt::empty({m_nelz-1}); for ( size_t iz = 1 ; iz < m_nelz ; ++iz ) out(iz-1) = iz*(m_nelx+1)*(m_nely+1) + m_nelx; return out; } // --------------------- node-numbers along the top-left edge, without corners --------------------- inline xt::xtensor Regular::nodesTopLeftOpenEdge() const { xt::xtensor out = xt::empty({m_nelz-1}); for ( size_t iz = 1 ; iz < m_nelz ; ++iz ) out(iz-1) = m_nely*(m_nelx+1) + iz*(m_nelx+1)*(m_nely+1); return out; } // -------------------- node-numbers along the top-right edge, without corners --------------------- inline xt::xtensor Regular::nodesTopRightOpenEdge() const { xt::xtensor out = xt::empty({m_nelz-1}); for ( size_t iz = 1 ; iz < m_nelz ; ++iz ) out(iz-1) = m_nely*(m_nelx+1) + iz*(m_nelx+1)*(m_nely+1) + m_nelx; return out; } // -------------------------------------------- aliases -------------------------------------------- inline xt::xtensor Regular::nodesBottomFrontOpenEdge() const { return nodesFrontBottomOpenEdge(); } inline xt::xtensor Regular::nodesBottomBackOpenEdge() const { return nodesBackBottomOpenEdge(); } inline xt::xtensor Regular::nodesTopFrontOpenEdge() const { return nodesFrontTopOpenEdge(); } inline xt::xtensor Regular::nodesTopBackOpenEdge() const { return nodesBackTopOpenEdge(); } inline xt::xtensor Regular::nodesLeftBottomOpenEdge() const { return nodesBottomLeftOpenEdge(); } inline xt::xtensor Regular::nodesLeftFrontOpenEdge() const { return nodesFrontLeftOpenEdge(); } inline xt::xtensor Regular::nodesLeftBackOpenEdge() const { return nodesBackLeftOpenEdge(); } inline xt::xtensor Regular::nodesLeftTopOpenEdge() const { return nodesTopLeftOpenEdge(); } inline xt::xtensor Regular::nodesRightBottomOpenEdge() const { return nodesBottomRightOpenEdge(); } inline xt::xtensor Regular::nodesRightTopOpenEdge() const { return nodesTopRightOpenEdge(); } inline xt::xtensor Regular::nodesRightFrontOpenEdge() const { return nodesFrontRightOpenEdge(); } inline xt::xtensor Regular::nodesRightBackOpenEdge() const { return nodesBackRightOpenEdge(); } // -------------------------- node-number of the front-bottom-left corner -------------------------- inline size_t Regular::nodesFrontBottomLeftCorner() const { return 0; } // ------------------------- node-number of the front-bottom-right corner -------------------------- inline size_t Regular::nodesFrontBottomRightCorner() const { return m_nelx; } // --------------------------- node-number of the front-top-left corner ---------------------------- inline size_t Regular::nodesFrontTopLeftCorner() const { return m_nely*(m_nelx+1); } // --------------------------- node-number of the front-top-right corner --------------------------- inline size_t Regular::nodesFrontTopRightCorner() const { return m_nely*(m_nelx+1) + m_nelx; } // -------------------------- node-number of the back-bottom-left corner --------------------------- inline size_t Regular::nodesBackBottomLeftCorner() const { return m_nelz*(m_nely+1)*(m_nelx+1); } // -------------------------- node-number of the back-bottom-right corner -------------------------- inline size_t Regular::nodesBackBottomRightCorner() const { return m_nelx + m_nelz*(m_nely+1)*(m_nelx+1); } // ---------------------------- node-number of the back-top-left corner ---------------------------- inline size_t Regular::nodesBackTopLeftCorner() const { return m_nely*(m_nelx+1) + m_nelz*(m_nely+1)*(m_nelx+1); } // --------------------------- node-number of the back-top-right corner ---------------------------- inline size_t Regular::nodesBackTopRightCorner() const { return m_nely*(m_nelx+1) + m_nelx + m_nelz*(m_nely+1)*(m_nelx+1); } // -------------------------------------------- aliases -------------------------------------------- inline size_t Regular::nodesFrontLeftBottomCorner() const { return nodesFrontBottomLeftCorner(); } inline size_t Regular::nodesBottomFrontLeftCorner() const { return nodesFrontBottomLeftCorner(); } inline size_t Regular::nodesBottomLeftFrontCorner() const { return nodesFrontBottomLeftCorner(); } inline size_t Regular::nodesLeftFrontBottomCorner() const { return nodesFrontBottomLeftCorner(); } inline size_t Regular::nodesLeftBottomFrontCorner() const { return nodesFrontBottomLeftCorner(); } inline size_t Regular::nodesFrontRightBottomCorner()const { return nodesFrontBottomRightCorner(); } inline size_t Regular::nodesBottomFrontRightCorner()const { return nodesFrontBottomRightCorner(); } inline size_t Regular::nodesBottomRightFrontCorner()const { return nodesFrontBottomRightCorner(); } inline size_t Regular::nodesRightFrontBottomCorner()const { return nodesFrontBottomRightCorner(); } inline size_t Regular::nodesRightBottomFrontCorner()const { return nodesFrontBottomRightCorner(); } inline size_t Regular::nodesFrontLeftTopCorner() const { return nodesFrontTopLeftCorner(); } inline size_t Regular::nodesTopFrontLeftCorner() const { return nodesFrontTopLeftCorner(); } inline size_t Regular::nodesTopLeftFrontCorner() const { return nodesFrontTopLeftCorner(); } inline size_t Regular::nodesLeftFrontTopCorner() const { return nodesFrontTopLeftCorner(); } inline size_t Regular::nodesLeftTopFrontCorner() const { return nodesFrontTopLeftCorner(); } inline size_t Regular::nodesFrontRightTopCorner() const { return nodesFrontTopRightCorner(); } inline size_t Regular::nodesTopFrontRightCorner() const { return nodesFrontTopRightCorner(); } inline size_t Regular::nodesTopRightFrontCorner() const { return nodesFrontTopRightCorner(); } inline size_t Regular::nodesRightFrontTopCorner() const { return nodesFrontTopRightCorner(); } inline size_t Regular::nodesRightTopFrontCorner() const { return nodesFrontTopRightCorner(); } inline size_t Regular::nodesBackLeftBottomCorner() const { return nodesBackBottomLeftCorner(); } inline size_t Regular::nodesBottomBackLeftCorner() const { return nodesBackBottomLeftCorner(); } inline size_t Regular::nodesBottomLeftBackCorner() const { return nodesBackBottomLeftCorner(); } inline size_t Regular::nodesLeftBackBottomCorner() const { return nodesBackBottomLeftCorner(); } inline size_t Regular::nodesLeftBottomBackCorner() const { return nodesBackBottomLeftCorner(); } inline size_t Regular::nodesBackRightBottomCorner() const { return nodesBackBottomRightCorner(); } inline size_t Regular::nodesBottomBackRightCorner() const { return nodesBackBottomRightCorner(); } inline size_t Regular::nodesBottomRightBackCorner() const { return nodesBackBottomRightCorner(); } inline size_t Regular::nodesRightBackBottomCorner() const { return nodesBackBottomRightCorner(); } inline size_t Regular::nodesRightBottomBackCorner() const { return nodesBackBottomRightCorner(); } inline size_t Regular::nodesBackLeftTopCorner() const { return nodesBackTopLeftCorner(); } inline size_t Regular::nodesTopBackLeftCorner() const { return nodesBackTopLeftCorner(); } inline size_t Regular::nodesTopLeftBackCorner() const { return nodesBackTopLeftCorner(); } inline size_t Regular::nodesLeftBackTopCorner() const { return nodesBackTopLeftCorner(); } inline size_t Regular::nodesLeftTopBackCorner() const { return nodesBackTopLeftCorner(); } inline size_t Regular::nodesBackRightTopCorner() const { return nodesBackTopRightCorner(); } inline size_t Regular::nodesTopBackRightCorner() const { return nodesBackTopRightCorner(); } inline size_t Regular::nodesTopRightBackCorner() const { return nodesBackTopRightCorner(); } inline size_t Regular::nodesRightBackTopCorner() const { return nodesBackTopRightCorner(); } inline size_t Regular::nodesRightTopBackCorner() const { return nodesBackTopRightCorner(); } // ------------------------------ node-numbers of periodic node-pairs ------------------------------ inline xt::xtensor Regular::nodesPeriodic() const { // faces xt::xtensor fro = nodesFrontFace(); xt::xtensor bck = nodesBackFace(); xt::xtensor lft = nodesLeftFace(); xt::xtensor rgt = nodesRightFace(); xt::xtensor bot = nodesBottomFace(); xt::xtensor top = nodesTopFace(); // edges xt::xtensor froBot = nodesFrontBottomOpenEdge(); xt::xtensor froTop = nodesFrontTopOpenEdge(); xt::xtensor froLft = nodesFrontLeftOpenEdge(); xt::xtensor froRgt = nodesFrontRightOpenEdge(); xt::xtensor bckBot = nodesBackBottomOpenEdge(); xt::xtensor bckTop = nodesBackTopOpenEdge(); xt::xtensor bckLft = nodesBackLeftOpenEdge(); xt::xtensor bckRgt = nodesBackRightOpenEdge(); xt::xtensor botLft = nodesBottomLeftOpenEdge(); xt::xtensor botRgt = nodesBottomRightOpenEdge(); xt::xtensor topLft = nodesTopLeftOpenEdge(); xt::xtensor topRgt = nodesTopRightOpenEdge(); // allocate nodal ties // - number of tying per category size_t tface = fro.size() + lft.size() + bot.size(); size_t tedge = 3*froBot.size() + 3*froLft.size() + 3*botLft.size(); size_t tnode = 7; // - allocate xt::xtensor out = xt::empty({tface+tedge+tnode, std::size_t(2)}); // counter size_t i = 0; // tie all corners to one corner out(i,0) = nodesFrontBottomLeftCorner(); out(i,1) = nodesFrontBottomRightCorner(); ++i; out(i,0) = nodesFrontBottomLeftCorner(); out(i,1) = nodesBackBottomRightCorner(); ++i; out(i,0) = nodesFrontBottomLeftCorner(); out(i,1) = nodesBackBottomLeftCorner(); ++i; out(i,0) = nodesFrontBottomLeftCorner(); out(i,1) = nodesFrontTopLeftCorner(); ++i; out(i,0) = nodesFrontBottomLeftCorner(); out(i,1) = nodesFrontTopRightCorner(); ++i; out(i,0) = nodesFrontBottomLeftCorner(); out(i,1) = nodesBackTopRightCorner(); ++i; out(i,0) = nodesFrontBottomLeftCorner(); out(i,1) = nodesBackTopLeftCorner(); ++i; // tie all corresponding edges to each other (exclude corners) for ( size_t j = 0 ; j Regular::dofs() const { - return xGooseFEM::Mesh::dofs(m_nnode,m_ndim); + return GooseFEM::Mesh::dofs(m_nnode,m_ndim); } // ------------------------ DOP-numbers with periodic dependencies removed ------------------------- inline xt::xtensor Regular::dofsPeriodic() const { // DOF-numbers for each component of each node (sequential) - xt::xtensor out = xGooseFEM::Mesh::dofs(m_nnode,m_ndim); + xt::xtensor out = GooseFEM::Mesh::dofs(m_nnode,m_ndim); // periodic node-pairs xt::xtensor nodePer = nodesPeriodic(); // eliminate 'dependent' DOFs; renumber "out" to be sequential for the remaining DOFs for ( size_t i = 0 ; i < nodePer.shape()[0] ; ++i ) for ( size_t j = 0 ; j < m_ndim ; ++j ) out(nodePer(i,1),j) = out(nodePer(i,0),j); // renumber "out" to be sequential - return xGooseFEM::Mesh::renumber(out); + return GooseFEM::Mesh::renumber(out); } // ------------------------------------------ constructor ------------------------------------------ inline FineLayer::FineLayer(size_t nelx, size_t nely, size_t nelz, double h, size_t nfine): m_h(h) { // basic assumptions assert( nelx >= 1 ); assert( nely >= 1 ); assert( nelz >= 1 ); // store basic info m_Lx = m_h * static_cast(nelx); m_Lz = m_h * static_cast(nelz); // compute element size in y-direction (use symmetry, compute upper half) // ---------------------------------------------------------------------- // temporary variables size_t nmin, ntot; xt::xtensor nhx = xt::ones({nely}); xt::xtensor nhy = xt::ones({nely}); xt::xtensor nhz = xt::ones({nely}); xt::xtensor refine = -1 * xt::ones ({nely}); // minimum height in y-direction (half of the height because of symmetry) if ( nely % 2 == 0 ) nmin = nely /2; else nmin = (nely +1)/2; // minimum number of fine layers in y-direction (minimum 1, middle layer part of this half) if ( nfine % 2 == 0 ) nfine = nfine /2 + 1; else nfine = (nfine+1)/2; if ( nfine < 1 ) nfine = 1; if ( nfine > nmin ) nfine = nmin; // loop over element layers in y-direction, try to coarsen using these rules: // (1) element size in y-direction <= distance to origin in y-direction // (2) element size in x-(z-)direction should fit the total number of elements in x-(z-)direction // (3) a certain number of layers have the minimum size "1" (are fine) for ( size_t iy = nfine ; ; ) { // initialize current size in y-direction if ( iy == nfine ) ntot = nfine; // check to stop if ( iy >= nely or ntot >= nmin ) { nely = iy; break; } // rules (1,2) satisfied: coarsen in x-direction (and z-direction) if ( 3*nhy(iy) <= ntot and nelx%(3*nhx(iy)) == 0 and ntot+nhy(iy) < nmin ) { // - process refinement in x-direction refine(iy) = 0; nhy (iy) *= 2; auto vnhy = xt::view(nhy, xt::range(iy+1, _)); auto vnhx = xt::view(nhx, xt::range(iy , _)); vnhy *= 3; vnhx *= 3; // - rule (2) satisfied: coarsen next element layer in z-direction if ( iy+1 < nely and ntot+2*nhy(iy) < nmin ) { if ( nelz%(3*nhz(iy+1)) == 0 ) { // - update the number of elements in y-direction ntot += nhy(iy); // - proceed to next element layer in y-direction ++iy; // - process refinement in z-direction refine(iy) = 2; nhy (iy) = nhy(iy-1); auto vnhz = xt::view(nhz, xt::range(iy, _)); vnhz *= 3; } } } // rules (1,2) satisfied: coarse in z-direction else if ( 3*nhy(iy) <= ntot and nelz%(3*nhz(iy)) == 0 and ntot+nhy(iy) < nmin ) { // - process refinement in z-direction refine(iy) = 2; nhy (iy) *= 2; auto vnhy = xt::view(nhy, xt::range(iy+1, _)); auto vnhz = xt::view(nhz, xt::range(iy , _)); vnhy *= 3; vnhz *= 3; } // update the number of elements in y-direction ntot += nhy(iy); // proceed to next element layer in y-direction ++iy; // check to stop if ( iy >= nely or ntot >= nmin ) { nely = iy; break; } } // symmetrize, compute full information // ------------------------------------ // allocate mesh constructor parameters m_nhx = xt::empty({nely*2-1}); m_nhy = xt::empty({nely*2-1}); m_nhz = xt::empty({nely*2-1}); m_refine = xt::empty ({nely*2-1}); m_nelx = xt::empty({nely*2-1}); m_nelz = xt::empty({nely*2-1}); m_nnd = xt::empty({nely*2 }); m_startElem = xt::empty({nely*2-1}); m_startNode = xt::empty({nely*2 }); // fill // - lower half for ( size_t iy = 0 ; iy < nely ; ++iy ) { m_nhx (iy) = nhx (nely-iy-1); m_nhy (iy) = nhy (nely-iy-1); m_nhz (iy) = nhz (nely-iy-1); m_refine(iy) = refine(nely-iy-1); } // - upper half for ( size_t iy = 0 ; iy < nely-1 ; ++iy ) { m_nhx (iy+nely) = nhx (iy+1); m_nhy (iy+nely) = nhy (iy+1); m_nhz (iy+nely) = nhz (iy+1); m_refine(iy+nely) = refine(iy+1); } // update size nely = m_nhx.size(); // compute the number of elements per element layer in y-direction for ( size_t iy = 0 ; iy < nely ; ++iy ) { m_nelx(iy) = nelx / m_nhx(iy); m_nelz(iy) = nelz / m_nhz(iy); } // compute the number of nodes per node layer in y-direction // - bottom half for ( size_t iy = 0 ; iy < (nely+1)/2 ; ++iy ) m_nnd(iy) = (m_nelx(iy)+1) * (m_nelz(iy)+1); // - top half for ( size_t iy = (nely-1)/2 ; iy < nely ; ++iy ) m_nnd(iy+1) = (m_nelx(iy)+1) * (m_nelz(iy)+1); // compute mesh dimensions // ----------------------- // initialize m_nnode = 0; m_nelem = 0; m_startNode(0) = 0; // loop over element layers (bottom -> middle, elements become finer) for ( size_t i = 0 ; i < (nely-1)/2 ; ++i ) { // - store the first element of the layer m_startElem(i) = m_nelem; // - add the nodes of this layer if ( m_refine(i) == 0 ) { m_nnode += (3*m_nelx(i)+1) * ( m_nelz(i)+1); } else if ( m_refine(i) == 2 ) { m_nnode += ( m_nelx(i)+1) * (3*m_nelz(i)+1); } else { m_nnode += ( m_nelx(i)+1) * ( m_nelz(i)+1); } // - add the elements of this layer if ( m_refine(i) == 0 ) { m_nelem += (4*m_nelx(i) ) * ( m_nelz(i) ); } else if ( m_refine(i) == 2 ) { m_nelem += ( m_nelx(i) ) * (4*m_nelz(i) ); } else { m_nelem += ( m_nelx(i) ) * ( m_nelz(i) ); } // - store the starting node of the next layer m_startNode(i+1) = m_nnode; } // loop over element layers (middle -> top, elements become coarser) for ( size_t i = (nely-1)/2 ; i < nely ; ++i ) { // - store the first element of the layer m_startElem(i) = m_nelem; // - add the nodes of this layer if ( m_refine(i) == 0 ) { m_nnode += (5*m_nelx(i)+1) * ( m_nelz(i)+1); } else if ( m_refine(i) == 2 ) { m_nnode += ( m_nelx(i)+1) * (5*m_nelz(i)+1); } else { m_nnode += ( m_nelx(i)+1) * ( m_nelz(i)+1); } // - add the elements of this layer if ( m_refine(i) == 0 ) { m_nelem += (4*m_nelx(i) ) * ( m_nelz(i) ); } else if ( m_refine(i) == 2 ) { m_nelem += ( m_nelx(i) ) * (4*m_nelz(i) ); } else { m_nelem += ( m_nelx(i) ) * ( m_nelz(i) ); } // - store the starting node of the next layer m_startNode(i+1) = m_nnode; } // - add the top row of nodes m_nnode += (m_nelx(nely-1)+1) * (m_nelz(nely-1)+1); } // -------------------------------------- number of elements --------------------------------------- inline size_t FineLayer::nelem() const { return m_nelem; } // ---------------------------------------- number of nodes ---------------------------------------- inline size_t FineLayer::nnode() const { return m_nnode; } // ---------------------------------- number of nodes per element ---------------------------------- inline size_t FineLayer::nne() const { return m_nne; } // ------------------------------------- number of dimensions -------------------------------------- inline size_t FineLayer::ndim() const { return m_ndim; } // ---------------------------- actual number of nodes in one direction ---------------------------- inline size_t FineLayer::shape(size_t i) const { assert( i >= 0 and i <= 2 ); if ( i == 0 ) return xt::amax(m_nelx)[0]; else if ( i == 2 ) return xt::amax(m_nelz)[0]; else return xt::sum (m_nhy )[0]; } // --------------------------------- coordinates (nodal positions) --------------------------------- inline xt::xtensor FineLayer::coor() const { // allocate output xt::xtensor out = xt::empty({m_nnode, m_ndim}); // current node, number of element layers size_t inode = 0; size_t nely = static_cast(m_nhy.size()); // y-position of each main node layer (i.e. excluding node layers for refinement/coarsening) // - allocate xt::xtensor y = xt::empty({nely+1}); // - initialize y(0) = 0.0; // - compute for ( size_t iy = 1 ; iy < nely+1 ; ++iy ) y(iy) = y(iy-1) + m_nhy(iy-1) * m_h; // loop over element layers (bottom -> middle) : add bottom layer (+ refinement layer) of nodes // -------------------------------------------------------------------------------------------- for ( size_t iy = 0 ; ; ++iy ) { // get positions along the x- and z-axis xt::xtensor x = xt::linspace(0.0, m_Lx, m_nelx(iy)+1); xt::xtensor z = xt::linspace(0.0, m_Lz, m_nelz(iy)+1); // add nodes of the bottom layer of this element for ( size_t iz = 0 ; iz < m_nelz(iy)+1 ; ++iz ) { for ( size_t ix = 0 ; ix < m_nelx(iy)+1 ; ++ix ) { out(inode,0) = x(ix); out(inode,1) = y(iy); out(inode,2) = z(iz); ++inode; } } // stop at middle layer if ( iy == (nely-1)/2 ) break; // add extra nodes of the intermediate layer, for refinement in x-direction if ( m_refine(iy) == 0 ) { // - get position offset in x- and y-direction double dx = m_h * static_cast(m_nhx(iy)/3); double dy = m_h * static_cast(m_nhy(iy)/2); // - add nodes of the intermediate layer for ( size_t iz = 0 ; iz < m_nelz(iy)+1 ; ++iz ) { for ( size_t ix = 0 ; ix < m_nelx(iy) ; ++ix ) { for ( size_t j = 0 ; j < 2 ; ++j ) { out(inode,0) = x(ix) + dx * static_cast(j+1); out(inode,1) = y(iy) + dy; out(inode,2) = z(iz); ++inode; } } } } // add extra nodes of the intermediate layer, for refinement in z-direction else if ( m_refine(iy) == 2 ) { // - get position offset in y- and z-direction double dz = m_h * static_cast(m_nhz(iy)/3); double dy = m_h * static_cast(m_nhy(iy)/2); // - add nodes of the intermediate layer for ( size_t iz = 0 ; iz < m_nelz(iy) ; ++iz ) { for ( size_t j = 0 ; j < 2 ; ++j ) { for ( size_t ix = 0 ; ix < m_nelx(iy)+1 ; ++ix ) { out(inode,0) = x(ix); out(inode,1) = y(iy) + dy; out(inode,2) = z(iz) + dz * static_cast(j+1); ++inode; } } } } } // loop over element layers (middle -> top) : add (refinement layer +) top layer of nodes // -------------------------------------------------------------------------------------- for ( size_t iy = (nely-1)/2 ; iy < nely ; ++iy ) { // get positions along the x- and z-axis xt::xtensor x = xt::linspace(0.0, m_Lx, m_nelx(iy)+1); xt::xtensor z = xt::linspace(0.0, m_Lz, m_nelz(iy)+1); // add extra nodes of the intermediate layer, for refinement in x-direction if ( m_refine(iy) == 0 ) { // - get position offset in x- and y-direction double dx = m_h * static_cast(m_nhx(iy)/3); double dy = m_h * static_cast(m_nhy(iy)/2); // - add nodes of the intermediate layer for ( size_t iz = 0 ; iz < m_nelz(iy)+1 ; ++iz ) { for ( size_t ix = 0 ; ix < m_nelx(iy) ; ++ix ) { for ( size_t j = 0 ; j < 2 ; ++j ) { out(inode,0) = x(ix) + dx * static_cast(j+1); out(inode,1) = y(iy) + dy; out(inode,2) = z(iz); ++inode; } } } } // add extra nodes of the intermediate layer, for refinement in z-direction else if ( m_refine(iy) == 2 ) { // - get position offset in y- and z-direction double dz = m_h * static_cast(m_nhz(iy)/3); double dy = m_h * static_cast(m_nhy(iy)/2); // - add nodes of the intermediate layer for ( size_t iz = 0 ; iz < m_nelz(iy) ; ++iz ) { for ( size_t j = 0 ; j < 2 ; ++j ) { for ( size_t ix = 0 ; ix < m_nelx(iy)+1 ; ++ix ) { out(inode,0) = x(ix); out(inode,1) = y(iy) + dy; out(inode,2) = z(iz) + dz * static_cast(j+1); ++inode; } } } } // add nodes of the top layer of this element for ( size_t iz = 0 ; iz < m_nelz(iy)+1 ; ++iz ) { for ( size_t ix = 0 ; ix < m_nelx(iy)+1 ; ++ix ) { out(inode,0) = x(ix ); out(inode,1) = y(iy+1); out(inode,2) = z(iz ); ++inode; } } } return out; } // ---------------------------- connectivity (node-numbers per element) ---------------------------- inline xt::xtensor FineLayer::conn() const { // allocate output xt::xtensor out = xt::empty({m_nelem, m_nne}); // current element, number of element layers, starting nodes of each node layer size_t ielem = 0; size_t nely = static_cast(m_nhy.size()); size_t bot,mid,top; // loop over all element layers for ( size_t iy = 0 ; iy < nely ; ++iy ) { // - get: starting nodes of bottom(, middle) and top layer bot = m_startNode(iy ); mid = m_startNode(iy ) + m_nnd(iy); top = m_startNode(iy+1); // - define connectivity: no coarsening/refinement if ( m_refine(iy) == -1 ) { for ( size_t iz = 0 ; iz < m_nelz(iy) ; ++iz ) { for ( size_t ix = 0 ; ix < m_nelx(iy) ; ++ix ) { out(ielem,0) = bot + (ix ) + (iz ) * (m_nelx(iy)+1); out(ielem,1) = bot + (ix+1) + (iz ) * (m_nelx(iy)+1); out(ielem,2) = top + (ix+1) + (iz ) * (m_nelx(iy)+1); out(ielem,3) = top + (ix ) + (iz ) * (m_nelx(iy)+1); out(ielem,4) = bot + (ix ) + (iz+1) * (m_nelx(iy)+1); out(ielem,5) = bot + (ix+1) + (iz+1) * (m_nelx(iy)+1); out(ielem,6) = top + (ix+1) + (iz+1) * (m_nelx(iy)+1); out(ielem,7) = top + (ix ) + (iz+1) * (m_nelx(iy)+1); ielem++; } } } // - define connectivity: refinement along the x-direction (below the middle layer) else if ( m_refine(iy) == 0 and iy <= (nely-1)/2 ) { for ( size_t iz = 0 ; iz < m_nelz(iy) ; ++iz ) { for ( size_t ix = 0 ; ix < m_nelx(iy) ; ++ix ) { // -- bottom element out(ielem,0) = bot + ( ix ) + (iz ) * ( m_nelx(iy)+1); out(ielem,1) = bot + ( ix+1) + (iz ) * ( m_nelx(iy)+1); out(ielem,2) = mid + (2*ix+1) + (iz ) * (2*m_nelx(iy) ); out(ielem,3) = mid + (2*ix ) + (iz ) * (2*m_nelx(iy) ); out(ielem,4) = bot + ( ix ) + (iz+1) * ( m_nelx(iy)+1); out(ielem,5) = bot + ( ix+1) + (iz+1) * ( m_nelx(iy)+1); out(ielem,6) = mid + (2*ix+1) + (iz+1) * (2*m_nelx(iy) ); out(ielem,7) = mid + (2*ix ) + (iz+1) * (2*m_nelx(iy) ); ielem++; // -- top-right element out(ielem,0) = bot + ( ix+1) + (iz ) * ( m_nelx(iy)+1); out(ielem,1) = top + (3*ix+3) + (iz ) * (3*m_nelx(iy)+1); out(ielem,2) = top + (3*ix+2) + (iz ) * (3*m_nelx(iy)+1); out(ielem,3) = mid + (2*ix+1) + (iz ) * (2*m_nelx(iy) ); out(ielem,4) = bot + ( ix+1) + (iz+1) * ( m_nelx(iy)+1); out(ielem,5) = top + (3*ix+3) + (iz+1) * (3*m_nelx(iy)+1); out(ielem,6) = top + (3*ix+2) + (iz+1) * (3*m_nelx(iy)+1); out(ielem,7) = mid + (2*ix+1) + (iz+1) * (2*m_nelx(iy) ); ielem++; // -- top-center element out(ielem,0) = mid + (2*ix ) + (iz ) * (2*m_nelx(iy) ); out(ielem,1) = mid + (2*ix+1) + (iz ) * (2*m_nelx(iy) ); out(ielem,2) = top + (3*ix+2) + (iz ) * (3*m_nelx(iy)+1); out(ielem,3) = top + (3*ix+1) + (iz ) * (3*m_nelx(iy)+1); out(ielem,4) = mid + (2*ix ) + (iz+1) * (2*m_nelx(iy) ); out(ielem,5) = mid + (2*ix+1) + (iz+1) * (2*m_nelx(iy) ); out(ielem,6) = top + (3*ix+2) + (iz+1) * (3*m_nelx(iy)+1); out(ielem,7) = top + (3*ix+1) + (iz+1) * (3*m_nelx(iy)+1); ielem++; // -- top-left element out(ielem,0) = bot + ( ix ) + (iz ) * ( m_nelx(iy)+1); out(ielem,1) = mid + (2*ix ) + (iz ) * (2*m_nelx(iy) ); out(ielem,2) = top + (3*ix+1) + (iz ) * (3*m_nelx(iy)+1); out(ielem,3) = top + (3*ix ) + (iz ) * (3*m_nelx(iy)+1); out(ielem,4) = bot + ( ix ) + (iz+1) * ( m_nelx(iy)+1); out(ielem,5) = mid + (2*ix ) + (iz+1) * (2*m_nelx(iy) ); out(ielem,6) = top + (3*ix+1) + (iz+1) * (3*m_nelx(iy)+1); out(ielem,7) = top + (3*ix ) + (iz+1) * (3*m_nelx(iy)+1); ielem++; } } } // - define connectivity: coarsening along the x-direction (above the middle layer) else if ( m_refine(iy) == 0 and iy > (nely-1)/2 ) { for ( size_t iz = 0 ; iz < m_nelz(iy) ; ++iz ) { for ( size_t ix = 0 ; ix < m_nelx(iy) ; ++ix ) { // -- lower-left element out(ielem,0) = bot + (3*ix ) + (iz ) * (3*m_nelx(iy)+1); out(ielem,1) = bot + (3*ix+1) + (iz ) * (3*m_nelx(iy)+1); out(ielem,2) = mid + (2*ix ) + (iz ) * (2*m_nelx(iy) ); out(ielem,3) = top + ( ix ) + (iz ) * ( m_nelx(iy)+1); out(ielem,4) = bot + (3*ix ) + (iz+1) * (3*m_nelx(iy)+1); out(ielem,5) = bot + (3*ix+1) + (iz+1) * (3*m_nelx(iy)+1); out(ielem,6) = mid + (2*ix ) + (iz+1) * (2*m_nelx(iy) ); out(ielem,7) = top + ( ix ) + (iz+1) * ( m_nelx(iy)+1); ielem++; // -- lower-center element out(ielem,0) = bot + (3*ix+1) + (iz ) * (3*m_nelx(iy)+1); out(ielem,1) = bot + (3*ix+2) + (iz ) * (3*m_nelx(iy)+1); out(ielem,2) = mid + (2*ix+1) + (iz ) * (2*m_nelx(iy) ); out(ielem,3) = mid + (2*ix ) + (iz ) * (2*m_nelx(iy) ); out(ielem,4) = bot + (3*ix+1) + (iz+1) * (3*m_nelx(iy)+1); out(ielem,5) = bot + (3*ix+2) + (iz+1) * (3*m_nelx(iy)+1); out(ielem,6) = mid + (2*ix+1) + (iz+1) * (2*m_nelx(iy) ); out(ielem,7) = mid + (2*ix ) + (iz+1) * (2*m_nelx(iy) ); ielem++; // -- lower-right element out(ielem,0) = bot + (3*ix+2) + (iz ) * (3*m_nelx(iy)+1); out(ielem,1) = bot + (3*ix+3) + (iz ) * (3*m_nelx(iy)+1); out(ielem,2) = top + ( ix+1) + (iz ) * ( m_nelx(iy)+1); out(ielem,3) = mid + (2*ix+1) + (iz ) * (2*m_nelx(iy) ); out(ielem,4) = bot + (3*ix+2) + (iz+1) * (3*m_nelx(iy)+1); out(ielem,5) = bot + (3*ix+3) + (iz+1) * (3*m_nelx(iy)+1); out(ielem,6) = top + ( ix+1) + (iz+1) * ( m_nelx(iy)+1); out(ielem,7) = mid + (2*ix+1) + (iz+1) * (2*m_nelx(iy) ); ielem++; // -- upper element out(ielem,0) = mid + (2*ix ) + (iz ) * (2*m_nelx(iy) ); out(ielem,1) = mid + (2*ix+1) + (iz ) * (2*m_nelx(iy) ); out(ielem,2) = top + ( ix+1) + (iz ) * ( m_nelx(iy)+1); out(ielem,3) = top + ( ix ) + (iz ) * ( m_nelx(iy)+1); out(ielem,4) = mid + (2*ix ) + (iz+1) * (2*m_nelx(iy) ); out(ielem,5) = mid + (2*ix+1) + (iz+1) * (2*m_nelx(iy) ); out(ielem,6) = top + ( ix+1) + (iz+1) * ( m_nelx(iy)+1); out(ielem,7) = top + ( ix ) + (iz+1) * ( m_nelx(iy)+1); ielem++; } } } // - define connectivity: refinement along the z-direction (below the middle layer) else if ( m_refine(iy) == 2 and iy <= (nely-1)/2 ) { for ( size_t iz = 0 ; iz < m_nelz(iy) ; ++iz ) { for ( size_t ix = 0 ; ix < m_nelx(iy) ; ++ix ) { // -- bottom element out(ielem,0) = bot + (ix ) + iz * (m_nelx(iy)+1); out(ielem,1) = bot + (ix ) + ( iz+1) * (m_nelx(iy)+1); out(ielem,2) = bot + (ix+1) + ( iz+1) * (m_nelx(iy)+1); out(ielem,3) = bot + (ix+1) + iz * (m_nelx(iy)+1); out(ielem,4) = mid + (ix ) + 2*iz * (m_nelx(iy)+1); out(ielem,5) = mid + (ix ) + (2*iz+1) * (m_nelx(iy)+1); out(ielem,6) = mid + (ix+1) + (2*iz+1) * (m_nelx(iy)+1); out(ielem,7) = mid + (ix+1) + 2*iz * (m_nelx(iy)+1); ielem++; // -- top-back element out(ielem,0) = mid + (ix ) + (2*iz+1) * (m_nelx(iy)+1); out(ielem,1) = mid + (ix+1) + (2*iz+1) * (m_nelx(iy)+1); out(ielem,2) = top + (ix+1) + (3*iz+2) * (m_nelx(iy)+1); out(ielem,3) = top + (ix ) + (3*iz+2) * (m_nelx(iy)+1); out(ielem,4) = bot + (ix ) + ( iz+1) * (m_nelx(iy)+1); out(ielem,5) = bot + (ix+1) + ( iz+1) * (m_nelx(iy)+1); out(ielem,6) = top + (ix+1) + (3*iz+3) * (m_nelx(iy)+1); out(ielem,7) = top + (ix ) + (3*iz+3) * (m_nelx(iy)+1); ielem++; // -- top-center element out(ielem,0) = mid + (ix ) + (2*iz ) * (m_nelx(iy)+1); out(ielem,1) = mid + (ix+1) + (2*iz ) * (m_nelx(iy)+1); out(ielem,2) = top + (ix+1) + (3*iz+1) * (m_nelx(iy)+1); out(ielem,3) = top + (ix ) + (3*iz+1) * (m_nelx(iy)+1); out(ielem,4) = mid + (ix ) + (2*iz+1) * (m_nelx(iy)+1); out(ielem,5) = mid + (ix+1) + (2*iz+1) * (m_nelx(iy)+1); out(ielem,6) = top + (ix+1) + (3*iz+2) * (m_nelx(iy)+1); out(ielem,7) = top + (ix ) + (3*iz+2) * (m_nelx(iy)+1); ielem++; // -- top-front element out(ielem,0) = bot + (ix ) + ( iz ) * (m_nelx(iy)+1); out(ielem,1) = bot + (ix+1) + ( iz ) * (m_nelx(iy)+1); out(ielem,2) = top + (ix+1) + (3*iz ) * (m_nelx(iy)+1); out(ielem,3) = top + (ix ) + (3*iz ) * (m_nelx(iy)+1); out(ielem,4) = mid + (ix ) + (2*iz ) * (m_nelx(iy)+1); out(ielem,5) = mid + (ix+1) + (2*iz ) * (m_nelx(iy)+1); out(ielem,6) = top + (ix+1) + (3*iz+1) * (m_nelx(iy)+1); out(ielem,7) = top + (ix ) + (3*iz+1) * (m_nelx(iy)+1); ielem++; } } } // - define connectivity: coarsening along the z-direction (above the middle layer) else if ( m_refine(iy) == 2 and iy > (nely-1)/2 ) { for ( size_t iz = 0 ; iz < m_nelz(iy) ; ++iz ) { for ( size_t ix = 0 ; ix < m_nelx(iy) ; ++ix ) { // -- bottom-front element out(ielem,0) = bot + (ix ) + (3*iz ) * (m_nelx(iy)+1); out(ielem,1) = bot + (ix+1) + (3*iz ) * (m_nelx(iy)+1); out(ielem,2) = top + (ix+1) + ( iz ) * (m_nelx(iy)+1); out(ielem,3) = top + (ix ) + ( iz ) * (m_nelx(iy)+1); out(ielem,4) = bot + (ix ) + (3*iz+1) * (m_nelx(iy)+1); out(ielem,5) = bot + (ix+1) + (3*iz+1) * (m_nelx(iy)+1); out(ielem,6) = mid + (ix+1) + (2*iz ) * (m_nelx(iy)+1); out(ielem,7) = mid + (ix ) + (2*iz ) * (m_nelx(iy)+1); ielem++; // -- bottom-center element out(ielem,0) = bot + (ix ) + (3*iz+1) * (m_nelx(iy)+1); out(ielem,1) = bot + (ix+1) + (3*iz+1) * (m_nelx(iy)+1); out(ielem,2) = mid + (ix+1) + (2*iz ) * (m_nelx(iy)+1); out(ielem,3) = mid + (ix ) + (2*iz ) * (m_nelx(iy)+1); out(ielem,4) = bot + (ix ) + (3*iz+2) * (m_nelx(iy)+1); out(ielem,5) = bot + (ix+1) + (3*iz+2) * (m_nelx(iy)+1); out(ielem,6) = mid + (ix+1) + (2*iz+1) * (m_nelx(iy)+1); out(ielem,7) = mid + (ix ) + (2*iz+1) * (m_nelx(iy)+1); ielem++; // -- bottom-back element out(ielem,0) = bot + (ix ) + (3*iz+2) * (m_nelx(iy)+1); out(ielem,1) = bot + (ix+1) + (3*iz+2) * (m_nelx(iy)+1); out(ielem,2) = mid + (ix+1) + (2*iz+1) * (m_nelx(iy)+1); out(ielem,3) = mid + (ix ) + (2*iz+1) * (m_nelx(iy)+1); out(ielem,4) = bot + (ix ) + (3*iz+3) * (m_nelx(iy)+1); out(ielem,5) = bot + (ix+1) + (3*iz+3) * (m_nelx(iy)+1); out(ielem,6) = top + (ix+1) + ( iz+1) * (m_nelx(iy)+1); out(ielem,7) = top + (ix ) + ( iz+1) * (m_nelx(iy)+1); ielem++; // -- top element out(ielem,0) = mid + (ix ) + (2*iz ) * (m_nelx(iy)+1); out(ielem,1) = mid + (ix+1) + (2*iz ) * (m_nelx(iy)+1); out(ielem,2) = top + (ix+1) + ( iz ) * (m_nelx(iy)+1); out(ielem,3) = top + (ix ) + ( iz ) * (m_nelx(iy)+1); out(ielem,4) = mid + (ix ) + (2*iz+1) * (m_nelx(iy)+1); out(ielem,5) = mid + (ix+1) + (2*iz+1) * (m_nelx(iy)+1); out(ielem,6) = top + (ix+1) + ( iz+1) * (m_nelx(iy)+1); out(ielem,7) = top + (ix ) + ( iz+1) * (m_nelx(iy)+1); ielem++; } } } } return out; } // ------------------------------ element numbers of the middle layer ------------------------------ inline xt::xtensor FineLayer::elementsMiddleLayer() const { // number of element layers in y-direction, the index of the middle layer size_t nely = static_cast(m_nhy.size()); size_t iy = (nely-1)/2; xt::xtensor out = xt::empty({m_nelx(iy)*m_nelz(iy)}); for ( size_t ix = 0 ; ix < m_nelx(iy) ; ++ix ) for ( size_t iz = 0 ; iz < m_nelz(iy) ; ++iz ) out(ix+iz*m_nelx(iy)) = m_startElem(iy) + ix + iz*m_nelx(iy); return out; } // ------------------------------ node-numbers along the front plane ------------------------------- inline xt::xtensor FineLayer::nodesFront() const { // number of element layers in y-direction size_t nely = static_cast(m_nhy.size()); // number of boundary nodes // - initialize size_t n = 0; // - bottom half: bottom node layer (+ middle node layer) for ( size_t iy = 0 ; iy < (nely+1)/2 ; ++iy ) { if ( m_refine(iy) == 0 ) n += m_nelx(iy) * 3 + 1; else n += m_nelx(iy) + 1; } // - top half: (middle node layer +) top node layer for ( size_t iy = (nely-1)/2 ; iy < nely ; ++iy ) { if ( m_refine(iy) == 0 ) n += m_nelx(iy) * 3 + 1; else n += m_nelx(iy) + 1; } // allocate node-list xt::xtensor out = xt::empty({n}); // initialize counter: current index in the node-list "out" size_t j = 0; // bottom half: bottom node layer (+ middle node layer) for ( size_t iy = 0 ; iy < (nely+1)/2 ; ++iy ) { // -- bottom node layer for ( size_t ix = 0 ; ix < m_nelx(iy)+1 ; ++ix ) { out(j) = m_startNode(iy) + ix; ++j; } // -- refinement layer if ( m_refine(iy) == 0 ) { for ( size_t ix = 0 ; ix < 2*m_nelx(iy) ; ++ix ) { out(j) = m_startNode(iy) + ix + m_nnd(iy); ++j; } } } // top half: (middle node layer +) top node layer for ( size_t iy = (nely-1)/2 ; iy < nely ; ++iy ) { // -- refinement layer if ( m_refine(iy) == 0 ) { for ( size_t ix = 0 ; ix < 2*m_nelx(iy) ; ++ix ) { out(j) = m_startNode(iy) + ix + m_nnd(iy); ++j; } } // -- top node layer for ( size_t ix = 0 ; ix < m_nelx(iy)+1 ; ++ix ) { out(j) = m_startNode(iy+1) + ix; ++j; } } return out; } // ------------------------------- node-numbers along the back plane ------------------------------- inline xt::xtensor FineLayer::nodesBack() const { // number of element layers in y-direction size_t nely = static_cast(m_nhy.size()); // number of boundary nodes // - initialize size_t n = 0; // - bottom half: bottom node layer (+ middle node layer) for ( size_t iy = 0 ; iy < (nely+1)/2 ; ++iy ) { if ( m_refine(iy) == 0 ) n += m_nelx(iy) * 3 + 1; else n += m_nelx(iy) + 1; } // - top half: (middle node layer +) top node layer for ( size_t iy = (nely-1)/2 ; iy < nely ; ++iy ) { if ( m_refine(iy) == 0 ) n += m_nelx(iy) * 3 + 1; else n += m_nelx(iy) + 1; } // allocate node-list xt::xtensor out = xt::empty({n}); // initialize counter: current index in the node-list "out" size_t j = 0; // bottom half: bottom node layer (+ middle node layer) for ( size_t iy = 0 ; iy < (nely+1)/2 ; ++iy ) { // -- bottom node layer for ( size_t ix = 0 ; ix < m_nelx(iy)+1 ; ++ix ) { out(j) = m_startNode(iy) + ix + (m_nelx(iy)+1)*m_nelz(iy); ++j; } // -- refinement layer if ( m_refine(iy) == 0 ) { for ( size_t ix = 0 ; ix < 2*m_nelx(iy) ; ++ix ) { out(j) = m_startNode(iy) + ix + m_nnd(iy) + 2*m_nelx(iy)*m_nelz(iy); ++j; } } } // top half: (middle node layer +) top node layer for ( size_t iy = (nely-1)/2 ; iy < nely ; ++iy ) { // -- refinement layer if ( m_refine(iy) == 0 ) { for ( size_t ix = 0 ; ix < 2*m_nelx(iy) ; ++ix ) { out(j) = m_startNode(iy) + ix + m_nnd(iy) + 2*m_nelx(iy)*m_nelz(iy); ++j; } } // -- top node layer for ( size_t ix = 0 ; ix < m_nelx(iy)+1 ; ++ix ) { out(j) = m_startNode(iy+1) + ix + (m_nelx(iy)+1)*m_nelz(iy); ++j; } } return out; } // ------------------------------- node-numbers along the left plane ------------------------------- inline xt::xtensor FineLayer::nodesLeft() const { // number of element layers in y-direction size_t nely = static_cast(m_nhy.size()); // number of boundary nodes // - initialize size_t n = 0; // - bottom half: bottom node layer (+ middle node layer) for ( size_t iy = 0 ; iy < (nely+1)/2 ; ++iy ) { if ( m_refine(iy) == 2 ) n += m_nelz(iy) * 3 + 1; else n += m_nelz(iy) + 1; } // - top half: (middle node layer +) top node layer for ( size_t iy = (nely-1)/2 ; iy < nely ; ++iy ) { if ( m_refine(iy) == 2 ) n += m_nelz(iy) * 3 + 1; else n += m_nelz(iy) + 1; } // allocate node-list xt::xtensor out = xt::empty({n}); // initialize counter: current index in the node-list "out" size_t j = 0; // bottom half: bottom node layer (+ middle node layer) for ( size_t iy = 0 ; iy < (nely+1)/2 ; ++iy ) { // -- bottom node layer for ( size_t iz = 0 ; iz < m_nelz(iy)+1 ; ++iz ) { out(j) = m_startNode(iy) + iz * (m_nelx(iy)+1); ++j; } // -- refinement layer if ( m_refine(iy) == 2 ) { for ( size_t iz = 0 ; iz < 2*m_nelz(iy) ; ++iz ) { out(j) = m_startNode(iy) + iz * (m_nelx(iy)+1) + m_nnd(iy); ++j; } } } // top half: (middle node layer +) top node layer for ( size_t iy = (nely-1)/2 ; iy < nely ; ++iy ) { // -- refinement layer if ( m_refine(iy) == 2 ) { for ( size_t iz = 0 ; iz < 2*m_nelz(iy) ; ++iz ) { out(j) = m_startNode(iy) + iz * (m_nelx(iy)+1) + m_nnd(iy); ++j; } } // -- top node layer for ( size_t iz = 0 ; iz < m_nelz(iy)+1 ; ++iz ) { out(j) = m_startNode(iy+1) + iz * (m_nelx(iy)+1); ++j; } } return out; } // ------------------------------ node-numbers along the right plane ------------------------------- inline xt::xtensor FineLayer::nodesRight() const { // number of element layers in y-direction size_t nely = static_cast(m_nhy.size()); // number of boundary nodes // - initialize size_t n = 0; // - bottom half: bottom node layer (+ middle node layer) for ( size_t iy = 0 ; iy < (nely+1)/2 ; ++iy ) { if ( m_refine(iy) == 2 ) n += m_nelz(iy) * 3 + 1; else n += m_nelz(iy) + 1; } // - top half: (middle node layer +) top node layer for ( size_t iy = (nely-1)/2 ; iy < nely ; ++iy ) { if ( m_refine(iy) == 2 ) n += m_nelz(iy) * 3 + 1; else n += m_nelz(iy) + 1; } // allocate node-list xt::xtensor out = xt::empty({n}); // initialize counter: current index in the node-list "out" size_t j = 0; // bottom half: bottom node layer (+ middle node layer) for ( size_t iy = 0 ; iy < (nely+1)/2 ; ++iy ) { // -- bottom node layer for ( size_t iz = 0 ; iz < m_nelz(iy)+1 ; ++iz ) { out(j) = m_startNode(iy) + iz * (m_nelx(iy)+1) + m_nelx(iy); ++j; } // -- refinement layer if ( m_refine(iy) == 2 ) { for ( size_t iz = 0 ; iz < 2*m_nelz(iy) ; ++iz ) { out(j) = m_startNode(iy) + m_nnd(iy) + iz * (m_nelx(iy)+1) + m_nelx(iy); ++j; } } } // top half: (middle node layer +) top node layer for ( size_t iy = (nely-1)/2 ; iy < nely ; ++iy ) { // -- refinement layer if ( m_refine(iy) == 2 ) { for ( size_t iz = 0 ; iz < 2*m_nelz(iy) ; ++iz ) { out(j) = m_startNode(iy) + m_nnd(iy) + iz * (m_nelx(iy)+1) + m_nelx(iy); ++j; } } // -- top node layer for ( size_t iz = 0 ; iz < m_nelz(iy)+1 ; ++iz ) { out(j) = m_startNode(iy+1) + iz * (m_nelx(iy)+1) + m_nelx(iy); ++j; } } return out; } // ------------------------------ node-numbers along the bottom plane ------------------------------ inline xt::xtensor FineLayer::nodesBottom() const { // number of element layers in y-direction size_t nely = static_cast(m_nhy.size()); // allocate node list xt::xtensor out = xt::empty({m_nnd(nely)}); // counter size_t j = 0; // fill node list for ( size_t ix = 0 ; ix < m_nelx(0)+1 ; ++ix ) { for ( size_t iz = 0 ; iz < m_nelz(0)+1 ; ++iz ) { out(j) = m_startNode(0) + ix + iz * (m_nelx(0)+1); ++j; } } return out; } // ------------------------------- node-numbers along the top plane -------------------------------- inline xt::xtensor FineLayer::nodesTop() const { // number of element layers in y-direction size_t nely = static_cast(m_nhy.size()); // allocate node list xt::xtensor out = xt::empty({m_nnd(nely)}); // counter size_t j = 0; // fill node list for ( size_t ix = 0 ; ix < m_nelx(nely-1)+1 ; ++ix ) { for ( size_t iz = 0 ; iz < m_nelz(nely-1)+1 ; ++iz ) { out(j) = m_startNode(nely) + ix + iz * (m_nelx(nely-1)+1); ++j; } } return out; } // ------------------------------- node-numbers along the front face ------------------------------- inline xt::xtensor FineLayer::nodesFrontFace() const { // number of element layers in y-direction size_t nely = static_cast(m_nhy.size()); // number of boundary nodes // - initialize size_t n = 0; // - bottom half: bottom node layer (+ middle node layer) for ( size_t iy = 1 ; iy < (nely+1)/2 ; ++iy ) { if ( m_refine(iy) == 0 ) n += m_nelx(iy) * 3 - 1; else n += m_nelx(iy) - 1; } // - top half: (middle node layer +) top node layer for ( size_t iy = (nely-1)/2 ; iy < nely-1 ; ++iy ) { if ( m_refine(iy) == 0 ) n += m_nelx(iy) * 3 - 1; else n += m_nelx(iy) - 1; } // allocate node-list xt::xtensor out = xt::empty({n}); // initialize counter: current index in the node-list "out" size_t j = 0; // bottom half: bottom node layer (+ middle node layer) for ( size_t iy = 1 ; iy < (nely+1)/2 ; ++iy ) { // -- bottom node layer for ( size_t ix = 1 ; ix < m_nelx(iy) ; ++ix ) { out(j) = m_startNode(iy) + ix; ++j; } // -- refinement layer if ( m_refine(iy) == 0 ) { for ( size_t ix = 0 ; ix < 2*m_nelx(iy) ; ++ix ) { out(j) = m_startNode(iy) + ix + m_nnd(iy); ++j; } } } // top half: (middle node layer +) top node layer for ( size_t iy = (nely-1)/2 ; iy < nely-1 ; ++iy ) { // -- refinement layer if ( m_refine(iy) == 0 ) { for ( size_t ix = 0 ; ix < 2*m_nelx(iy) ; ++ix ) { out(j) = m_startNode(iy) + ix + m_nnd(iy); ++j; } } // -- top node layer for ( size_t ix = 1 ; ix < m_nelx(iy) ; ++ix ) { out(j) = m_startNode(iy+1) + ix; ++j; } } return out; } // ------------------------------- node-numbers along the back face -------------------------------- inline xt::xtensor FineLayer::nodesBackFace() const { // number of element layers in y-direction size_t nely = static_cast(m_nhy.size()); // number of boundary nodes // - initialize size_t n = 0; // - bottom half: bottom node layer (+ middle node layer) for ( size_t iy = 1 ; iy < (nely+1)/2 ; ++iy ) { if ( m_refine(iy) == 0 ) n += m_nelx(iy) * 3 - 1; else n += m_nelx(iy) - 1; } // - top half: (middle node layer +) top node layer for ( size_t iy = (nely-1)/2 ; iy < nely-1 ; ++iy ) { if ( m_refine(iy) == 0 ) n += m_nelx(iy) * 3 - 1; else n += m_nelx(iy) - 1; } // allocate node-list xt::xtensor out = xt::empty({n}); // initialize counter: current index in the node-list "out" size_t j = 0; // bottom half: bottom node layer (+ middle node layer) for ( size_t iy = 1 ; iy < (nely+1)/2 ; ++iy ) { // -- bottom node layer for ( size_t ix = 1 ; ix < m_nelx(iy) ; ++ix ) { out(j) = m_startNode(iy) + ix + (m_nelx(iy)+1)*m_nelz(iy); ++j; } // -- refinement layer if ( m_refine(iy) == 0 ) { for ( size_t ix = 0 ; ix < 2*m_nelx(iy) ; ++ix ) { out(j) = m_startNode(iy) + ix + m_nnd(iy) + 2*m_nelx(iy)*m_nelz(iy); ++j; } } } // top half: (middle node layer +) top node layer for ( size_t iy = (nely-1)/2 ; iy < nely-1 ; ++iy ) { // -- refinement layer if ( m_refine(iy) == 0 ) { for ( size_t ix = 0 ; ix < 2*m_nelx(iy) ; ++ix ) { out(j) = m_startNode(iy) + ix + m_nnd(iy) + 2*m_nelx(iy)*m_nelz(iy); ++j; } } // -- top node layer for ( size_t ix = 1 ; ix < m_nelx(iy) ; ++ix ) { out(j) = m_startNode(iy+1) + ix + (m_nelx(iy)+1)*m_nelz(iy); ++j; } } return out; } // ------------------------------- node-numbers along the left face -------------------------------- inline xt::xtensor FineLayer::nodesLeftFace() const { // number of element layers in y-direction size_t nely = static_cast(m_nhy.size()); // number of boundary nodes // - initialize size_t n = 0; // - bottom half: bottom node layer (+ middle node layer) for ( size_t iy = 1 ; iy < (nely+1)/2 ; ++iy ) { if ( m_refine(iy) == 2 ) n += m_nelz(iy) * 3 - 1; else n += m_nelz(iy) - 1; } // - top half: (middle node layer +) top node layer for ( size_t iy = (nely-1)/2 ; iy < nely-1 ; ++iy ) { if ( m_refine(iy) == 2 ) n += m_nelz(iy) * 3 - 1; else n += m_nelz(iy) - 1; } // allocate node-list xt::xtensor out = xt::empty({n}); // initialize counter: current index in the node-list "out" size_t j = 0; // bottom half: bottom node layer (+ middle node layer) for ( size_t iy = 1 ; iy < (nely+1)/2 ; ++iy ) { // -- bottom node layer for ( size_t iz = 1 ; iz < m_nelz(iy) ; ++iz ) { out(j) = m_startNode(iy) + iz * (m_nelx(iy)+1); ++j; } // -- refinement layer if ( m_refine(iy) == 2 ) { for ( size_t iz = 0 ; iz < 2*m_nelz(iy) ; ++iz ) { out(j) = m_startNode(iy) + iz * (m_nelx(iy)+1) + m_nnd(iy); ++j; } } } // top half: (middle node layer +) top node layer for ( size_t iy = (nely-1)/2 ; iy < nely-1 ; ++iy ) { // -- refinement layer if ( m_refine(iy) == 2 ) { for ( size_t iz = 0 ; iz < 2*m_nelz(iy) ; ++iz ) { out(j) = m_startNode(iy) + iz * (m_nelx(iy)+1) + m_nnd(iy); ++j; } } // -- top node layer for ( size_t iz = 1 ; iz < m_nelz(iy) ; ++iz ) { out(j) = m_startNode(iy+1) + iz * (m_nelx(iy)+1); ++j; } } return out; } // ------------------------------- node-numbers along the right face ------------------------------- inline xt::xtensor FineLayer::nodesRightFace() const { // number of element layers in y-direction size_t nely = static_cast(m_nhy.size()); // number of boundary nodes // - initialize size_t n = 0; // - bottom half: bottom node layer (+ middle node layer) for ( size_t iy = 1 ; iy < (nely+1)/2 ; ++iy ) { if ( m_refine(iy) == 2 ) n += m_nelz(iy) * 3 - 1; else n += m_nelz(iy) - 1; } // - top half: (middle node layer +) top node layer for ( size_t iy = (nely-1)/2 ; iy < nely-1 ; ++iy ) { if ( m_refine(iy) == 2 ) n += m_nelz(iy) * 3 - 1; else n += m_nelz(iy) - 1; } // allocate node-list xt::xtensor out = xt::empty({n}); // initialize counter: current index in the node-list "out" size_t j = 0; // bottom half: bottom node layer (+ middle node layer) for ( size_t iy = 1 ; iy < (nely+1)/2 ; ++iy ) { // -- bottom node layer for ( size_t iz = 1 ; iz < m_nelz(iy) ; ++iz ) { out(j) = m_startNode(iy) + iz * (m_nelx(iy)+1) + m_nelx(iy); ++j; } // -- refinement layer if ( m_refine(iy) == 2 ) { for ( size_t iz = 0 ; iz < 2*m_nelz(iy) ; ++iz ) { out(j) = m_startNode(iy) + m_nnd(iy) + iz * (m_nelx(iy)+1) + m_nelx(iy); ++j; } } } // top half: (middle node layer +) top node layer for ( size_t iy = (nely-1)/2 ; iy < nely-1 ; ++iy ) { // -- refinement layer if ( m_refine(iy) == 2 ) { for ( size_t iz = 0 ; iz < 2*m_nelz(iy) ; ++iz ) { out(j) = m_startNode(iy) + m_nnd(iy) + iz * (m_nelx(iy)+1) + m_nelx(iy); ++j; } } // -- top node layer for ( size_t iz = 1 ; iz < m_nelz(iy) ; ++iz ) { out(j) = m_startNode(iy+1) + iz * (m_nelx(iy)+1) + m_nelx(iy); ++j; } } return out; } // ------------------------------ node-numbers along the bottom face ------------------------------- inline xt::xtensor FineLayer::nodesBottomFace() const { // allocate node list xt::xtensor out = xt::empty({(m_nelx(0)-1)*(m_nelz(0)-1)}); // counter size_t j = 0; // fill node list for ( size_t ix = 1 ; ix < m_nelx(0) ; ++ix ) { for ( size_t iz = 1 ; iz < m_nelz(0) ; ++iz ) { out(j) = m_startNode(0) + ix + iz * (m_nelx(0)+1); ++j; } } return out; } // -------------------------------- node-numbers along the top face -------------------------------- inline xt::xtensor FineLayer::nodesTopFace() const { // number of element layers in y-direction size_t nely = static_cast(m_nhy.size()); // allocate node list xt::xtensor out = xt::empty({(m_nelx(nely-1)-1)*(m_nelz(nely-1)-1)}); // counter size_t j = 0; // fill node list for ( size_t ix = 1 ; ix < m_nelx(nely-1) ; ++ix ) { for ( size_t iz = 1 ; iz < m_nelz(nely-1) ; ++iz ) { out(j) = m_startNode(nely) + ix + iz * (m_nelx(nely-1)+1); ++j; } } return out; } // --------------------------- node-numbers along the front-bottom edge ---------------------------- inline xt::xtensor FineLayer::nodesFrontBottomEdge() const { xt::xtensor out = xt::empty({m_nelx(0)+1}); for ( size_t ix = 0 ; ix < m_nelx(0)+1 ; ++ix ) out(ix) = m_startNode(0) + ix; return out; } // ----------------------------- node-numbers along the front-top edge ----------------------------- inline xt::xtensor FineLayer::nodesFrontTopEdge() const { size_t nely = static_cast(m_nhy.size()); xt::xtensor out = xt::empty({m_nelx(nely-1)+1}); for ( size_t ix = 0 ; ix < m_nelx(nely-1)+1 ; ++ix ) out(ix) = m_startNode(nely) + ix; return out; } // ---------------------------- node-numbers along the front-left edge ----------------------------- inline xt::xtensor FineLayer::nodesFrontLeftEdge() const { size_t nely = static_cast(m_nhy.size()); xt::xtensor out = xt::empty({nely+1}); for ( size_t iy = 0 ; iy < (nely+1)/2 ; ++iy ) out(iy) = m_startNode(iy); for ( size_t iy = (nely-1)/2 ; iy < nely ; ++iy ) out(iy+1) = m_startNode(iy+1); return out; } // ---------------------------- node-numbers along the front-right edge ---------------------------- inline xt::xtensor FineLayer::nodesFrontRightEdge() const { size_t nely = static_cast(m_nhy.size()); xt::xtensor out = xt::empty({nely+1}); for ( size_t iy = 0 ; iy < (nely+1)/2 ; ++iy ) out(iy) = m_startNode(iy) + m_nelx(iy); for ( size_t iy = (nely-1)/2 ; iy < nely ; ++iy ) out(iy+1) = m_startNode(iy+1) + m_nelx(iy); return out; } // ---------------------------- node-numbers along the back-bottom edge ---------------------------- inline xt::xtensor FineLayer::nodesBackBottomEdge() const { xt::xtensor out = xt::empty({m_nelx(0)+1}); for ( size_t ix = 0 ; ix < m_nelx(0)+1 ; ++ix ) out(ix) = m_startNode(0) + ix + (m_nelx(0)+1)*(m_nelz(0)); return out; } // ----------------------------- node-numbers along the back-top edge ------------------------------ inline xt::xtensor FineLayer::nodesBackTopEdge() const { size_t nely = static_cast(m_nhy.size()); xt::xtensor out = xt::empty({m_nelx(nely-1)+1}); for ( size_t ix = 0 ; ix < m_nelx(nely-1)+1 ; ++ix ) out(ix) = m_startNode(nely) + ix + (m_nelx(nely-1)+1)*(m_nelz(nely-1)); return out; } // ----------------------------- node-numbers along the back-left edge ----------------------------- inline xt::xtensor FineLayer::nodesBackLeftEdge() const { size_t nely = static_cast(m_nhy.size()); xt::xtensor out = xt::empty({nely+1}); for ( size_t iy = 0 ; iy < (nely+1)/2 ; ++iy ) out(iy) = m_startNode(iy) + (m_nelx(iy)+1)*(m_nelz(iy)); for ( size_t iy = (nely-1)/2 ; iy < nely ; ++iy ) out(iy+1) = m_startNode(iy+1) + (m_nelx(iy)+1)*(m_nelz(iy)); return out; } // ---------------------------- node-numbers along the back-right edge ----------------------------- inline xt::xtensor FineLayer::nodesBackRightEdge() const { size_t nely = static_cast(m_nhy.size()); xt::xtensor out = xt::empty({nely+1}); for ( size_t iy = 0 ; iy < (nely+1)/2 ; ++iy ) out(iy) = m_startNode(iy) + m_nelx(iy) + (m_nelx(iy)+1)*(m_nelz(iy)); for ( size_t iy = (nely-1)/2 ; iy < nely ; ++iy ) out(iy+1) = m_startNode(iy+1) + m_nelx(iy) + (m_nelx(iy)+1)*(m_nelz(iy)); return out; } // ---------------------------- node-numbers along the bottom-left edge ---------------------------- inline xt::xtensor FineLayer::nodesBottomLeftEdge() const { xt::xtensor out = xt::empty({m_nelz(0)+1}); for ( size_t iz = 0 ; iz < m_nelz(0)+1 ; ++iz ) out(iz) = m_startNode(0) + iz * (m_nelx(0)+1); return out; } // --------------------------- node-numbers along the bottom-right edge ---------------------------- inline xt::xtensor FineLayer::nodesBottomRightEdge() const { xt::xtensor out = xt::empty({m_nelz(0)+1}); for ( size_t iz = 0 ; iz < m_nelz(0)+1 ; ++iz ) out(iz) = m_startNode(0) + m_nelx(0) + iz * (m_nelx(0)+1); return out; } // ----------------------------- node-numbers along the top-left edge ------------------------------ inline xt::xtensor FineLayer::nodesTopLeftEdge() const { size_t nely = static_cast(m_nhy.size()); xt::xtensor out = xt::empty({m_nelz(nely-1)+1}); for ( size_t iz = 0 ; iz < m_nelz(nely-1)+1 ; ++iz ) out(iz) = m_startNode(nely) + iz * (m_nelx(nely-1)+1); return out; } // ----------------------------- node-numbers along the top-right edge ----------------------------- inline xt::xtensor FineLayer::nodesTopRightEdge() const { size_t nely = static_cast(m_nhy.size()); xt::xtensor out = xt::empty({m_nelz(nely-1)+1}); for ( size_t iz = 0 ; iz < m_nelz(nely-1)+1 ; ++iz ) out(iz) = m_startNode(nely) + m_nelx(nely-1) + iz * (m_nelx(nely-1)+1); return out; } // -------------------------------------------- aliases -------------------------------------------- inline xt::xtensor FineLayer::nodesBottomFrontEdge() const { return nodesFrontBottomEdge(); } inline xt::xtensor FineLayer::nodesBottomBackEdge() const { return nodesBackBottomEdge(); } inline xt::xtensor FineLayer::nodesTopFrontEdge() const { return nodesFrontTopEdge(); } inline xt::xtensor FineLayer::nodesTopBackEdge() const { return nodesBackTopEdge(); } inline xt::xtensor FineLayer::nodesLeftBottomEdge() const { return nodesBottomLeftEdge(); } inline xt::xtensor FineLayer::nodesLeftFrontEdge() const { return nodesFrontLeftEdge(); } inline xt::xtensor FineLayer::nodesLeftBackEdge() const { return nodesBackLeftEdge(); } inline xt::xtensor FineLayer::nodesLeftTopEdge() const { return nodesTopLeftEdge(); } inline xt::xtensor FineLayer::nodesRightBottomEdge() const { return nodesBottomRightEdge(); } inline xt::xtensor FineLayer::nodesRightTopEdge() const { return nodesTopRightEdge(); } inline xt::xtensor FineLayer::nodesRightFrontEdge() const { return nodesFrontRightEdge(); } inline xt::xtensor FineLayer::nodesRightBackEdge() const { return nodesBackRightEdge(); } // ------------------- node-numbers along the front-bottom edge, without corners ------------------- inline xt::xtensor FineLayer::nodesFrontBottomOpenEdge() const { xt::xtensor out = xt::empty({m_nelx(0)-1}); for ( size_t ix = 1 ; ix < m_nelx(0) ; ++ix ) out(ix-1) = m_startNode(0) + ix; return out; } // -------------------- node-numbers along the front-top edge, without corners --------------------- inline xt::xtensor FineLayer::nodesFrontTopOpenEdge() const { size_t nely = static_cast(m_nhy.size()); xt::xtensor out = xt::empty({m_nelx(nely-1)-1}); for ( size_t ix = 1 ; ix < m_nelx(nely-1) ; ++ix ) out(ix-1) = m_startNode(nely) + ix; return out; } // -------------------- node-numbers along the front-left edge, without corners -------------------- inline xt::xtensor FineLayer::nodesFrontLeftOpenEdge() const { size_t nely = static_cast(m_nhy.size()); xt::xtensor out = xt::empty({nely-1}); for ( size_t iy = 1 ; iy < (nely+1)/2 ; ++iy ) out(iy-1) = m_startNode(iy); for ( size_t iy = (nely-1)/2 ; iy < nely-1 ; ++iy ) out(iy) = m_startNode(iy+1); return out; } // ------------------- node-numbers along the front-right edge, without corners -------------------- inline xt::xtensor FineLayer::nodesFrontRightOpenEdge() const { size_t nely = static_cast(m_nhy.size()); xt::xtensor out = xt::empty({nely-1}); for ( size_t iy = 1 ; iy < (nely+1)/2 ; ++iy ) out(iy-1) = m_startNode(iy) + m_nelx(iy); for ( size_t iy = (nely-1)/2 ; iy < nely-1 ; ++iy ) out(iy) = m_startNode(iy+1) + m_nelx(iy); return out; } // ------------------- node-numbers along the back-bottom edge, without corners -------------------- inline xt::xtensor FineLayer::nodesBackBottomOpenEdge() const { xt::xtensor out = xt::empty({m_nelx(0)-1}); for ( size_t ix = 1 ; ix < m_nelx(0) ; ++ix ) out(ix-1) = m_startNode(0) + ix + (m_nelx(0)+1)*(m_nelz(0)); return out; } // --------------------- node-numbers along the back-top edge, without corners --------------------- inline xt::xtensor FineLayer::nodesBackTopOpenEdge() const { size_t nely = static_cast(m_nhy.size()); xt::xtensor out = xt::empty({m_nelx(nely-1)-1}); for ( size_t ix = 1 ; ix < m_nelx(nely-1) ; ++ix ) out(ix-1) = m_startNode(nely) + ix + (m_nelx(nely-1)+1)*(m_nelz(nely-1)); return out; } // -------------------- node-numbers along the back-left edge, without corners --------------------- inline xt::xtensor FineLayer::nodesBackLeftOpenEdge() const { size_t nely = static_cast(m_nhy.size()); xt::xtensor out = xt::empty({nely-1}); for ( size_t iy = 1 ; iy < (nely+1)/2 ; ++iy ) out(iy-1) = m_startNode(iy) + (m_nelx(iy)+1)*(m_nelz(iy)); for ( size_t iy = (nely-1)/2 ; iy < nely-1 ; ++iy ) out(iy) = m_startNode(iy+1) + (m_nelx(iy)+1)*(m_nelz(iy)); return out; } // -------------------- node-numbers along the back-right edge, without corners -------------------- inline xt::xtensor FineLayer::nodesBackRightOpenEdge() const { size_t nely = static_cast(m_nhy.size()); xt::xtensor out = xt::empty({nely-1}); for ( size_t iy = 1 ; iy < (nely+1)/2 ; ++iy ) out(iy-1) = m_startNode(iy) + m_nelx(iy) + (m_nelx(iy)+1)*(m_nelz(iy)); for ( size_t iy = (nely-1)/2 ; iy < nely-1 ; ++iy ) out(iy) = m_startNode(iy+1) + m_nelx(iy) + (m_nelx(iy)+1)*(m_nelz(iy)); return out; } // ------------------- node-numbers along the bottom-left edge, without corners -------------------- inline xt::xtensor FineLayer::nodesBottomLeftOpenEdge() const { xt::xtensor out = xt::empty({m_nelz(0)-1}); for ( size_t iz = 1 ; iz < m_nelz(0) ; ++iz ) out(iz-1) = m_startNode(0) + iz * (m_nelx(0)+1); return out; } // ------------------- node-numbers along the bottom-right edge, without corners ------------------- inline xt::xtensor FineLayer::nodesBottomRightOpenEdge() const { xt::xtensor out = xt::empty({m_nelz(0)-1}); for ( size_t iz = 1 ; iz < m_nelz(0) ; ++iz ) out(iz-1) = m_startNode(0) + m_nelx(0) + iz * (m_nelx(0)+1); return out; } // --------------------- node-numbers along the top-left edge, without corners --------------------- inline xt::xtensor FineLayer::nodesTopLeftOpenEdge() const { size_t nely = static_cast(m_nhy.size()); xt::xtensor out = xt::empty({m_nelz(nely-1)-1}); for ( size_t iz = 1 ; iz < m_nelz(nely-1) ; ++iz ) out(iz-1) = m_startNode(nely) + iz * (m_nelx(nely-1)+1); return out; } // -------------------- node-numbers along the top-right edge, without corners --------------------- inline xt::xtensor FineLayer::nodesTopRightOpenEdge() const { size_t nely = static_cast(m_nhy.size()); xt::xtensor out = xt::empty({m_nelz(nely-1)-1}); for ( size_t iz = 1 ; iz < m_nelz(nely-1) ; ++iz ) out(iz-1) = m_startNode(nely) + m_nelx(nely-1) + iz * (m_nelx(nely-1)+1); return out; } // -------------------------------------------- aliases -------------------------------------------- inline xt::xtensor FineLayer::nodesBottomFrontOpenEdge() const { return nodesFrontBottomOpenEdge(); } inline xt::xtensor FineLayer::nodesBottomBackOpenEdge() const { return nodesBackBottomOpenEdge(); } inline xt::xtensor FineLayer::nodesTopFrontOpenEdge() const { return nodesFrontTopOpenEdge(); } inline xt::xtensor FineLayer::nodesTopBackOpenEdge() const { return nodesBackTopOpenEdge(); } inline xt::xtensor FineLayer::nodesLeftBottomOpenEdge() const { return nodesBottomLeftOpenEdge(); } inline xt::xtensor FineLayer::nodesLeftFrontOpenEdge() const { return nodesFrontLeftOpenEdge(); } inline xt::xtensor FineLayer::nodesLeftBackOpenEdge() const { return nodesBackLeftOpenEdge(); } inline xt::xtensor FineLayer::nodesLeftTopOpenEdge() const { return nodesTopLeftOpenEdge(); } inline xt::xtensor FineLayer::nodesRightBottomOpenEdge() const { return nodesBottomRightOpenEdge(); } inline xt::xtensor FineLayer::nodesRightTopOpenEdge() const { return nodesTopRightOpenEdge(); } inline xt::xtensor FineLayer::nodesRightFrontOpenEdge() const { return nodesFrontRightOpenEdge(); } inline xt::xtensor FineLayer::nodesRightBackOpenEdge() const { return nodesBackRightOpenEdge(); } // -------------------------- node-number of the front-bottom-left corner -------------------------- inline size_t FineLayer::nodesFrontBottomLeftCorner() const { return m_startNode(0); } // ------------------------- node-number of the front-bottom-right corner -------------------------- inline size_t FineLayer::nodesFrontBottomRightCorner() const { return m_startNode(0) + m_nelx(0); } // --------------------------- node-number of the front-top-left corner ---------------------------- inline size_t FineLayer::nodesFrontTopLeftCorner() const { size_t nely = static_cast(m_nhy.size()); return m_startNode(nely); } // --------------------------- node-number of the front-top-right corner --------------------------- inline size_t FineLayer::nodesFrontTopRightCorner() const { size_t nely = static_cast(m_nhy.size()); return m_startNode(nely) + m_nelx(nely-1); } // -------------------------- node-number of the back-bottom-left corner --------------------------- inline size_t FineLayer::nodesBackBottomLeftCorner() const { return m_startNode(0) + (m_nelx(0)+1)*(m_nelz(0)); } // -------------------------- node-number of the back-bottom-right corner -------------------------- inline size_t FineLayer::nodesBackBottomRightCorner() const { return m_startNode(0) + m_nelx(0) + (m_nelx(0)+1)*(m_nelz(0)); } // ---------------------------- node-number of the back-top-left corner ---------------------------- inline size_t FineLayer::nodesBackTopLeftCorner() const { size_t nely = static_cast(m_nhy.size()); return m_startNode(nely) + (m_nelx(nely-1)+1)*(m_nelz(nely-1)); } // --------------------------- node-number of the back-top-right corner ---------------------------- inline size_t FineLayer::nodesBackTopRightCorner() const { size_t nely = static_cast(m_nhy.size()); return m_startNode(nely) + m_nelx(nely-1) + (m_nelx(nely-1)+1)*(m_nelz(nely-1)); } // -------------------------------------------- aliases -------------------------------------------- inline size_t FineLayer::nodesFrontLeftBottomCorner() const { return nodesFrontBottomLeftCorner(); } inline size_t FineLayer::nodesBottomFrontLeftCorner() const { return nodesFrontBottomLeftCorner(); } inline size_t FineLayer::nodesBottomLeftFrontCorner() const { return nodesFrontBottomLeftCorner(); } inline size_t FineLayer::nodesLeftFrontBottomCorner() const { return nodesFrontBottomLeftCorner(); } inline size_t FineLayer::nodesLeftBottomFrontCorner() const { return nodesFrontBottomLeftCorner(); } inline size_t FineLayer::nodesFrontRightBottomCorner() const { return nodesFrontBottomRightCorner(); } inline size_t FineLayer::nodesBottomFrontRightCorner() const { return nodesFrontBottomRightCorner(); } inline size_t FineLayer::nodesBottomRightFrontCorner() const { return nodesFrontBottomRightCorner(); } inline size_t FineLayer::nodesRightFrontBottomCorner() const { return nodesFrontBottomRightCorner(); } inline size_t FineLayer::nodesRightBottomFrontCorner() const { return nodesFrontBottomRightCorner(); } inline size_t FineLayer::nodesFrontLeftTopCorner() const { return nodesFrontTopLeftCorner(); } inline size_t FineLayer::nodesTopFrontLeftCorner() const { return nodesFrontTopLeftCorner(); } inline size_t FineLayer::nodesTopLeftFrontCorner() const { return nodesFrontTopLeftCorner(); } inline size_t FineLayer::nodesLeftFrontTopCorner() const { return nodesFrontTopLeftCorner(); } inline size_t FineLayer::nodesLeftTopFrontCorner() const { return nodesFrontTopLeftCorner(); } inline size_t FineLayer::nodesFrontRightTopCorner() const { return nodesFrontTopRightCorner(); } inline size_t FineLayer::nodesTopFrontRightCorner() const { return nodesFrontTopRightCorner(); } inline size_t FineLayer::nodesTopRightFrontCorner() const { return nodesFrontTopRightCorner(); } inline size_t FineLayer::nodesRightFrontTopCorner() const { return nodesFrontTopRightCorner(); } inline size_t FineLayer::nodesRightTopFrontCorner() const { return nodesFrontTopRightCorner(); } inline size_t FineLayer::nodesBackLeftBottomCorner() const { return nodesBackBottomLeftCorner(); } inline size_t FineLayer::nodesBottomBackLeftCorner() const { return nodesBackBottomLeftCorner(); } inline size_t FineLayer::nodesBottomLeftBackCorner() const { return nodesBackBottomLeftCorner(); } inline size_t FineLayer::nodesLeftBackBottomCorner() const { return nodesBackBottomLeftCorner(); } inline size_t FineLayer::nodesLeftBottomBackCorner() const { return nodesBackBottomLeftCorner(); } inline size_t FineLayer::nodesBackRightBottomCorner() const { return nodesBackBottomRightCorner(); } inline size_t FineLayer::nodesBottomBackRightCorner() const { return nodesBackBottomRightCorner(); } inline size_t FineLayer::nodesBottomRightBackCorner() const { return nodesBackBottomRightCorner(); } inline size_t FineLayer::nodesRightBackBottomCorner() const { return nodesBackBottomRightCorner(); } inline size_t FineLayer::nodesRightBottomBackCorner() const { return nodesBackBottomRightCorner(); } inline size_t FineLayer::nodesBackLeftTopCorner() const { return nodesBackTopLeftCorner(); } inline size_t FineLayer::nodesTopBackLeftCorner() const { return nodesBackTopLeftCorner(); } inline size_t FineLayer::nodesTopLeftBackCorner() const { return nodesBackTopLeftCorner(); } inline size_t FineLayer::nodesLeftBackTopCorner() const { return nodesBackTopLeftCorner(); } inline size_t FineLayer::nodesLeftTopBackCorner() const { return nodesBackTopLeftCorner(); } inline size_t FineLayer::nodesBackRightTopCorner() const { return nodesBackTopRightCorner(); } inline size_t FineLayer::nodesTopBackRightCorner() const { return nodesBackTopRightCorner(); } inline size_t FineLayer::nodesTopRightBackCorner() const { return nodesBackTopRightCorner(); } inline size_t FineLayer::nodesRightBackTopCorner() const { return nodesBackTopRightCorner(); } inline size_t FineLayer::nodesRightTopBackCorner() const { return nodesBackTopRightCorner(); } // ------------------------------ node-numbers of periodic node-pairs ------------------------------ inline xt::xtensor FineLayer::nodesPeriodic() const { // faces xt::xtensor fro = nodesFrontFace(); xt::xtensor bck = nodesBackFace(); xt::xtensor lft = nodesLeftFace(); xt::xtensor rgt = nodesRightFace(); xt::xtensor bot = nodesBottomFace(); xt::xtensor top = nodesTopFace(); // edges xt::xtensor froBot = nodesFrontBottomOpenEdge(); xt::xtensor froTop = nodesFrontTopOpenEdge(); xt::xtensor froLft = nodesFrontLeftOpenEdge(); xt::xtensor froRgt = nodesFrontRightOpenEdge(); xt::xtensor bckBot = nodesBackBottomOpenEdge(); xt::xtensor bckTop = nodesBackTopOpenEdge(); xt::xtensor bckLft = nodesBackLeftOpenEdge(); xt::xtensor bckRgt = nodesBackRightOpenEdge(); xt::xtensor botLft = nodesBottomLeftOpenEdge(); xt::xtensor botRgt = nodesBottomRightOpenEdge(); xt::xtensor topLft = nodesTopLeftOpenEdge(); xt::xtensor topRgt = nodesTopRightOpenEdge(); // allocate nodal ties // - number of tying per category size_t tface = fro.size() + lft.size() + bot.size(); size_t tedge = 3*froBot.size() + 3*froLft.size() + 3*botLft.size(); size_t tnode = 7; // - allocate xt::xtensor out = xt::empty({tface+tedge+tnode, std::size_t(2)}); // counter size_t i = 0; // tie all corners to one corner out(i,0) = nodesFrontBottomLeftCorner(); out(i,1) = nodesFrontBottomRightCorner(); ++i; out(i,0) = nodesFrontBottomLeftCorner(); out(i,1) = nodesBackBottomRightCorner(); ++i; out(i,0) = nodesFrontBottomLeftCorner(); out(i,1) = nodesBackBottomLeftCorner(); ++i; out(i,0) = nodesFrontBottomLeftCorner(); out(i,1) = nodesFrontTopLeftCorner(); ++i; out(i,0) = nodesFrontBottomLeftCorner(); out(i,1) = nodesFrontTopRightCorner(); ++i; out(i,0) = nodesFrontBottomLeftCorner(); out(i,1) = nodesBackTopRightCorner(); ++i; out(i,0) = nodesFrontBottomLeftCorner(); out(i,1) = nodesBackTopLeftCorner(); ++i; // tie all corresponding edges to each other (exclude corners) for ( size_t j = 0 ; j FineLayer::dofs() const { - return xGooseFEM::Mesh::dofs(m_nnode,m_ndim); + return GooseFEM::Mesh::dofs(m_nnode,m_ndim); } // ------------------------ DOP-numbers with periodic dependencies removed ------------------------- inline xt::xtensor FineLayer::dofsPeriodic() const { // DOF-numbers for each component of each node (sequential) - xt::xtensor out = xGooseFEM::Mesh::dofs(m_nnode,m_ndim); + xt::xtensor out = GooseFEM::Mesh::dofs(m_nnode,m_ndim); // periodic node-pairs xt::xtensor nodePer = nodesPeriodic(); // eliminate 'dependent' DOFs; renumber "out" to be sequential for the remaining DOFs for ( size_t i = 0 ; i < nodePer.shape()[0] ; ++i ) for ( size_t j = 0 ; j < m_ndim ; ++j ) out(nodePer(i,1),j) = out(nodePer(i,0),j); // renumber "out" to be sequential - return xGooseFEM::Mesh::renumber(out); + return GooseFEM::Mesh::renumber(out); } // ------------------------------------------------------------------------------------------------- }}} // namespace ... // ================================================================================================= #endif diff --git a/include/xGooseFEM/MeshQuad4.h b/include/GooseFEM/MeshQuad4.h similarity index 99% rename from include/xGooseFEM/MeshQuad4.h rename to include/GooseFEM/MeshQuad4.h index 55d6359..5ec6b9e 100644 --- a/include/xGooseFEM/MeshQuad4.h +++ b/include/GooseFEM/MeshQuad4.h @@ -1,137 +1,137 @@ /* ================================================================================================= (c - GPLv3) T.W.J. de Geus (Tom) | tom@geus.me | www.geus.me | github.com/tdegeus/GooseFEM ================================================================================================= */ -#ifndef XGOOSEFEM_MESHQUAD4_H -#define XGOOSEFEM_MESHQUAD4_H +#ifndef GOOSEFEM_MESHQUAD4_H +#define GOOSEFEM_MESHQUAD4_H // ------------------------------------------------------------------------------------------------- #include "GooseFEM.h" // ===================================== GooseFEM::Mesh::Quad4 ===================================== -namespace xGooseFEM { +namespace GooseFEM { namespace Mesh { namespace Quad4 { // ----------------------------------------- regular mesh ------------------------------------------ class Regular { 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 public: // mesh with "nelx*nely" 'elements' of edge size "h" Regular(size_t nelx, size_t nely, double h=1.); // sizes 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 nnodePeriodic() const; // number of nodes, after elimination of periodicity // mesh xt::xtensor coor() const; // nodal positions [nnode ,ndim] xt::xtensor conn() const; // connectivity [nelem ,nne ] // boundary nodes: edges xt::xtensor nodesBottomEdge() const; // node-numbers along the bottom edge xt::xtensor nodesTopEdge() const; // node-numbers along the top edge xt::xtensor nodesLeftEdge() const; // node-numbers along the left edge xt::xtensor nodesRightEdge() const; // node-numbers along the right edge // boundary nodes: edges, without corners xt::xtensor nodesBottomOpenEdge() const; // node-numbers along the bottom edge xt::xtensor nodesTopOpenEdge() const; // node-numbers along the top edge xt::xtensor nodesLeftOpenEdge() const; // node-numbers along the left edge xt::xtensor nodesRightOpenEdge() const; // node-numbers along the right edge // boundary nodes: corners size_t nodesBottomLeftCorner() const; // node-number of the bottom - left corner size_t nodesBottomRightCorner() const; // node-number of the bottom - right corner size_t nodesTopLeftCorner() const; // node-number of the top - left corner size_t nodesTopRightCorner() const; // node-number of the top - right corner // boundary nodes: corners (aliases) size_t nodesLeftBottomCorner() const; // alias, see above: nodesBottomLeftCorner size_t nodesLeftTopCorner() const; // alias, see above: nodesBottomRightCorner size_t nodesRightBottomCorner() const; // alias, see above: nodesTopLeftCorner size_t nodesRightTopCorner() const; // alias, see above: nodesTopRightCorner // periodicity xt::xtensor nodesPeriodic() const; // periodic node pairs [:,2]: (independent, dependent) size_t nodesOrigin() const; // bottom-left node, used as reference for periodicity xt::xtensor dofs() const; // DOF-numbers for each component of each node (sequential) xt::xtensor dofsPeriodic() const; // ,, for the case that the periodicity if fully eliminated }; // ---------------------- mesh with a fine layer that exponentially coarsens ----------------------- class FineLayer { private: double m_h; // elementary element edge-size (in all directions) double m_Lx; // mesh size in "x" size_t m_nelem; // number of elements size_t m_nnode; // number of nodes static const size_t m_nne=4; // number of nodes-per-element static const size_t m_ndim=2; // number of dimensions xt::xtensor m_nelx; // number of elements in "x" (per el.layer in "y") xt::xtensor m_nnd; // total number of nodes in the main node layer (per nd.layer in "y") xt::xtensor m_nhx, m_nhy; // element size in each direction (per el.layer in "y") xt::xtensor m_refine; // refine direction (-1:no refine, 0:"x") (per el.layer in "y") xt::xtensor m_startElem; // start element (per el.layer in "y") xt::xtensor m_startNode; // start node (per nd.layer in "y") public: // mesh with "nelx*nely" elements of edge size "h"; elements are coarsened in "y"-direction FineLayer(size_t nelx, size_t nely, double h=1., size_t nfine=1); // sizes 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 shape(size_t i) const; // actual shape in a certain direction // mesh xt::xtensor coor() const; // nodal positions [nnode ,ndim] xt::xtensor conn() const; // connectivity [nelem ,nne ] // element sets xt::xtensor elementsMiddleLayer() const; // elements in the middle, fine, layer // boundary nodes: edges xt::xtensor nodesBottomEdge() const; // node-numbers along the bottom edge xt::xtensor nodesTopEdge() const; // node-numbers along the top edge xt::xtensor nodesLeftEdge() const; // node-numbers along the left edge xt::xtensor nodesRightEdge() const; // node-numbers along the right edge // boundary nodes: edges, without corners xt::xtensor nodesBottomOpenEdge() const; // node-numbers along the bottom edge xt::xtensor nodesTopOpenEdge() const; // node-numbers along the top edge xt::xtensor nodesLeftOpenEdge() const; // node-numbers along the left edge xt::xtensor nodesRightOpenEdge() const; // node-numbers along the right edge // boundary nodes: corners size_t nodesBottomLeftCorner() const; // node-number of the bottom - left corner size_t nodesBottomRightCorner() const; // node-number of the bottom - right corner size_t nodesTopLeftCorner() const; // node-number of the top - left corner size_t nodesTopRightCorner() const; // node-number of the top - right corner // boundary nodes: corners (aliases) size_t nodesLeftBottomCorner() const; // alias, see above: nodesBottomLeftCorner size_t nodesLeftTopCorner() const; // alias, see above: nodesBottomRightCorner size_t nodesRightBottomCorner() const; // alias, see above: nodesTopLeftCorner size_t nodesRightTopCorner() const; // alias, see above: nodesTopRightCorner // periodicity xt::xtensor nodesPeriodic() const; // periodic node pairs [:,2]: (independent, dependent) size_t nodesOrigin() const; // bottom-left node, used as reference for periodicity xt::xtensor dofs() const; // DOF-numbers for each component of each node (sequential) xt::xtensor dofsPeriodic() const; // ,, for the case that the periodicity if fully eliminated }; // ------------------------------------------------------------------------------------------------- }}} // namespace ... // ================================================================================================= #endif diff --git a/include/xGooseFEM/MeshQuad4.hpp b/include/GooseFEM/MeshQuad4.hpp similarity index 98% rename from include/xGooseFEM/MeshQuad4.hpp rename to include/GooseFEM/MeshQuad4.hpp index b764bad..054a3c6 100644 --- a/include/xGooseFEM/MeshQuad4.hpp +++ b/include/GooseFEM/MeshQuad4.hpp @@ -1,921 +1,921 @@ /* ================================================================================================= (c - GPLv3) T.W.J. de Geus (Tom) | tom@geus.me | www.geus.me | github.com/tdegeus/GooseFEM ================================================================================================= */ -#ifndef XGOOSEFEM_MESHQUAD4_CPP -#define XGOOSEFEM_MESHQUAD4_CPP +#ifndef GOOSEFEM_MESHQUAD4_CPP +#define GOOSEFEM_MESHQUAD4_CPP // ------------------------------------------------------------------------------------------------- #include "MeshQuad4.h" // ===================================== GooseFEM::Mesh::Quad4 ===================================== -namespace xGooseFEM { +namespace GooseFEM { namespace Mesh { namespace Quad4 { // ------------------------------------------ constructor ------------------------------------------ inline Regular::Regular(size_t nelx, size_t nely, double h): m_h(h), m_nelx(nelx), m_nely(nely) { assert( m_nelx >= 1 ); assert( m_nely >= 1 ); m_nnode = (m_nelx+1) * (m_nely+1); m_nelem = m_nelx * m_nely ; } // -------------------------------------- number of elements --------------------------------------- inline size_t Regular::nelem() const { return m_nelem; } // ---------------------------------------- number of nodes ---------------------------------------- inline size_t Regular::nnode() const { return m_nnode; } // ---------------------------------- number of nodes per element ---------------------------------- inline size_t Regular::nne() const { return m_nne; } // ------------------------------------- number of dimensions -------------------------------------- inline size_t Regular::ndim() const { return m_ndim; } // ------------------------ number of nodes, after eliminating periodicity ------------------------- inline size_t Regular::nnodePeriodic() const { return (m_nelx+1) * (m_nely+1) - (m_nely+1) - (m_nelx); } // --------------------------------- coordinates (nodal positions) --------------------------------- inline xt::xtensor Regular::coor() const { xt::xtensor out = xt::empty({m_nnode, m_ndim}); xt::xtensor x = xt::linspace(0.0, m_h*static_cast(m_nelx), m_nelx+1); xt::xtensor y = xt::linspace(0.0, m_h*static_cast(m_nely), m_nely+1); size_t inode = 0; for ( size_t iy = 0 ; iy < m_nely+1 ; ++iy ) { for ( size_t ix = 0 ; ix < m_nelx+1 ; ++ix ) { out(inode,0) = x(ix); out(inode,1) = y(iy); ++inode; } } return out; } // ---------------------------- connectivity (node-numbers per element) ---------------------------- inline xt::xtensor Regular::conn() const { xt::xtensor out = xt::empty({m_nelem,m_nne}); size_t ielem = 0; for ( size_t iy = 0 ; iy < m_nely ; ++iy ) { for ( size_t ix = 0 ; ix < m_nelx ; ++ix ) { out(ielem,0) = (iy )*(m_nelx+1) + (ix ); out(ielem,1) = (iy )*(m_nelx+1) + (ix+1); out(ielem,3) = (iy+1)*(m_nelx+1) + (ix ); out(ielem,2) = (iy+1)*(m_nelx+1) + (ix+1); ++ielem; } } return out; } // ------------------------------ node-numbers along the bottom edge ------------------------------- inline xt::xtensor Regular::nodesBottomEdge() const { xt::xtensor out = xt::empty({m_nelx+1}); for ( size_t ix = 0 ; ix < m_nelx+1 ; ++ix ) out(ix) = ix; return out; } // -------------------------------- node-numbers along the top edge -------------------------------- inline xt::xtensor Regular::nodesTopEdge() const { xt::xtensor out = xt::empty({m_nelx+1}); for ( size_t ix = 0 ; ix < m_nelx+1 ; ++ix ) out(ix) = ix + m_nely*(m_nelx+1); return out; } // ------------------------------- node-numbers along the left edge -------------------------------- inline xt::xtensor Regular::nodesLeftEdge() const { xt::xtensor out = xt::empty({m_nely+1}); for ( size_t iy = 0 ; iy < m_nely+1 ; ++iy ) out(iy) = iy*(m_nelx+1); return out; } // ------------------------------- node-numbers along the right edge ------------------------------- inline xt::xtensor Regular::nodesRightEdge() const { xt::xtensor out = xt::empty({m_nely+1}); for ( size_t iy = 0 ; iy < m_nely+1 ; ++iy ) out(iy) = iy*(m_nelx+1) + m_nelx; return out; } // ---------------------- node-numbers along the bottom edge, without corners ---------------------- inline xt::xtensor Regular::nodesBottomOpenEdge() const { xt::xtensor out = xt::empty({m_nelx-1}); for ( size_t ix = 1 ; ix < m_nelx ; ++ix ) out(ix-1) = ix; return out; } // ----------------------- node-numbers along the top edge, without corners ------------------------ inline xt::xtensor Regular::nodesTopOpenEdge() const { xt::xtensor out = xt::empty({m_nelx-1}); for ( size_t ix = 1 ; ix < m_nelx ; ++ix ) out(ix-1) = ix + m_nely*(m_nelx+1); return out; } // ----------------------- node-numbers along the left edge, without corners ----------------------- inline xt::xtensor Regular::nodesLeftOpenEdge() const { xt::xtensor out = xt::empty({m_nely-1}); for ( size_t iy = 1 ; iy < m_nely ; ++iy ) out(iy-1) = iy*(m_nelx+1); return out; } // ---------------------- node-numbers along the right edge, without corners ----------------------- inline xt::xtensor Regular::nodesRightOpenEdge() const { xt::xtensor out = xt::empty({m_nely-1}); for ( size_t iy = 1 ; iy < m_nely ; ++iy ) out(iy-1) = iy*(m_nelx+1) + m_nelx; return out; } // ----------------------------- node-number of the bottom-left corner ----------------------------- inline size_t Regular::nodesBottomLeftCorner() const { return 0; } // ---------------------------- node-number of the bottom-right corner ----------------------------- inline size_t Regular::nodesBottomRightCorner() const { return m_nelx; } // ------------------------------ node-number of the top-left corner ------------------------------- inline size_t Regular::nodesTopLeftCorner() const { return m_nely*(m_nelx+1); } // ------------------------------ node-number of the top-right corner ------------------------------ inline size_t Regular::nodesTopRightCorner() const { return m_nely*(m_nelx+1) + m_nelx; } // ----------------------------- node-number of the corners (aliases) ------------------------------ 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(); } // ------------------------------ node-numbers of periodic node-pairs ------------------------------ inline xt::xtensor Regular::nodesPeriodic() const { // edges (without corners) xt::xtensor bot = nodesBottomOpenEdge(); xt::xtensor top = nodesTopOpenEdge(); xt::xtensor lft = nodesLeftOpenEdge(); xt::xtensor rgt = nodesRightOpenEdge(); // allocate nodal ties // - number of tying per category size_t tedge = bot.size() + lft.size(); size_t tnode = 3; // - allocate xt::xtensor out = xt::empty({tedge+tnode, std::size_t(2)}); // counter size_t i = 0; // tie all corners to one corner out(i,0) = nodesBottomLeftCorner(); out(i,1) = nodesBottomRightCorner(); ++i; out(i,0) = nodesBottomLeftCorner(); out(i,1) = nodesTopRightCorner(); ++i; out(i,0) = nodesBottomLeftCorner(); out(i,1) = nodesTopLeftCorner(); ++i; // tie all corresponding edges to each other for ( size_t j = 0 ; j Regular::dofs() const { - return xGooseFEM::Mesh::dofs(m_nnode,m_ndim); + return GooseFEM::Mesh::dofs(m_nnode,m_ndim); } // ------------------------ DOP-numbers with periodic dependencies removed ------------------------- inline xt::xtensor Regular::dofsPeriodic() const { // DOF-numbers for each component of each node (sequential) - xt::xtensor out = xGooseFEM::Mesh::dofs(m_nnode,m_ndim); + xt::xtensor out = GooseFEM::Mesh::dofs(m_nnode,m_ndim); // periodic node-pairs xt::xtensor nodePer = nodesPeriodic(); // eliminate 'dependent' DOFs; renumber "out" to be sequential for the remaining DOFs for ( size_t i = 0 ; i < nodePer.shape()[0] ; ++i ) for ( size_t j = 0 ; j < m_ndim ; ++j ) out(nodePer(i,1),j) = out(nodePer(i,0),j); // renumber "out" to be sequential - return xGooseFEM::Mesh::renumber(out); + return GooseFEM::Mesh::renumber(out); } // ------------------------------------------ constructor ------------------------------------------ inline FineLayer::FineLayer(size_t nelx, size_t nely, double h, size_t nfine): m_h(h) { // basic assumptions assert( nelx >= 1 ); assert( nely >= 1 ); // store basic info m_Lx = m_h * static_cast(nelx); // compute element size in y-direction (use symmetry, compute upper half) // ---------------------------------------------------------------------- // temporary variables size_t nmin, ntot; xt::xtensor nhx = xt::ones({nely}); xt::xtensor nhy = xt::ones({nely}); xt::xtensor refine = -1 * xt::ones ({nely}); // 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 or ntot >= nmin ) { nely = iy; break; } // rules (1,2) satisfied: coarsen in x-direction if ( 3*nhy(iy) <= ntot and nelx%(3*nhx(iy)) == 0 and 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 or ntot >= nmin ) { nely = iy; break; } } // symmetrize, compute full information // ------------------------------------ // allocate mesh constructor parameters m_nhx = xt::empty({nely*2-1}); m_nhy = xt::empty({nely*2-1}); m_refine = xt::empty ({nely*2-1}); m_nelx = xt::empty({nely*2-1}); m_nnd = xt::empty({nely*2 }); m_startElem = xt::empty({nely*2-1}); m_startNode = xt::empty({nely*2 }); // fill // - lower half for ( size_t iy = 0 ; iy < nely ; ++iy ) { m_nhx (iy) = nhx (nely-iy-1); m_nhy (iy) = nhy (nely-iy-1); m_refine(iy) = refine(nely-iy-1); } // - upper half for ( size_t iy = 0 ; iy < nely-1 ; ++iy ) { m_nhx (iy+nely) = nhx (iy+1); m_nhy (iy+nely) = nhy (iy+1); m_refine(iy+nely) = refine(iy+1); } // update size nely = m_nhx.size(); // compute the number of elements per element layer in y-direction for ( size_t iy = 0 ; iy < nely ; ++iy ) m_nelx(iy) = nelx / m_nhx(iy); // compute the number of nodes per node layer in y-direction for ( size_t iy = 0 ; iy < (nely+1)/2 ; ++iy ) m_nnd(iy ) = m_nelx(iy)+1; for ( size_t iy = (nely-1)/2 ; iy < nely ; ++iy ) m_nnd(iy+1) = m_nelx(iy)+1; // compute mesh dimensions // ----------------------- // initialize m_nnode = 0; m_nelem = 0; m_startNode(0) = 0; // loop over element layers (bottom -> middle, elements become finer) for ( size_t i = 0 ; i < (nely-1)/2 ; ++i ) { // - store the first element of the layer m_startElem(i) = m_nelem; // - add the nodes of this layer if ( m_refine(i) == 0 ) { m_nnode += (3*m_nelx(i)+1); } else { m_nnode += ( m_nelx(i)+1); } // - add the elements of this layer if ( m_refine(i) == 0 ) { m_nelem += (4*m_nelx(i) ); } else { m_nelem += ( m_nelx(i) ); } // - store the starting node of the next layer m_startNode(i+1) = m_nnode; } // loop over element layers (middle -> top, elements become coarser) for ( size_t i = (nely-1)/2 ; i < nely ; ++i ) { // - store the first element of the layer m_startElem(i) = m_nelem; // - add the nodes of this layer if ( m_refine(i) == 0 ) { m_nnode += (5*m_nelx(i)+1); } else { m_nnode += ( m_nelx(i)+1); } // - add the elements of this layer if ( m_refine(i) == 0 ) { m_nelem += (4*m_nelx(i) ); } else { m_nelem += ( m_nelx(i) ); } // - store the starting node of the next layer m_startNode(i+1) = m_nnode; } // - add the top row of nodes m_nnode += m_nelx(nely-1)+1; } // -------------------------------------- number of elements --------------------------------------- inline size_t FineLayer::nelem() const { return m_nelem; } // ---------------------------------------- number of nodes ---------------------------------------- inline size_t FineLayer::nnode() const { return m_nnode; } // ---------------------------------- number of nodes per element ---------------------------------- inline size_t FineLayer::nne() const { return m_nne; } // ------------------------------------- number of dimensions -------------------------------------- inline size_t FineLayer::ndim() const { return m_ndim; } // ---------------------------- actual number of nodes in one direction ---------------------------- inline size_t FineLayer::shape(size_t i) const { assert( i >= 0 and i <= 1 ); if ( i == 0 ) return xt::amax(m_nelx)[0]; else return xt::sum (m_nhy )[0]; } // --------------------------------- coordinates (nodal positions) --------------------------------- inline xt::xtensor FineLayer::coor() const { // allocate output xt::xtensor out = xt::empty({m_nnode, m_ndim}); // current node, number of element layers size_t inode = 0; size_t nely = static_cast(m_nhy.size()); // y-position of each main node layer (i.e. excluding node layers for refinement/coarsening) // - allocate xt::xtensor y = xt::empty({nely+1}); // - initialize y(0) = 0.0; // - compute for ( size_t iy = 1 ; iy < nely+1 ; ++iy ) y(iy) = y(iy-1) + m_nhy(iy-1) * m_h; // loop over element layers (bottom -> middle) : add bottom layer (+ refinement layer) of nodes // -------------------------------------------------------------------------------------------- for ( size_t iy = 0 ; ; ++iy ) { // get positions along the x- and z-axis xt::xtensor x = xt::linspace(0.0, m_Lx, m_nelx(iy)+1); // add nodes of the bottom layer of this element for ( size_t ix = 0 ; ix < m_nelx(iy)+1 ; ++ix ) { out(inode,0) = x(ix); out(inode,1) = y(iy); ++inode; } // stop at middle layer if ( iy == (nely-1)/2 ) break; // add extra nodes of the intermediate layer, for refinement in x-direction if ( m_refine(iy) == 0 ) { // - get position offset in x- and y-direction double dx = m_h * static_cast(m_nhx(iy)/3); double dy = m_h * static_cast(m_nhy(iy)/2); // - add nodes of the intermediate layer for ( size_t ix = 0 ; ix < m_nelx(iy) ; ++ix ) { for ( size_t j = 0 ; j < 2 ; ++j ) { out(inode,0) = x(ix) + dx * static_cast(j+1); out(inode,1) = y(iy) + dy; ++inode; } } } } // loop over element layers (middle -> top) : add (refinement layer +) top layer of nodes // -------------------------------------------------------------------------------------- for ( size_t iy = (nely-1)/2 ; iy < nely ; ++iy ) { // get positions along the x- and z-axis xt::xtensor x = xt::linspace(0.0, m_Lx, m_nelx(iy)+1); // add extra nodes of the intermediate layer, for refinement in x-direction if ( m_refine(iy) == 0 ) { // - get position offset in x- and y-direction double dx = m_h * static_cast(m_nhx(iy)/3); double dy = m_h * static_cast(m_nhy(iy)/2); // - add nodes of the intermediate layer for ( size_t ix = 0 ; ix < m_nelx(iy) ; ++ix ) { for ( size_t j = 0 ; j < 2 ; ++j ) { out(inode,0) = x(ix) + dx * static_cast(j+1); out(inode,1) = y(iy) + dy; ++inode; } } } // add nodes of the top layer of this element for ( size_t ix = 0 ; ix < m_nelx(iy)+1 ; ++ix ) { out(inode,0) = x(ix ); out(inode,1) = y(iy+1); ++inode; } } return out; } // ---------------------------- connectivity (node-numbers per element) ---------------------------- inline xt::xtensor FineLayer::conn() const { // allocate output xt::xtensor out = xt::empty({m_nelem, m_nne}); // current element, number of element layers, starting nodes of each node layer size_t ielem = 0; size_t nely = static_cast(m_nhy.size()); size_t bot,mid,top; // loop over all element layers for ( size_t iy = 0 ; iy < nely ; ++iy ) { // - get: starting nodes of bottom(, middle) and top layer bot = m_startNode(iy ); mid = m_startNode(iy ) + m_nnd(iy); top = m_startNode(iy+1); // - define connectivity: no coarsening/refinement if ( m_refine(iy) == -1 ) { for ( size_t ix = 0 ; ix < m_nelx(iy) ; ++ix ) { out(ielem,0) = bot + (ix ); out(ielem,1) = bot + (ix+1); out(ielem,2) = top + (ix+1); out(ielem,3) = top + (ix ); ielem++; } } // - define connectivity: refinement along the x-direction (below the middle layer) else if ( m_refine(iy) == 0 and iy <= (nely-1)/2 ) { for ( size_t ix = 0 ; ix < m_nelx(iy) ; ++ix ) { // -- bottom element out(ielem,0) = bot + ( ix ); out(ielem,1) = bot + ( ix+1); out(ielem,2) = mid + (2*ix+1); out(ielem,3) = mid + (2*ix ); ielem++; // -- top-right element out(ielem,0) = bot + ( ix+1); out(ielem,1) = top + (3*ix+3); out(ielem,2) = top + (3*ix+2); out(ielem,3) = mid + (2*ix+1); ielem++; // -- top-center element out(ielem,0) = mid + (2*ix ); out(ielem,1) = mid + (2*ix+1); out(ielem,2) = top + (3*ix+2); out(ielem,3) = top + (3*ix+1); ielem++; // -- top-left element out(ielem,0) = bot + ( ix ); out(ielem,1) = mid + (2*ix ); out(ielem,2) = top + (3*ix+1); out(ielem,3) = top + (3*ix ); ielem++; } } // - define connectivity: coarsening along the x-direction (above the middle layer) else if ( m_refine(iy) == 0 and iy > (nely-1)/2 ) { for ( size_t ix = 0 ; ix < m_nelx(iy) ; ++ix ) { // -- lower-left element out(ielem,0) = bot + (3*ix ); out(ielem,1) = bot + (3*ix+1); out(ielem,2) = mid + (2*ix ); out(ielem,3) = top + ( ix ); ielem++; // -- lower-center element out(ielem,0) = bot + (3*ix+1); out(ielem,1) = bot + (3*ix+2); out(ielem,2) = mid + (2*ix+1); out(ielem,3) = mid + (2*ix ); ielem++; // -- lower-right element out(ielem,0) = bot + (3*ix+2); out(ielem,1) = bot + (3*ix+3); out(ielem,2) = top + ( ix+1); out(ielem,3) = mid + (2*ix+1); ielem++; // -- upper element out(ielem,0) = mid + (2*ix ); out(ielem,1) = mid + (2*ix+1); out(ielem,2) = top + ( ix+1); out(ielem,3) = top + ( ix ); ielem++; } } } return out; } // ------------------------------ element numbers of the middle layer ------------------------------ inline xt::xtensor FineLayer::elementsMiddleLayer() const { // number of element layers in y-direction, the index of the middle layer size_t nely = static_cast(m_nhy.size()); size_t iy = (nely-1)/2; xt::xtensor out = xt::empty({m_nelx(iy)}); for ( size_t ix = 0 ; ix < m_nelx(iy) ; ++ix ) out(ix) = m_startElem(iy) + ix; return out; } // ------------------------------ node-numbers along the bottom edge ------------------------------- inline xt::xtensor FineLayer::nodesBottomEdge() const { xt::xtensor out = xt::empty({m_nelx(0)+1}); for ( size_t ix = 0 ; ix < m_nelx(0)+1 ; ++ix ) out(ix) = m_startNode(0) + ix; return out; } // -------------------------------- node-numbers along the top edge -------------------------------- inline xt::xtensor FineLayer::nodesTopEdge() const { size_t nely = static_cast(m_nhy.size()); xt::xtensor out = xt::empty({m_nelx(nely-1)+1}); for ( size_t ix = 0 ; ix < m_nelx(nely-1)+1 ; ++ix ) out(ix) = m_startNode(nely) + ix; return out; } // ------------------------------- node-numbers along the left edge -------------------------------- inline xt::xtensor FineLayer::nodesLeftEdge() const { size_t nely = static_cast(m_nhy.size()); xt::xtensor out = xt::empty({nely+1}); for ( size_t iy = 0 ; iy < (nely+1)/2 ; ++iy ) out(iy) = m_startNode(iy); for ( size_t iy = (nely-1)/2 ; iy < nely ; ++iy ) out(iy+1) = m_startNode(iy+1); return out; } // ------------------------------- node-numbers along the right edge ------------------------------- inline xt::xtensor FineLayer::nodesRightEdge() const { size_t nely = static_cast(m_nhy.size()); xt::xtensor out = xt::empty({nely+1}); for ( size_t iy = 0 ; iy < (nely+1)/2 ; ++iy ) out(iy) = m_startNode(iy) + m_nelx(iy); for ( size_t iy = (nely-1)/2 ; iy < nely ; ++iy ) out(iy+1) = m_startNode(iy+1) + m_nelx(iy); return out; } // ---------------------- node-numbers along the bottom edge, without corners ---------------------- inline xt::xtensor FineLayer::nodesBottomOpenEdge() const { xt::xtensor out = xt::empty({m_nelx(0)-1}); for ( size_t ix = 1 ; ix < m_nelx(0) ; ++ix ) out(ix-1) = m_startNode(0) + ix; return out; } // ----------------------- node-numbers along the top edge, without corners ------------------------ inline xt::xtensor FineLayer::nodesTopOpenEdge() const { size_t nely = static_cast(m_nhy.size()); xt::xtensor out = xt::empty({m_nelx(nely-1)-1}); for ( size_t ix = 1 ; ix < m_nelx(nely-1) ; ++ix ) out(ix-1) = m_startNode(nely) + ix; return out; } // ----------------------- node-numbers along the left edge, without corners ----------------------- inline xt::xtensor FineLayer::nodesLeftOpenEdge() const { size_t nely = static_cast(m_nhy.size()); xt::xtensor out = xt::empty({nely-1}); for ( size_t iy = 1 ; iy < (nely+1)/2 ; ++iy ) out(iy-1) = m_startNode(iy); for ( size_t iy = (nely-1)/2 ; iy < nely-1 ; ++iy ) out(iy) = m_startNode(iy+1); return out; } // ---------------------- node-numbers along the right edge, without corners ----------------------- inline xt::xtensor FineLayer::nodesRightOpenEdge() const { size_t nely = static_cast(m_nhy.size()); xt::xtensor out = xt::empty({nely-1}); for ( size_t iy = 1 ; iy < (nely+1)/2 ; ++iy ) out(iy-1) = m_startNode(iy) + m_nelx(iy); for ( size_t iy = (nely-1)/2 ; iy < nely-1 ; ++iy ) out(iy) = m_startNode(iy+1) + m_nelx(iy); return out; } // ----------------------------- node-number of the bottom-left corner ----------------------------- inline size_t FineLayer::nodesBottomLeftCorner() const { return m_startNode(0); } // ---------------------------- node-number of the bottom-right corner ----------------------------- inline size_t FineLayer::nodesBottomRightCorner() const { return m_startNode(0) + m_nelx(0); } // ------------------------------ node-number of the top-left corner ------------------------------- inline size_t FineLayer::nodesTopLeftCorner() const { size_t nely = static_cast(m_nhy.size()); return m_startNode(nely); } // ------------------------------ node-number of the top-right corner ------------------------------ inline size_t FineLayer::nodesTopRightCorner() const { size_t nely = static_cast(m_nhy.size()); return m_startNode(nely) + m_nelx(nely-1); } // -------------------------------------------- aliases -------------------------------------------- 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(); } // ------------------------------ node-numbers of periodic node-pairs ------------------------------ inline xt::xtensor FineLayer::nodesPeriodic() const { // edges (without corners) xt::xtensor bot = nodesBottomOpenEdge(); xt::xtensor top = nodesTopOpenEdge(); xt::xtensor lft = nodesLeftOpenEdge(); xt::xtensor rgt = nodesRightOpenEdge(); // allocate nodal ties // - number of tying per category size_t tedge = bot.size() + lft.size(); size_t tnode = 3; // - allocate xt::xtensor out = xt::empty({tedge+tnode, std::size_t(2)}); // counter size_t i = 0; // tie all corners to one corner out(i,0) = nodesBottomLeftCorner(); out(i,1) = nodesBottomRightCorner(); ++i; out(i,0) = nodesBottomLeftCorner(); out(i,1) = nodesTopRightCorner(); ++i; out(i,0) = nodesBottomLeftCorner(); out(i,1) = nodesTopLeftCorner(); ++i; // tie all corresponding edges to each other for ( size_t j = 0 ; j FineLayer::dofs() const { - return xGooseFEM::Mesh::dofs(m_nnode,m_ndim); + return GooseFEM::Mesh::dofs(m_nnode,m_ndim); } // ------------------------ DOP-numbers with periodic dependencies removed ------------------------- inline xt::xtensor FineLayer::dofsPeriodic() const { // DOF-numbers for each component of each node (sequential) - xt::xtensor out = xGooseFEM::Mesh::dofs(m_nnode,m_ndim); + xt::xtensor out = GooseFEM::Mesh::dofs(m_nnode,m_ndim); // periodic node-pairs xt::xtensor nodePer = nodesPeriodic(); // eliminate 'dependent' DOFs; renumber "out" to be sequential for the remaining DOFs for ( size_t i = 0 ; i < nodePer.shape()[0] ; ++i ) for ( size_t j = 0 ; j < m_ndim ; ++j ) out(nodePer(i,1),j) = out(nodePer(i,0),j); // renumber "out" to be sequential - return xGooseFEM::Mesh::renumber(out); + return GooseFEM::Mesh::renumber(out); } // ------------------------------------------------------------------------------------------------- }}} // namespace ... // ================================================================================================= #endif diff --git a/include/xGooseFEM/MeshTri3.h b/include/GooseFEM/MeshTri3.h similarity index 98% rename from include/xGooseFEM/MeshTri3.h rename to include/GooseFEM/MeshTri3.h index f7232aa..60a00cb 100644 --- a/include/xGooseFEM/MeshTri3.h +++ b/include/GooseFEM/MeshTri3.h @@ -1,154 +1,154 @@ /* ================================================================================================= (c - GPLv3) T.W.J. de Geus (Tom) | tom@geus.me | www.geus.me | github.com/tdegeus/GooseFEM ================================================================================================= */ -#ifndef XGOOSEFEM_MESHTRI3_H -#define XGOOSEFEM_MESHTRI3_H +#ifndef GOOSEFEM_MESHTRI3_H +#define GOOSEFEM_MESHTRI3_H // ------------------------------------------------------------------------------------------------- #include "Mesh.h" // ===================================== GooseFEM::Mesh::Tri3 ====================================== -namespace xGooseFEM { +namespace GooseFEM { namespace Mesh { namespace Tri3 { // ------------------------------------------ regular mesh ----------------------------------------- class Regular { private: double m_h; // elementary element edge-size (in both directions) size_t m_nelx; // number of elements in x-direction (length == "m_nelx * m_h") size_t m_nely; // number of elements in y-direction (length == "m_nely * m_h") size_t m_nelem; // number of elements size_t m_nnode; // number of nodes static const size_t m_nne=3; // number of nodes-per-element static const size_t m_ndim=2; // number of dimensions public: // mesh with "2*nelx*nely" 'elements' of edge size "h" Regular(size_t nelx, size_t nely, double h=1.); // sizes 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 // mesh xt::xtensor coor() const; // nodal positions [nnode ,ndim] xt::xtensor conn() const; // connectivity [nelem ,nne ] // boundary nodes: edges xt::xtensor nodesBottomEdge() const; // node-numbers along the bottom edge xt::xtensor nodesTopEdge() const; // node-numbers along the top edge xt::xtensor nodesLeftEdge() const; // node-numbers along the left edge xt::xtensor nodesRightEdge() const; // node-numbers along the right edge // boundary nodes: edges, without corners xt::xtensor nodesBottomOpenEdge() const; // node-numbers along the bottom edge xt::xtensor nodesTopOpenEdge() const; // node-numbers along the top edge xt::xtensor nodesLeftOpenEdge() const; // node-numbers along the left edge xt::xtensor nodesRightOpenEdge() const; // node-numbers along the right edge // boundary nodes: corners size_t nodesBottomLeftCorner() const; // node-number of the bottom - left corner size_t nodesBottomRightCorner() const; // node-number of the bottom - right corner size_t nodesTopLeftCorner() const; // node-number of the top - left corner size_t nodesTopRightCorner() const; // node-number of the top - right corner // boundary nodes: corners (aliases) size_t nodesLeftBottomCorner() const; // alias, see above: nodesBottomLeftCorner size_t nodesLeftTopCorner() const; // alias, see above: nodesBottomRightCorner size_t nodesRightBottomCorner() const; // alias, see above: nodesTopLeftCorner size_t nodesRightTopCorner() const; // alias, see above: nodesTopRightCorner // periodicity xt::xtensor nodesPeriodic() const; // periodic node pairs [:,2]: (independent, dependent) size_t nodesOrigin() const; // bottom-left node, used as reference for periodicity xt::xtensor dofs() const; // DOF-numbers for each component of each node (sequential) xt::xtensor dofsPeriodic() const; // ,, for the case that the periodicity if fully eliminated }; // ----------------------------------------- mesh analysis ----------------------------------------- // read / set the orientation (-1 / +1) of all triangles inline xt::xtensor getOrientation(const xt::xtensor &coor, const xt::xtensor &conn ); inline xt::xtensor setOrientation(const xt::xtensor &coor, const xt::xtensor &conn, int orientation=-1); inline xt::xtensor setOrientation(const xt::xtensor &coor, const xt::xtensor &conn, const xt::xtensor &val, int orientation=-1); // --------------------------------------- re-triangulation ---------------------------------------- // simple interface to compute the full re-triangulation; it uses, depending on the input mesh: // (1) the minimal evasive "TriUpdate" // (2) the more rigorous "TriCompute" inline xt::xtensor retriangulate(const xt::xtensor &coor, const xt::xtensor &conn, int orientation=-1); // ================================= GooseFEM::Mesh::Tri3::Private ================================= namespace Private { // ------------------------- support class - update existing triangulation ------------------------- // minimal evasive re-triangulation which only flips edges of the existing connectivity class TriUpdate { private: size_t m_nelem; // #elements size_t m_nnode; // #nodes size_t m_nne; // #nodes-per-element size_t m_ndim; // #dimensions xt::xtensor m_edge; // the element that neighbors along each edge (m_nelem: no neighbor) xt::xtensor m_conn; // connectivity (updated) xt::xtensor m_coor; // nodal positions (does not change) xt::xtensor_fixed> m_elem; // the two elements in the last element change xt::xtensor_fixed> m_node; // the four nodes in the last element change // old: m_elem(0) = [ m_node(0) , m_node(1) , m_node(2) ] // m_elem(1) = [ m_node(1) , m_node(3) , m_node(2) ] // new: m_elem(0) = [ m_node(0) , m_node(3) , m_node(2) ] // m_elem(1) = [ m_node(0) , m_node(1) , m_node(3) ] // compute neighbors per edge of all elements void edge(); // update edges around renumbered elements void chedge(size_t edge, size_t old_elem, size_t new_elem); public: TriUpdate() = default; TriUpdate(const xt::xtensor &coor, const xt::xtensor &conn); bool eval (); // re-triangulate the full mesh (returns "true" if changed) bool increment(); // one re-triangulation step (returns "true" if changed) xt::xtensor conn() { return m_conn; }; // (new) connectivity xt::xtensor ch_elem() { return m_elem; }; // element involved in last element change xt::xtensor ch_node() { return m_node; }; // nodes involved in last element change }; // -------------------------------- support class - edge definition -------------------------------- // support class to allow the storage of a list of edges class Edge { public: size_t n1 ; // node 1 (edge from node 1-2) size_t n2 ; // node 2 (edge from node 1-2) size_t elem; // element to which the edge belong size_t edge; // edge index within the element (e.g. edge==1 -> n1=conn(0,elem), n2=conn(1,elem)) Edge() = default; Edge(size_t i, size_t j, size_t el, size_t ed, bool sort=false); }; // ------------------------------------------------------------------------------------------------- // compare edges inline bool Edge_cmp (Edge a, Edge b); // check equality inline bool Edge_sort(Edge a, Edge b); // check if "a" is smaller than "b" in terms of node-numbers // ------------------------------------------------------------------------------------------------- } // namespace Private // ------------------------------------------------------------------------------------------------- }}} // namespace ... #endif diff --git a/include/xGooseFEM/MeshTri3.hpp b/include/GooseFEM/MeshTri3.hpp similarity index 98% rename from include/xGooseFEM/MeshTri3.hpp rename to include/GooseFEM/MeshTri3.hpp index 0b8df90..185a2ae 100644 --- a/include/xGooseFEM/MeshTri3.hpp +++ b/include/GooseFEM/MeshTri3.hpp @@ -1,600 +1,600 @@ /* ================================================================================================= (c - GPLv3) T.W.J. de Geus (Tom) | tom@geus.me | www.geus.me | github.com/tdegeus/GooseFEM ================================================================================================= */ -#ifndef XGOOSEFEM_MESHTRI3_CPP -#define XGOOSEFEM_MESHTRI3_CPP +#ifndef GOOSEFEM_MESHTRI3_CPP +#define GOOSEFEM_MESHTRI3_CPP // ------------------------------------------------------------------------------------------------- #include "MeshTri3.h" // ===================================== GooseFEM::Mesh::Tri3 ====================================== -namespace xGooseFEM { +namespace GooseFEM { namespace Mesh { namespace Tri3 { // ------------------------------------------ constructor ------------------------------------------ inline Regular::Regular(size_t nelx, size_t nely, double h): m_h(h), m_nelx(nelx), m_nely(nely) { assert( m_nelx >= 1 ); assert( m_nely >= 1 ); m_nnode = (m_nelx+1) * (m_nely+1); m_nelem = m_nelx * m_nely * 2; } // -------------------------------------- number of elements --------------------------------------- inline size_t Regular::nelem() const { return m_nelem; } // ---------------------------------------- number of nodes ---------------------------------------- inline size_t Regular::nnode() const { return m_nnode; } // ---------------------------------- number of nodes per element ---------------------------------- inline size_t Regular::nne() const { return m_nne; } // ------------------------------------- number of dimensions -------------------------------------- inline size_t Regular::ndim() const { return m_ndim; } // --------------------------------- coordinates (nodal positions) --------------------------------- inline xt::xtensor Regular::coor() const { xt::xtensor out = xt::empty({m_nnode, m_ndim}); xt::xtensor x = xt::linspace(0.0, m_h*static_cast(m_nelx), m_nelx+1); xt::xtensor y = xt::linspace(0.0, m_h*static_cast(m_nely), m_nely+1); size_t inode = 0; for ( size_t iy = 0 ; iy < m_nely+1 ; ++iy ) { for ( size_t ix = 0 ; ix < m_nelx+1 ; ++ix ) { out(inode,0) = x(ix); out(inode,1) = y(iy); ++inode; } } return out; } // ---------------------------- connectivity (node-numbers per element) ---------------------------- inline xt::xtensor Regular::conn() const { xt::xtensor out = xt::empty({m_nelem,m_nne}); size_t ielem = 0; for ( size_t iy = 0 ; iy < m_nely ; ++iy ) { for ( size_t ix = 0 ; ix < m_nelx ; ++ix ) { out(ielem,0) = (iy )*(m_nelx+1) + (ix ); out(ielem,1) = (iy )*(m_nelx+1) + (ix+1); out(ielem,2) = (iy+1)*(m_nelx+1) + (ix ); ++ielem; out(ielem,0) = (iy )*(m_nelx+1) + (ix+1); out(ielem,1) = (iy+1)*(m_nelx+1) + (ix+1); out(ielem,2) = (iy+1)*(m_nelx+1) + (ix ); ++ielem; } } return out; } // ------------------------------ node-numbers along the bottom edge ------------------------------- inline xt::xtensor Regular::nodesBottomEdge() const { xt::xtensor out = xt::empty({m_nelx+1}); for ( size_t ix = 0 ; ix < m_nelx+1 ; ++ix ) out(ix) = ix; return out; } // -------------------------------- node-numbers along the top edge -------------------------------- inline xt::xtensor Regular::nodesTopEdge() const { xt::xtensor out = xt::empty({m_nelx+1}); for ( size_t ix = 0 ; ix < m_nelx+1 ; ++ix ) out(ix) = ix + m_nely*(m_nelx+1); return out; } // ------------------------------- node-numbers along the left edge -------------------------------- inline xt::xtensor Regular::nodesLeftEdge() const { xt::xtensor out = xt::empty({m_nely+1}); for ( size_t iy = 0 ; iy < m_nely+1 ; ++iy ) out(iy) = iy*(m_nelx+1); return out; } // ------------------------------- node-numbers along the right edge ------------------------------- inline xt::xtensor Regular::nodesRightEdge() const { xt::xtensor out = xt::empty({m_nely+1}); for ( size_t iy = 0 ; iy < m_nely+1 ; ++iy ) out(iy) = iy*(m_nelx+1) + m_nelx; return out; } // ---------------------- node-numbers along the bottom edge, without corners ---------------------- inline xt::xtensor Regular::nodesBottomOpenEdge() const { xt::xtensor out = xt::empty({m_nelx-1}); for ( size_t ix = 1 ; ix < m_nelx ; ++ix ) out(ix-1) = ix; return out; } // ----------------------- node-numbers along the top edge, without corners ------------------------ inline xt::xtensor Regular::nodesTopOpenEdge() const { xt::xtensor out = xt::empty({m_nelx-1}); for ( size_t ix = 1 ; ix < m_nelx ; ++ix ) out(ix-1) = ix + m_nely*(m_nelx+1); return out; } // ----------------------- node-numbers along the left edge, without corners ----------------------- inline xt::xtensor Regular::nodesLeftOpenEdge() const { xt::xtensor out = xt::empty({m_nely-1}); for ( size_t iy = 1 ; iy < m_nely ; ++iy ) out(iy-1) = iy*(m_nelx+1); return out; } // ---------------------- node-numbers along the right edge, without corners ----------------------- inline xt::xtensor Regular::nodesRightOpenEdge() const { xt::xtensor out = xt::empty({m_nely-1}); for ( size_t iy = 1 ; iy < m_nely ; ++iy ) out(iy-1) = iy*(m_nelx+1) + m_nelx; return out; } // ----------------------------- node-number of the bottom-left corner ----------------------------- inline size_t Regular::nodesBottomLeftCorner() const { return 0; } // ---------------------------- node-number of the bottom-right corner ----------------------------- inline size_t Regular::nodesBottomRightCorner() const { return m_nelx; } // ------------------------------ node-number of the top-left corner ------------------------------- inline size_t Regular::nodesTopLeftCorner() const { return m_nely*(m_nelx+1); } // ------------------------------ node-number of the top-right corner ------------------------------ inline size_t Regular::nodesTopRightCorner() const { return m_nely*(m_nelx+1) + m_nelx; } // ----------------------------- node-number of the corners (aliases) ------------------------------ 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(); } // ------------------------------ node-numbers of periodic node-pairs ------------------------------ inline xt::xtensor Regular::nodesPeriodic() const { // edges (without corners) xt::xtensor bot = nodesBottomOpenEdge(); xt::xtensor top = nodesTopOpenEdge(); xt::xtensor lft = nodesLeftOpenEdge(); xt::xtensor rgt = nodesRightOpenEdge(); // allocate nodal ties // - number of tying per category size_t tedge = bot.size() + lft.size(); size_t tnode = 3; // - allocate xt::xtensor out = xt::empty({tedge+tnode, std::size_t(2)}); // counter size_t i = 0; // tie all corners to one corner out(i,0) = nodesBottomLeftCorner(); out(i,1) = nodesBottomRightCorner(); ++i; out(i,0) = nodesBottomLeftCorner(); out(i,1) = nodesTopRightCorner(); ++i; out(i,0) = nodesBottomLeftCorner(); out(i,1) = nodesTopLeftCorner(); ++i; // tie all corresponding edges to each other for ( size_t j = 0 ; j Regular::dofs() const { - return xGooseFEM::Mesh::dofs(m_nnode,m_ndim); + return GooseFEM::Mesh::dofs(m_nnode,m_ndim); } // ------------------------ DOP-numbers with periodic dependencies removed ------------------------- inline xt::xtensor Regular::dofsPeriodic() const { // DOF-numbers for each component of each node (sequential) - xt::xtensor out = xGooseFEM::Mesh::dofs(m_nnode,m_ndim); + xt::xtensor out = GooseFEM::Mesh::dofs(m_nnode,m_ndim); // periodic node-pairs xt::xtensor nodePer = nodesPeriodic(); // eliminate 'dependent' DOFs; renumber "out" to be sequential for the remaining DOFs for ( size_t i = 0 ; i < nodePer.shape()[0] ; ++i ) for ( size_t j = 0 ; j < m_ndim ; ++j ) out(nodePer(i,1),j) = out(nodePer(i,0),j); // renumber "out" to be sequential - return xGooseFEM::Mesh::renumber(out); + return GooseFEM::Mesh::renumber(out); } // ------------------------------ get the orientation of each element ------------------------------ inline xt::xtensor getOrientation(const xt::xtensor &coor, const xt::xtensor &conn) { assert( conn.shape()[1] == 3 ); assert( coor.shape()[1] == 2 ); double k; size_t nelem = conn.shape()[0]; xt::xtensor out = xt::empty({nelem}); for ( size_t ielem = 0 ; ielem < nelem ; ++ielem ) { auto v1 = xt::view(coor, conn(ielem,0), xt::all()) - xt::view(coor, conn(ielem,1), xt::all()); auto v2 = xt::view(coor, conn(ielem,2), xt::all()) - xt::view(coor, conn(ielem,1), xt::all()); k = v1(0) * v2(1) - v2(0) * v1(1); if ( k < 0 ) out(ielem) = -1; else out(ielem) = +1; } return out; } // ------------------------------ set the orientation of each element ------------------------------ inline xt::xtensor setOrientation(const xt::xtensor &coor, const xt::xtensor &conn, int orientation) { assert( conn.shape()[1] == 3 ); assert( coor.shape()[1] == 2 ); assert( orientation == -1 || orientation == +1 ); xt::xtensor val = getOrientation(coor, conn); return setOrientation(coor, conn, val, orientation); } // -------------------- set the orientation of each element to a certain value --------------------- inline xt::xtensor setOrientation(const xt::xtensor &coor, const xt::xtensor &conn, const xt::xtensor &val, int orientation) { assert( conn.shape()[1] == 3 ); assert( coor.shape()[1] == 2 ); assert( conn.shape()[0] == val.size() ); assert( orientation == -1 || orientation == +1 ); // avoid compiler warning UNUSED(coor); size_t nelem = conn.shape()[0]; xt::xtensor out = conn; for ( size_t ielem = 0 ; ielem < nelem ; ++ielem ) if ( ( orientation == -1 and val(ielem) > 0 ) or ( orientation == +1 and val(ielem) < 0 ) ) std::swap( out(ielem,2) , out(ielem,1) ); return out; } // ------------------------------------- re-triangulation API -------------------------------------- inline xt::xtensor retriangulate(const xt::xtensor &coor, const xt::xtensor &conn, int orientation) { // get the orientation of all elements xt::xtensor dir = getOrientation(coor, conn); // check the orientation bool eq = static_cast(std::abs(xt::sum(dir)[0])) == conn.shape()[0]; // new connectivity xt::xtensor out; // perform re-triangulation // - use "TriUpdate" if ( eq ) { Private::TriUpdate obj(coor,conn); obj.eval(); out = obj.conn(); } // - using TriCompute else { throw std::runtime_error("Work-in-progress, has to be re-triangulated using 'TriCompute'"); } return setOrientation(coor,out,orientation); } // ================================= GooseFEM::Mesh::Tri3::Private ================================= namespace Private { // ------------------------------------------ constructor ------------------------------------------ inline TriUpdate::TriUpdate(const xt::xtensor &coor, const xt::xtensor &conn): m_conn(conn), m_coor(coor) { assert( conn.shape()[1] == 3 ); assert( coor.shape()[1] == 2 ); // store shapes m_nnode = coor.shape()[0]; m_ndim = coor.shape()[1]; m_nelem = conn.shape()[0]; m_nne = conn.shape()[1]; // set default to out-of-bounds, to make clear that nothing happened yet m_elem = m_nelem * xt::ones({2}); m_node = m_nnode * xt::ones({4}); edge(); } // -------------------------- compute neighbors per edge of all elements --------------------------- inline void TriUpdate::edge() { // signal that nothing has been set m_edge = m_nelem * xt::ones({m_nelem , m_nne}); std::vector idx = {0,1,2}; // lists to convert connectivity -> edges std::vector jdx = {1,2,0}; // lists to convert connectivity -> edges std::vector edge; edge.reserve(m_nelem*idx.size()); for ( size_t e = 0 ; e < m_nelem ; ++e ) for ( size_t i = 0 ; i < m_nne ; ++i ) edge.push_back( Edge( m_conn(e,idx[i]), m_conn(e,jdx[i]) , e , i , true ) ); std::sort( edge.begin() , edge.end() , Edge_sort ); for ( size_t i = 0 ; i < edge.size()-1 ; ++i ) { if ( edge[i].n1 == edge[i+1].n1 and edge[i].n2 == edge[i+1].n2 ) { m_edge( edge[i ].elem , edge[i ].edge ) = edge[i+1].elem; m_edge( edge[i+1].elem , edge[i+1].edge ) = edge[i ].elem; } } } // ---------------------------- update edges around renumbered elements ---------------------------- inline void TriUpdate::chedge(size_t edge, size_t old_elem, size_t new_elem) { size_t m; size_t neigh = m_edge(old_elem , edge); if ( neigh >= m_nelem ) return; for ( m = 0 ; m < m_nne ; ++m ) if ( m_edge( neigh , m ) == old_elem ) break; m_edge( neigh , m ) = new_elem; } // --------------------------------- re-triangulate the full mesh ---------------------------------- inline bool TriUpdate::eval() { bool change = false; while ( increment() ) { change = true; } return change; } // ----------------------------------- one re-triangulation step ----------------------------------- inline bool TriUpdate::increment() { size_t ielem,jelem,iedge,jedge; double phi1,phi2; xt::xtensor_fixed> c = xt::empty({4}); xt::xtensor_fixed> n = xt::empty({4}); // loop over all elements for ( ielem = 0 ; ielem < m_nelem ; ++ielem ) { // loop over all edges for ( iedge = 0 ; iedge < m_nne ; ++iedge ) { // only proceed if the edge is shared with another element if ( m_edge(ielem,iedge) >= m_nelem ) continue; // read "jelem" jelem = m_edge(ielem,iedge); // find the edge involved for "jelem" for ( jedge=0; jedge M_PI ) { // update connectivity m_conn(ielem,0) = c(0); m_conn(ielem,1) = c(3); m_conn(ielem,2) = c(2); m_conn(jelem,0) = c(0); m_conn(jelem,1) = c(1); m_conn(jelem,2) = c(3); // change list with neighbors for the elements around (only two neighbors change) if ( iedge==0 ) { chedge(2,ielem,jelem); } else if ( iedge==1 ) { chedge(0,ielem,jelem); } else if ( iedge==2 ) { chedge(1,ielem,jelem); } if ( jedge==0 ) { chedge(2,jelem,ielem); } else if ( jedge==1 ) { chedge(0,jelem,ielem); } else if ( jedge==2 ) { chedge(1,jelem,ielem); } // convert to four static nodes if ( iedge==0 ) { n(0)=m_edge(ielem,2); n(3)=m_edge(ielem,1); } else if ( iedge==1 ) { n(0)=m_edge(ielem,0); n(3)=m_edge(ielem,2); } else if ( iedge==2 ) { n(0)=m_edge(ielem,1); n(3)=m_edge(ielem,0); } if ( jedge==0 ) { n(1)=m_edge(jelem,1); n(2)=m_edge(jelem,2); } else if ( jedge==1 ) { n(1)=m_edge(jelem,2); n(2)=m_edge(jelem,0); } else if ( jedge==2 ) { n(1)=m_edge(jelem,0); n(2)=m_edge(jelem,1); } // store the neighbors for the changed elements m_edge(ielem,0) = jelem; m_edge(jelem,0) = n(0) ; m_edge(ielem,1) = n(2) ; m_edge(jelem,1) = n(1) ; m_edge(ielem,2) = n(3) ; m_edge(jelem,2) = ielem; // store information for transfer algorithm m_node = c; m_elem(0) = ielem; m_elem(1) = jelem; return true; } } } return false; } // ------------------------------------------ constructor ------------------------------------------ inline Edge::Edge(size_t i, size_t j, size_t el, size_t ed, bool sort): n1(i), n2(j), elem(el), edge(ed) { if ( sort && n1>n2 ) std::swap(n1,n2); } // --------------------------------------- compare two edges --------------------------------------- inline bool Edge_cmp(Edge a, Edge b) { if ( a.n1 == b.n1 and a.n2 == b.n2 ) return true; return false; } // ----------------------- sort edges by comparing the first and second node ----------------------- inline bool Edge_sort(Edge a, Edge b) { if ( a.n1 < b.n1 or a.n2 < b.n2 ) return true; return false; } // ------------------------------------------------------------------------------------------------- } // namespace Private // ------------------------------------------------------------------------------------------------- }}} // namespace ... // ================================================================================================= #endif diff --git a/include/xGooseFEM/Vector.h b/include/GooseFEM/Vector.h similarity index 98% rename from include/xGooseFEM/Vector.h rename to include/GooseFEM/Vector.h index 2e85114..4a35328 100644 --- a/include/xGooseFEM/Vector.h +++ b/include/GooseFEM/Vector.h @@ -1,126 +1,126 @@ /* ================================================================================================= (c - GPLv3) T.W.J. de Geus (Tom) | tom@geus.me | www.geus.me | github.com/tdegeus/GooseFEM ================================================================================================= */ -#ifndef XGOOSEFEM_VECTOR_H -#define XGOOSEFEM_VECTOR_H +#ifndef GOOSEFEM_VECTOR_H +#define GOOSEFEM_VECTOR_H // ------------------------------------------------------------------------------------------------- #include "GooseFEM.h" // =========================================== GooseFEM ============================================ -namespace xGooseFEM { +namespace GooseFEM { // ------------------------------------------------------------------------------------------------- /* "nodevec" - nodal vectors - [nnode, ndim] "elemvec" - nodal vectors stored per element - [nelem, nne, ndim] "dofval" - DOF values - [ndof] */ class Vector { public: // constructor Vector() = default; Vector(const xt::xtensor &conn, const xt::xtensor &dofs); // dimensions size_t nelem() const; // number of elements size_t nne() const; // number of nodes per element size_t nnode() const; // number of nodes size_t ndim() const; // number of dimensions size_t ndof() const; // number of DOFs // DOF lists xt::xtensor dofs() const; // DOFs // convert to "dofval" (overwrite entries that occur more than once) -- (auto allocation below) void asDofs(const xt::xtensor &nodevec, xt::xtensor &dofval) const; void asDofs(const xt::xtensor &elemvec, xt::xtensor &dofval) const; // convert to "nodevec" (overwrite entries that occur more than once) -- (auto allocation below) void asNode(const xt::xtensor &dofval, xt::xtensor &nodevec) const; void asNode(const xt::xtensor &elemvec, xt::xtensor &nodevec) const; // convert to "elemvec" (overwrite entries that occur more than once) -- (auto allocation below) void asElement(const xt::xtensor &dofval, xt::xtensor &elemvec) const; void asElement(const xt::xtensor &nodevec, xt::xtensor &elemvec) const; // assemble "dofval" (adds entries that occur more that once) -- (auto allocation below) void assembleDofs(const xt::xtensor &nodevec, xt::xtensor &dofval) const; void assembleDofs(const xt::xtensor &elemvec, xt::xtensor &dofval) const; // assemble "nodevec" (adds entries that occur more that once) -- (auto allocation below) void assembleNode(const xt::xtensor &elemvec, xt::xtensor &nodevec) const; // auto allocation of the functions above xt::xtensor asDofs(const xt::xtensor &nodevec) const; xt::xtensor asDofs(const xt::xtensor &elemvec) const; xt::xtensor asNode(const xt::xtensor &dofval) const; xt::xtensor asNode(const xt::xtensor &elemvec) const; xt::xtensor asElement(const xt::xtensor &dofval) const; xt::xtensor asElement(const xt::xtensor &nodevec) const; xt::xtensor assembleDofs(const xt::xtensor &nodevec) const; xt::xtensor assembleDofs(const xt::xtensor &elemvec) const; xt::xtensor assembleNode(const xt::xtensor &elemvec) const; private: // bookkeeping xt::xtensor m_conn; // connectivity [nelem, nne ] xt::xtensor m_dofs; // DOF-numbers per node [nnode, ndim] // dimensions size_t m_nelem; // number of elements size_t m_nne; // number of nodes per element size_t m_nnode; // number of nodes size_t m_ndim; // number of dimensions size_t m_ndof; // number of DOFs }; // ------------------------------------------------------------------------------------------------- } // namespace ... // ================================================================================================= #endif diff --git a/include/xGooseFEM/Vector.hpp b/include/GooseFEM/Vector.hpp similarity index 99% rename from include/xGooseFEM/Vector.hpp rename to include/GooseFEM/Vector.hpp index e99bc65..b3ad85e 100644 --- a/include/xGooseFEM/Vector.hpp +++ b/include/GooseFEM/Vector.hpp @@ -1,337 +1,337 @@ /* ================================================================================================= (c - GPLv3) T.W.J. de Geus (Tom) | tom@geus.me | www.geus.me | github.com/tdegeus/GooseFEM ================================================================================================= */ -#ifndef XGOOSEFEM_VECTOR_CPP -#define XGOOSEFEM_VECTOR_CPP +#ifndef GOOSEFEM_VECTOR_CPP +#define GOOSEFEM_VECTOR_CPP // ------------------------------------------------------------------------------------------------- #include "Vector.h" // ================================================================================================= -namespace xGooseFEM { +namespace GooseFEM { // ------------------------------------------------------------------------------------------------- inline Vector::Vector(const xt::xtensor &conn, const xt::xtensor &dofs) : m_conn(conn), m_dofs(dofs) { // mesh dimensions m_nelem = m_conn.shape()[0]; m_nne = m_conn.shape()[1]; m_nnode = m_dofs.shape()[0]; m_ndim = m_dofs.shape()[1]; // dimensions of the system m_ndof = xt::amax(m_dofs)[0] + 1; // check consistency assert( xt::amax(m_conn)[0] + 1 == m_nnode ); assert( m_ndof <= m_nnode * m_ndim ); } // ------------------------------------------------------------------------------------------------- inline size_t Vector::nelem() const { return m_nelem; } // ------------------------------------------------------------------------------------------------- inline size_t Vector::nne() const { return m_nne; } // ------------------------------------------------------------------------------------------------- inline size_t Vector::nnode() const { return m_nnode; } // ------------------------------------------------------------------------------------------------- inline size_t Vector::ndim() const { return m_ndim; } // ------------------------------------------------------------------------------------------------- inline size_t Vector::ndof() const { return m_ndof; } // ------------------------------------------------------------------------------------------------- inline xt::xtensor Vector::dofs() const { return m_dofs; } // ------------------------------------------------------------------------------------------------- inline void Vector::asDofs(const xt::xtensor &nodevec, xt::xtensor &dofval) const { assert( nodevec.shape()[0] == m_nnode ); assert( nodevec.shape()[1] == m_ndim ); assert( dofval.size() == m_ndof ); #pragma omp parallel for for ( size_t n = 0 ; n < m_nnode ; ++n ) for ( size_t i = 0 ; i < m_ndim ; ++i ) dofval(m_dofs(n,i)) = nodevec(n,i); } // ------------------------------------------------------------------------------------------------- inline void Vector::asDofs(const xt::xtensor &elemvec, xt::xtensor &dofval) const { assert( elemvec.shape()[0] == m_nelem ); assert( elemvec.shape()[1] == m_nne ); assert( elemvec.shape()[2] == m_ndim ); assert( dofval.size() == m_ndof ); #pragma omp parallel for for ( size_t e = 0 ; e < m_nelem ; ++e ) for ( size_t m = 0 ; m < m_nne ; ++m ) for ( size_t i = 0 ; i < m_ndim ; ++i ) dofval(m_dofs(m_conn(e,m),i)) = elemvec(e,m,i); } // ------------------------------------------------------------------------------------------------- inline void Vector::asNode(const xt::xtensor &dofval, xt::xtensor &nodevec) const { assert( dofval.size() == m_ndof ); assert( nodevec.shape()[0] == m_nnode ); assert( nodevec.shape()[1] == m_ndim ); #pragma omp parallel for for ( size_t n = 0 ; n < m_nnode ; ++n ) for ( size_t i = 0 ; i < m_ndim ; ++i ) nodevec(n,i) = dofval(m_dofs(n,i)); } // ------------------------------------------------------------------------------------------------- inline void Vector::asNode(const xt::xtensor &elemvec, xt::xtensor &nodevec) const { assert( elemvec.shape()[0] == m_nelem ); assert( elemvec.shape()[1] == m_nne ); assert( elemvec.shape()[2] == m_ndim ); assert( nodevec.shape()[0] == m_nnode ); assert( nodevec.shape()[1] == m_ndim ); #pragma omp parallel for for ( size_t e = 0 ; e < m_nelem ; ++e ) for ( size_t m = 0 ; m < m_nne ; ++m ) for ( size_t i = 0 ; i < m_ndim ; ++i ) nodevec(m_conn(e,m),i) = elemvec(e,m,i); } // ------------------------------------------------------------------------------------------------- inline void Vector::asElement(const xt::xtensor &dofval, xt::xtensor &elemvec) const { assert( dofval.size() == m_ndof ); assert( elemvec.shape()[0] == m_nelem ); assert( elemvec.shape()[1] == m_nne ); assert( elemvec.shape()[2] == m_ndim ); #pragma omp parallel for for ( size_t e = 0 ; e < m_nelem ; ++e ) for ( size_t m = 0 ; m < m_nne ; ++m ) for ( size_t i = 0 ; i < m_ndim ; ++i ) elemvec(e,m,i) = dofval(m_dofs(m_conn(e,m),i)); } // ------------------------------------------------------------------------------------------------- inline void Vector::asElement(const xt::xtensor &nodevec, xt::xtensor &elemvec) const { assert( nodevec.shape()[0] == m_nnode ); assert( nodevec.shape()[1] == m_ndim ); assert( elemvec.shape()[0] == m_nelem ); assert( elemvec.shape()[1] == m_nne ); assert( elemvec.shape()[2] == m_ndim ); #pragma omp parallel for for ( size_t e = 0 ; e < m_nelem ; ++e ) for ( size_t m = 0 ; m < m_nne ; ++m ) for ( size_t i = 0 ; i < m_ndim ; ++i ) elemvec(e,m,i) = nodevec(m_conn(e,m),i); } // ------------------------------------------------------------------------------------------------- inline void Vector::assembleDofs(const xt::xtensor &nodevec, xt::xtensor &dofval) const { assert( nodevec.shape()[0] == m_nnode ); assert( nodevec.shape()[1] == m_ndim ); assert( dofval.size() == m_ndof ); dofval.fill(0.0); for ( size_t n = 0 ; n < m_nnode ; ++n ) for ( size_t i = 0 ; i < m_ndim ; ++i ) dofval(m_dofs(n,i)) += nodevec(n,i); } // ------------------------------------------------------------------------------------------------- inline void Vector::assembleDofs(const xt::xtensor &elemvec, xt::xtensor &dofval) const { assert( elemvec.shape()[0] == m_nelem ); assert( elemvec.shape()[1] == m_nne ); assert( elemvec.shape()[2] == m_ndim ); assert( dofval.size() == m_ndof ); dofval.fill(0.0); for ( size_t e = 0 ; e < m_nelem ; ++e ) for ( size_t m = 0 ; m < m_nne ; ++m ) for ( size_t i = 0 ; i < m_ndim ; ++i ) dofval(m_dofs(m_conn(e,m),i)) += elemvec(e,m,i); } // ------------------------------------------------------------------------------------------------- inline void Vector::assembleNode(const xt::xtensor &elemvec, xt::xtensor &nodevec) const { assert( elemvec.shape()[0] == m_nelem ); assert( elemvec.shape()[1] == m_nne ); assert( elemvec.shape()[2] == m_ndim ); assert( nodevec.shape()[0] == m_nnode ); assert( nodevec.shape()[1] == m_ndim ); nodevec.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 ) nodevec(m_conn(e,m),i) += elemvec(e,m,i); } // ------------------------------------------------------------------------------------------------- inline xt::xtensor Vector::asDofs(const xt::xtensor &nodevec) const { xt::xtensor dofval = xt::empty({m_ndof}); this->asDofs(nodevec, dofval); return dofval; } // ------------------------------------------------------------------------------------------------- inline xt::xtensor Vector::asDofs(const xt::xtensor &elemvec) const { xt::xtensor dofval = xt::empty({m_ndof}); this->asDofs(elemvec, dofval); return dofval; } // ------------------------------------------------------------------------------------------------- inline xt::xtensor Vector::asNode(const xt::xtensor &dofval) const { xt::xtensor nodevec = xt::empty({m_nnode, m_ndim}); this->asNode(dofval, nodevec); return nodevec; } // ------------------------------------------------------------------------------------------------- inline xt::xtensor Vector::asNode(const xt::xtensor &elemvec) const { xt::xtensor nodevec = xt::empty({m_nnode, m_ndim}); this->asNode(elemvec, nodevec); return nodevec; } // ------------------------------------------------------------------------------------------------- inline xt::xtensor Vector::asElement(const xt::xtensor &dofval) const { xt::xtensor elemvec = xt::empty({m_nelem, m_nne, m_ndim}); this->asElement(dofval, elemvec); return elemvec; } // ------------------------------------------------------------------------------------------------- inline xt::xtensor Vector::asElement(const xt::xtensor &nodevec) const { xt::xtensor elemvec = xt::empty({m_nelem, m_nne, m_ndim}); this->asElement(nodevec, elemvec); return elemvec; } // ------------------------------------------------------------------------------------------------- inline xt::xtensor Vector::assembleDofs(const xt::xtensor &nodevec) const { xt::xtensor dofval = xt::empty({m_ndof}); this->assembleDofs(nodevec, dofval); return dofval; } // ------------------------------------------------------------------------------------------------- inline xt::xtensor Vector::assembleDofs(const xt::xtensor &elemvec) const { xt::xtensor dofval = xt::empty({m_ndof}); this->assembleDofs(elemvec, dofval); return dofval; } // ------------------------------------------------------------------------------------------------- inline xt::xtensor Vector::assembleNode(const xt::xtensor &elemvec) const { xt::xtensor nodevec = xt::empty({m_nnode, m_ndim}); this->assembleNode(elemvec, nodevec); return nodevec; } // ------------------------------------------------------------------------------------------------- } // namespace ... // ================================================================================================= #endif diff --git a/include/xGooseFEM/VectorPartitioned.h b/include/GooseFEM/VectorPartitioned.h similarity index 98% rename from include/xGooseFEM/VectorPartitioned.h rename to include/GooseFEM/VectorPartitioned.h index 540a242..9912ea3 100644 --- a/include/xGooseFEM/VectorPartitioned.h +++ b/include/GooseFEM/VectorPartitioned.h @@ -1,194 +1,194 @@ /* ================================================================================================= (c - GPLv3) T.W.J. de Geus (Tom) | tom@geus.me | www.geus.me | github.com/tdegeus/GooseFEM ================================================================================================= */ -#ifndef XGOOSEFEM_VECTORPARTITIONED_H -#define XGOOSEFEM_VECTORPARTITIONED_H +#ifndef GOOSEFEM_VECTORPARTITIONED_H +#define GOOSEFEM_VECTORPARTITIONED_H // ------------------------------------------------------------------------------------------------- #include "GooseFEM.h" // =========================================== GooseFEM ============================================ -namespace xGooseFEM { +namespace GooseFEM { // ------------------------------------------------------------------------------------------------- /* "nodevec" - nodal vectors - [nnode, ndim] "elemvec" - nodal vectors stored per element - [nelem, nne, ndim] "dofval" - DOF values - [ndof] "dofval_u" - DOF values (Unknown) "== dofval[iiu]" - [nnu] "dofval_p" - DOF values (Prescribed) "== dofval[iiu]" - [nnp] */ class VectorPartitioned { public: // constructor VectorPartitioned() = default; VectorPartitioned(const xt::xtensor &conn, const xt::xtensor &dofs, const xt::xtensor &iip); // dimensions size_t nelem() const; // number of elements size_t nne() const; // number of nodes per element size_t nnode() const; // number of nodes size_t ndim() const; // number of dimensions size_t ndof() const; // number of DOFs size_t nnu() const; // number of unknown DOFs size_t nnp() const; // number of prescribed DOFs // DOF lists xt::xtensor dofs() const; // DOFs xt::xtensor iiu() const; // unknown DOFs xt::xtensor iip() const; // prescribed DOFs // convert to "dofval" (overwrite entries that occur more than once) -- (auto allocation below) void asDofs (const xt::xtensor &dofval_u, const xt::xtensor &dofval_p, xt::xtensor &dofval) const; void asDofs (const xt::xtensor &nodevec, xt::xtensor &dofval) const; void asDofs (const xt::xtensor &elemvec, xt::xtensor &dofval) const; void asDofs_u(const xt::xtensor &nodevec, xt::xtensor &dofval_u) const; void asDofs_u(const xt::xtensor &elemvec, xt::xtensor &dofval_u) const; void asDofs_p(const xt::xtensor &nodevec, xt::xtensor &dofval_p) const; void asDofs_p(const xt::xtensor &elemvec, xt::xtensor &dofval_p) const; // convert to "nodevec" (overwrite entries that occur more than once) -- (auto allocation below) void asNode(const xt::xtensor &dofval_u, const xt::xtensor &dofval_p, xt::xtensor &nodevec) const; void asNode(const xt::xtensor &dofval, xt::xtensor &nodevec) const; void asNode(const xt::xtensor &elemvec, xt::xtensor &nodevec) const; // convert to "elemvec" (overwrite entries that occur more than once) -- (auto allocation below) void asElement(const xt::xtensor &dofval_u, const xt::xtensor &dofval_p, xt::xtensor &elemvec) const; void asElement(const xt::xtensor &dofval, xt::xtensor &elemvec) const; void asElement(const xt::xtensor &nodevec, xt::xtensor &elemvec) const; // assemble "dofval" (adds entries that occur more that once) -- (auto allocation below) void assembleDofs (const xt::xtensor &nodevec, xt::xtensor &dofval ) const; void assembleDofs (const xt::xtensor &elemvec, xt::xtensor &dofval ) const; void assembleDofs_u(const xt::xtensor &nodevec, xt::xtensor &dofval_u) const; void assembleDofs_u(const xt::xtensor &elemvec, xt::xtensor &dofval_u) const; void assembleDofs_p(const xt::xtensor &nodevec, xt::xtensor &dofval_p) const; void assembleDofs_p(const xt::xtensor &elemvec, xt::xtensor &dofval_p) const; // assemble "nodevec" (adds entries that occur more that once) -- (auto allocation below) void assembleNode(const xt::xtensor &elemvec, xt::xtensor &nodevec) const; // auto allocation of the functions above xt::xtensor asDofs (const xt::xtensor &dofval_u, const xt::xtensor &dofval_p) const; xt::xtensor asDofs (const xt::xtensor &nodevec) const; xt::xtensor asDofs (const xt::xtensor &elemvec) const; xt::xtensor asDofs_u(const xt::xtensor &nodevec) const; xt::xtensor asDofs_u(const xt::xtensor &elemvec) const; xt::xtensor asDofs_p(const xt::xtensor &nodevec) const; xt::xtensor asDofs_p(const xt::xtensor &elemvec) const; xt::xtensor asNode(const xt::xtensor &dofval_u, const xt::xtensor &dofval_p) const; xt::xtensor asNode(const xt::xtensor &dofval) const; xt::xtensor asNode(const xt::xtensor &elemvec) const; xt::xtensor asElement(const xt::xtensor &dofval_u, const xt::xtensor &dofval_p) const; xt::xtensor asElement(const xt::xtensor &dofval) const; xt::xtensor asElement(const xt::xtensor &nodevec) const; xt::xtensor assembleDofs (const xt::xtensor &nodevec) const; xt::xtensor assembleDofs (const xt::xtensor &elemvec) const; xt::xtensor assembleDofs_u(const xt::xtensor &nodevec) const; xt::xtensor assembleDofs_u(const xt::xtensor &elemvec) const; xt::xtensor assembleDofs_p(const xt::xtensor &nodevec) const; xt::xtensor assembleDofs_p(const xt::xtensor &elemvec) const; xt::xtensor assembleNode(const xt::xtensor &elemvec) const; private: // bookkeeping xt::xtensor m_conn; // connectivity [nelem, nne ] xt::xtensor m_dofs; // DOF-numbers per node [nnode, ndim] xt::xtensor m_iiu; // DOF-numbers that are unknown [nnu] xt::xtensor m_iip; // DOF-numbers that are prescribed [nnp] // DOFs per node, such that iiu = arange(nnu), iip = nnu + arange(nnp) xt::xtensor m_part; // dimensions size_t m_nelem; // number of elements size_t m_nne; // number of nodes per element size_t m_nnode; // number of nodes size_t m_ndim; // number of dimensions size_t m_ndof; // number of DOFs size_t m_nnu; // number of unknown DOFs size_t m_nnp; // number of prescribed DOFs }; // ------------------------------------------------------------------------------------------------- } // namespace ... // ================================================================================================= #endif diff --git a/include/xGooseFEM/VectorPartitioned.hpp b/include/GooseFEM/VectorPartitioned.hpp similarity index 99% rename from include/xGooseFEM/VectorPartitioned.hpp rename to include/GooseFEM/VectorPartitioned.hpp index c0fe780..110d5fd 100644 --- a/include/xGooseFEM/VectorPartitioned.hpp +++ b/include/GooseFEM/VectorPartitioned.hpp @@ -1,703 +1,703 @@ /* ================================================================================================= (c - GPLv3) T.W.J. de Geus (Tom) | tom@geus.me | www.geus.me | github.com/tdegeus/GooseFEM ================================================================================================= */ -#ifndef XGOOSEFEM_VECTORPARTITIONED_CPP -#define XGOOSEFEM_VECTORPARTITIONED_CPP +#ifndef GOOSEFEM_VECTORPARTITIONED_CPP +#define GOOSEFEM_VECTORPARTITIONED_CPP // ------------------------------------------------------------------------------------------------- #include "VectorPartitioned.h" // ================================================================================================= -namespace xGooseFEM { +namespace GooseFEM { // ------------------------------------------------------------------------------------------------- inline VectorPartitioned::VectorPartitioned(const xt::xtensor &conn, const xt::xtensor &dofs, const xt::xtensor &iip) : m_conn(conn), m_dofs(dofs), m_iip(iip) { // mesh dimensions m_nelem = m_conn.shape()[0]; m_nne = m_conn.shape()[1]; m_nnode = m_dofs.shape()[0]; m_ndim = m_dofs.shape()[1]; // list with unknown DOFs m_iiu = xt::setdiff1d(dofs, iip); // dimensions of the system m_ndof = xt::amax(m_dofs)[0] + 1; m_nnp = m_iip.size(); m_nnu = m_iiu.size(); // DOFs per node, such that iiu = arange(nnu), iip = nnu + arange(nnp) m_part = Mesh::reorder(m_dofs, m_iip, "end"); // check consistency assert( xt::amax(m_conn)[0] + 1 == m_nnode ); assert( xt::amax(m_iip)[0] <= xt::amax(m_dofs)[0] ); assert( m_ndof <= m_nnode * m_ndim ); } // ------------------------------------------------------------------------------------------------- inline size_t VectorPartitioned::nelem() const { return m_nelem; } // ------------------------------------------------------------------------------------------------- inline size_t VectorPartitioned::nne() const { return m_nne; } // ------------------------------------------------------------------------------------------------- inline size_t VectorPartitioned::nnode() const { return m_nnode; } // ------------------------------------------------------------------------------------------------- inline size_t VectorPartitioned::ndim() const { return m_ndim; } // ------------------------------------------------------------------------------------------------- inline size_t VectorPartitioned::ndof() const { return m_ndof; } // ------------------------------------------------------------------------------------------------- inline size_t VectorPartitioned::nnu() const { return m_nnu; } // ------------------------------------------------------------------------------------------------- inline size_t VectorPartitioned::nnp() const { return m_nnp; } // ------------------------------------------------------------------------------------------------- inline xt::xtensor VectorPartitioned::dofs() const { return m_dofs; } // ------------------------------------------------------------------------------------------------- inline xt::xtensor VectorPartitioned::iiu() const { return m_iiu; } // ------------------------------------------------------------------------------------------------- inline xt::xtensor VectorPartitioned::iip() const { return m_iip; } // ------------------- assemble: dofval[iiu] = dofval_u; dofval[iip] = dofval_p -------------------- inline void VectorPartitioned::asDofs(const xt::xtensor &dofval_u, const xt::xtensor &dofval_p, xt::xtensor &dofval) const { assert( dofval_u.size() == m_nnu ); assert( dofval_p.size() == m_nnp ); assert( dofval.size() == m_ndof ); #pragma omp parallel for for ( size_t i = 0 ; i < m_nnu ; ++i ) dofval(m_iiu(i)) = dofval_u(i); #pragma omp parallel for for ( size_t i = 0 ; i < m_nnp ; ++i ) dofval(m_iip(i)) = dofval_p(i); } // ------------------------------------------------------------------------------------------------- inline xt::xtensor VectorPartitioned::asDofs(const xt::xtensor &dofval_u, const xt::xtensor &dofval_p) const { xt::xtensor dofval = xt::empty({m_ndof}); this->asDofs(dofval_u, dofval_p, dofval); return dofval; } // ------------------------------------------------------------------------------------------------- inline void VectorPartitioned::asDofs(const xt::xtensor &nodevec, xt::xtensor &dofval) const { assert( nodevec.shape()[0] == m_nnode ); assert( nodevec.shape()[1] == m_ndim ); assert( dofval.size() == m_ndof ); #pragma omp parallel for for ( size_t n = 0 ; n < m_nnode ; ++n ) for ( size_t i = 0 ; i < m_ndim ; ++i ) dofval(m_dofs(n,i)) = nodevec(n,i); } // ------------------------------------------------------------------------------------------------- inline void VectorPartitioned::asDofs_u(const xt::xtensor &nodevec, xt::xtensor &dofval_u) const { assert( nodevec.shape()[0] == m_nnode ); assert( nodevec.shape()[1] == m_ndim ); assert( dofval_u.size() == m_nnu ); #pragma omp parallel for for ( size_t n = 0 ; n < m_nnode ; ++n ) for ( size_t i = 0 ; i < m_ndim ; ++i ) if ( m_part(n,i) < m_nnu ) dofval_u(m_part(n,i)) = nodevec(n,i); } // ------------------------------------------------------------------------------------------------- inline void VectorPartitioned::asDofs_p(const xt::xtensor &nodevec, xt::xtensor &dofval_p) const { assert( nodevec.shape()[0] == m_nnode ); assert( nodevec.shape()[1] == m_ndim ); assert( dofval_p.size() == m_nnp ); #pragma omp parallel for for ( size_t n = 0 ; n < m_nnode ; ++n ) for ( size_t i = 0 ; i < m_ndim ; ++i ) if ( m_part(n,i) >= m_nnu ) dofval_p(m_part(n,i)-m_nnu) = nodevec(n,i); } // ------------------------------------------------------------------------------------------------- inline void VectorPartitioned::asDofs(const xt::xtensor &elemvec, xt::xtensor &dofval) const { assert( elemvec.shape()[0] == m_nelem ); assert( elemvec.shape()[1] == m_nne ); assert( elemvec.shape()[2] == m_ndim ); assert( dofval.size() == m_ndof ); #pragma omp parallel for for ( size_t e = 0 ; e < m_nelem ; ++e ) for ( size_t m = 0 ; m < m_nne ; ++m ) for ( size_t i = 0 ; i < m_ndim ; ++i ) dofval(m_dofs(m_conn(e,m),i)) = elemvec(e,m,i); } // ------------------------------------------------------------------------------------------------- inline void VectorPartitioned::asDofs_u(const xt::xtensor &elemvec, xt::xtensor &dofval_u) const { assert( elemvec.shape()[0] == m_nelem ); assert( elemvec.shape()[1] == m_nne ); assert( elemvec.shape()[2] == m_ndim ); assert( dofval_u.size() == m_nnu ); #pragma omp parallel for for ( size_t e = 0 ; e < m_nelem ; ++e ) for ( size_t m = 0 ; m < m_nne ; ++m ) for ( size_t i = 0 ; i < m_ndim ; ++i ) if ( m_part(m_conn(e,m),i) < m_nnu ) dofval_u(m_part(m_conn(e,m),i)) = elemvec(e,m,i); } // ------------------------------------------------------------------------------------------------- inline void VectorPartitioned::asDofs_p(const xt::xtensor &elemvec, xt::xtensor &dofval_p) const { assert( elemvec.shape()[0] == m_nelem ); assert( elemvec.shape()[1] == m_nne ); assert( elemvec.shape()[2] == m_ndim ); assert( dofval_p.size() == m_nnp ); #pragma omp parallel for for ( size_t e = 0 ; e < m_nelem ; ++e ) for ( size_t m = 0 ; m < m_nne ; ++m ) for ( size_t i = 0 ; i < m_ndim ; ++i ) if ( m_part(m_conn(e,m),i) >= m_nnu ) dofval_p(m_part(m_conn(e,m),i)-m_nnu) = elemvec(e,m,i); } // ------------------------------------------------------------------------------------------------- inline void VectorPartitioned::asNode(const xt::xtensor &dofval, xt::xtensor &nodevec) const { assert( dofval.size() == m_ndof ); assert( nodevec.shape()[0] == m_nnode ); assert( nodevec.shape()[1] == m_ndim ); #pragma omp parallel for for ( size_t n = 0 ; n < m_nnode ; ++n ) for ( size_t i = 0 ; i < m_ndim ; ++i ) nodevec(n,i) = dofval(m_dofs(n,i)); } // ------------------------------------------------------------------------------------------------- inline void VectorPartitioned::asNode(const xt::xtensor &dofval_u, const xt::xtensor &dofval_p, xt::xtensor &nodevec) const { assert( dofval_u.size() == m_nnu ); assert( dofval_p.size() == m_nnp ); assert( nodevec.shape()[0] == m_nnode ); assert( nodevec.shape()[1] == m_ndim ); #pragma omp parallel for for ( size_t n = 0 ; n < m_nnode ; ++n ) { for ( size_t i = 0 ; i < m_ndim ; ++i ) { if ( m_part(n,i) < m_nnu ) nodevec(n,i) = dofval_u(m_part(n,i) ); else nodevec(n,i) = dofval_p(m_part(n,i)-m_nnu); } } } // ------------------------------------------------------------------------------------------------- inline void VectorPartitioned::asNode(const xt::xtensor &elemvec, xt::xtensor &nodevec) const { assert( elemvec.shape()[0] == m_nelem ); assert( elemvec.shape()[1] == m_nne ); assert( elemvec.shape()[2] == m_ndim ); assert( nodevec.shape()[0] == m_nnode ); assert( nodevec.shape()[1] == m_ndim ); #pragma omp parallel for for ( size_t e = 0 ; e < m_nelem ; ++e ) for ( size_t m = 0 ; m < m_nne ; ++m ) for ( size_t i = 0 ; i < m_ndim ; ++i ) nodevec(m_conn(e,m),i) = elemvec(e,m,i); } // ------------------------------------------------------------------------------------------------- inline void VectorPartitioned::asElement(const xt::xtensor &dofval, xt::xtensor &elemvec) const { assert( dofval.size() == m_ndof ); assert( elemvec.shape()[0] == m_nelem ); assert( elemvec.shape()[1] == m_nne ); assert( elemvec.shape()[2] == m_ndim ); #pragma omp parallel for for ( size_t e = 0 ; e < m_nelem ; ++e ) for ( size_t m = 0 ; m < m_nne ; ++m ) for ( size_t i = 0 ; i < m_ndim ; ++i ) elemvec(e,m,i) = dofval(m_dofs(m_conn(e,m),i)); } // ------------------------------------------------------------------------------------------------- inline void VectorPartitioned::asElement(const xt::xtensor &dofval_u, const xt::xtensor &dofval_p, xt::xtensor &elemvec) const { assert( dofval_u.size() == m_nnu ); assert( dofval_p.size() == m_nnp ); assert( elemvec.shape()[0] == m_nelem ); assert( elemvec.shape()[1] == m_nne ); assert( elemvec.shape()[2] == 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) &nodevec, xt::xtensor &elemvec) const { assert( nodevec.shape()[0] == m_nnode ); assert( nodevec.shape()[1] == m_ndim ); assert( elemvec.shape()[0] == m_nelem ); assert( elemvec.shape()[1] == m_nne ); assert( elemvec.shape()[2] == m_ndim ); #pragma omp parallel for for ( size_t e = 0 ; e < m_nelem ; ++e ) for ( size_t m = 0 ; m < m_nne ; ++m ) for ( size_t i = 0 ; i < m_ndim ; ++i ) elemvec(e,m,i) = nodevec(m_conn(e,m),i); } // ------------------------------------------------------------------------------------------------- inline void VectorPartitioned::assembleDofs(const xt::xtensor &nodevec, xt::xtensor &dofval) const { assert( nodevec.shape()[0] == m_nnode ); assert( nodevec.shape()[1] == m_ndim ); assert( dofval.size() == m_ndof ); dofval.fill(0.0); for ( size_t n = 0 ; n < m_nnode ; ++n ) for ( size_t i = 0 ; i < m_ndim ; ++i ) dofval(m_dofs(n,i)) += nodevec(n,i); } // ------------------------------------------------------------------------------------------------- inline void VectorPartitioned::assembleDofs_u(const xt::xtensor &nodevec, xt::xtensor &dofval_u) const { assert( nodevec.shape()[0] == m_nnode ); assert( nodevec.shape()[1] == m_ndim ); assert( dofval_u.size() == m_nnu ); dofval_u.fill(0.0); for ( size_t n = 0 ; n < m_nnode ; ++n ) for ( size_t i = 0 ; i < m_ndim ; ++i ) if ( m_part(n,i) < m_nnu ) dofval_u(m_part(n,i)) += nodevec(n,i); } // ------------------------------------------------------------------------------------------------- inline void VectorPartitioned::assembleDofs_p(const xt::xtensor &nodevec, xt::xtensor &dofval_p) const { assert( nodevec.shape()[0] == m_nnode ); assert( nodevec.shape()[1] == m_ndim ); assert( dofval_p.size() == m_nnp ); dofval_p.fill(0.0); for ( size_t n = 0 ; n < m_nnode ; ++n ) for ( size_t i = 0 ; i < m_ndim ; ++i ) if ( m_part(n,i) >= m_nnu ) dofval_p(m_part(n,i)-m_nnu) += nodevec(n,i); } // ------------------------------------------------------------------------------------------------- inline void VectorPartitioned::assembleDofs(const xt::xtensor &elemvec, xt::xtensor &dofval) const { assert( elemvec.shape()[0] == m_nelem ); assert( elemvec.shape()[1] == m_nne ); assert( elemvec.shape()[2] == m_ndim ); assert( dofval.size() == m_ndof ); dofval.fill(0.0); for ( size_t e = 0 ; e < m_nelem ; ++e ) for ( size_t m = 0 ; m < m_nne ; ++m ) for ( size_t i = 0 ; i < m_ndim ; ++i ) dofval(m_dofs(m_conn(e,m),i)) += elemvec(e,m,i); } // ------------------------------------------------------------------------------------------------- inline void VectorPartitioned::assembleDofs_u(const xt::xtensor &elemvec, xt::xtensor &dofval_u) const { assert( elemvec.shape()[0] == m_nelem ); assert( elemvec.shape()[1] == m_nne ); assert( elemvec.shape()[2] == m_ndim ); 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_dofs(m_conn(e,m),i)) += elemvec(e,m,i); } // ------------------------------------------------------------------------------------------------- inline void VectorPartitioned::assembleDofs_p(const xt::xtensor &elemvec, xt::xtensor &dofval_p) const { assert( elemvec.shape()[0] == m_nelem ); assert( elemvec.shape()[1] == m_nne ); assert( elemvec.shape()[2] == m_ndim ); 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_dofs(m_conn(e,m),i)-m_nnu) += elemvec(e,m,i); } // ------------------------------------------------------------------------------------------------- inline void VectorPartitioned::assembleNode(const xt::xtensor &elemvec, xt::xtensor &nodevec) const { assert( elemvec.shape()[0] == m_nelem ); assert( elemvec.shape()[1] == m_nne ); assert( elemvec.shape()[2] == m_ndim ); assert( nodevec.shape()[0] == m_nnode ); assert( nodevec.shape()[1] == m_ndim ); nodevec.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 ) nodevec(m_conn(e,m),i) += elemvec(e,m,i); } // ------------------------------------------------------------------------------------------------- inline xt::xtensor VectorPartitioned::asDofs(const xt::xtensor &nodevec) const { xt::xtensor dofval = xt::empty({m_ndof}); this->asDofs(nodevec, dofval); return dofval; } // ------------------------------------------------------------------------------------------------- inline xt::xtensor VectorPartitioned::asDofs_u(const xt::xtensor &nodevec) const { xt::xtensor dofval_u = xt::empty({m_nnu}); this->asDofs_u(nodevec, dofval_u); return dofval_u; } // ------------------------------------------------------------------------------------------------- inline xt::xtensor VectorPartitioned::asDofs_p(const xt::xtensor &nodevec) const { xt::xtensor dofval_p = xt::empty({m_nnp}); this->asDofs_p(nodevec, dofval_p); return dofval_p; } // ------------------------------------------------------------------------------------------------- inline xt::xtensor VectorPartitioned::asDofs(const xt::xtensor &elemvec) const { xt::xtensor dofval = xt::empty({m_ndof}); this->asDofs(elemvec, dofval); return dofval; } // ------------------------------------------------------------------------------------------------- inline xt::xtensor VectorPartitioned::asDofs_u(const xt::xtensor &elemvec) const { xt::xtensor dofval_u = xt::empty({m_nnu}); this->asDofs_u(elemvec, dofval_u); return dofval_u; } // ------------------------------------------------------------------------------------------------- inline xt::xtensor VectorPartitioned::asDofs_p(const xt::xtensor &elemvec) const { xt::xtensor dofval_p = xt::empty({m_nnp}); this->asDofs_p(elemvec, dofval_p); return dofval_p; } // ------------------------------------------------------------------------------------------------- inline xt::xtensor VectorPartitioned::asNode(const xt::xtensor &dofval) const { xt::xtensor nodevec = xt::empty({m_nnode, m_ndim}); this->asNode(dofval, nodevec); return nodevec; } // ------------------------------------------------------------------------------------------------- inline xt::xtensor VectorPartitioned::asNode(const xt::xtensor &dofval_u, const xt::xtensor &dofval_p) const { xt::xtensor nodevec = xt::empty({m_nnode, m_ndim}); this->asNode(dofval_u, dofval_p, nodevec); return nodevec; } // ------------------------------------------------------------------------------------------------- inline xt::xtensor VectorPartitioned::asNode(const xt::xtensor &elemvec) const { xt::xtensor nodevec = xt::empty({m_nnode, m_ndim}); this->asNode(elemvec, nodevec); return nodevec; } // ------------------------------------------------------------------------------------------------- inline xt::xtensor VectorPartitioned::asElement(const xt::xtensor &dofval) const { xt::xtensor elemvec = xt::empty({m_nelem, m_nne, m_ndim}); this->asElement(dofval, elemvec); return elemvec; } // ------------------------------------------------------------------------------------------------- inline xt::xtensor VectorPartitioned::asElement(const xt::xtensor &dofval_u, const xt::xtensor &dofval_p) const { xt::xtensor elemvec = xt::empty({m_nelem, m_nne, m_ndim}); this->asElement(dofval_u, dofval_p, elemvec); return elemvec; } // ------------------------------------------------------------------------------------------------- inline xt::xtensor VectorPartitioned::asElement(const xt::xtensor &nodevec) const { xt::xtensor elemvec = xt::empty({m_nelem, m_nne, m_ndim}); this->asElement(nodevec, elemvec); return elemvec; } // ------------------------------------------------------------------------------------------------- inline xt::xtensor VectorPartitioned::assembleDofs( const xt::xtensor &nodevec) const { xt::xtensor dofval = xt::empty({m_ndof}); this->assembleDofs(nodevec, dofval); return dofval; } // ------------------------------------------------------------------------------------------------- inline xt::xtensor VectorPartitioned::assembleDofs_u( const xt::xtensor &nodevec) const { xt::xtensor dofval_u = xt::empty({m_nnu}); this->assembleDofs_u(nodevec, dofval_u); return dofval_u; } // ------------------------------------------------------------------------------------------------- inline xt::xtensor VectorPartitioned::assembleDofs_p( const xt::xtensor &nodevec) const { xt::xtensor dofval_p = xt::empty({m_nnp}); this->assembleDofs_p(nodevec, dofval_p); return dofval_p; } // ------------------------------------------------------------------------------------------------- inline xt::xtensor VectorPartitioned::assembleDofs( const xt::xtensor &elemvec) const { xt::xtensor dofval = xt::empty({m_ndof}); this->assembleDofs(elemvec, dofval); return dofval; } // ------------------------------------------------------------------------------------------------- inline xt::xtensor VectorPartitioned::assembleDofs_u( const xt::xtensor &elemvec) const { xt::xtensor dofval_u = xt::empty({m_nnu}); this->assembleDofs_u(elemvec, dofval_u); return dofval_u; } // ------------------------------------------------------------------------------------------------- inline xt::xtensor VectorPartitioned::assembleDofs_p( const xt::xtensor &elemvec) const { xt::xtensor dofval_p = xt::empty({m_nnp}); this->assembleDofs_p(elemvec, dofval_p); return dofval_p; } // ------------------------------------------------------------------------------------------------- inline xt::xtensor VectorPartitioned::assembleNode( const xt::xtensor &elemvec) const { xt::xtensor nodevec = xt::empty({m_nnode, m_ndim}); this->assembleNode(elemvec, nodevec); return nodevec; } // ------------------------------------------------------------------------------------------------- } // namespace ... // ================================================================================================= #endif diff --git a/include/GooseFEM/python.cpp b/include/GooseFEM/python.cpp new file mode 100644 index 0000000..8c282ed --- /dev/null +++ b/include/GooseFEM/python.cpp @@ -0,0 +1,757 @@ +/* ================================================================================================= + +(c - GPLv3) T.W.J. de Geus (Tom) | tom@geus.me | www.geus.me | github.com/tdegeus/GooseFEM + +================================================================================================= */ + +#include +#include + +#include +#include + +#include + +#include + +#include "GooseFEM.h" + +// ================================================================================================= + +namespace py = pybind11; +namespace M = GooseFEM; + +// ======================================= trampoline class ======================================== + +class PyGeometry : public GooseFEM::Dynamics::Geometry +{ +public: + using GooseFEM::Dynamics::Geometry::Geometry; + using Arr1 = xt::xtensor; + using Arr2 = xt::xtensor; + using Arr3 = xt::xtensor; + + xt::xtensor solve_A() override { PYBIND11_OVERLOAD_PURE( Arr1, GooseFEM::Dynamics::Geometry, solve_A ); } + xt::xtensor solve_V() override { PYBIND11_OVERLOAD_PURE( Arr1, GooseFEM::Dynamics::Geometry, solve_V ); } + xt::xtensor u() const override { PYBIND11_OVERLOAD_PURE( Arr2, GooseFEM::Dynamics::Geometry, u ); } + xt::xtensor v() const override { PYBIND11_OVERLOAD_PURE( Arr2, GooseFEM::Dynamics::Geometry, v ); } + xt::xtensor a() const override { PYBIND11_OVERLOAD_PURE( Arr2, GooseFEM::Dynamics::Geometry, a ); } + xt::xtensor dofs_u() const override { PYBIND11_OVERLOAD_PURE( Arr1, GooseFEM::Dynamics::Geometry, dofs_u ); } + xt::xtensor dofs_v() const override { PYBIND11_OVERLOAD_PURE( Arr1, GooseFEM::Dynamics::Geometry, dofs_v ); } + xt::xtensor dofs_a() const override { PYBIND11_OVERLOAD_PURE( Arr1, GooseFEM::Dynamics::Geometry, dofs_a ); } + + void set_u(const xt::xtensor &nodevec) override { PYBIND11_OVERLOAD_PURE( void, GooseFEM::Dynamics::Geometry, set_u , nodevec); } + void set_u(const xt::xtensor &dofval ) override { PYBIND11_OVERLOAD_PURE( void, GooseFEM::Dynamics::Geometry, set_u , dofval ); } + void set_v(const xt::xtensor &dofval ) override { PYBIND11_OVERLOAD_PURE( void, GooseFEM::Dynamics::Geometry, set_v , dofval ); } + void set_a(const xt::xtensor &dofval ) override { PYBIND11_OVERLOAD_PURE( void, GooseFEM::Dynamics::Geometry, set_a , dofval ); } +}; + +// =========================================== GooseFEM ============================================ + +PYBIND11_MODULE(GooseFEM, m) { + +m.doc() = "Some simple finite element meshes and operations"; + +// ======================================== GooseFEM.Vector ======================================== + +py::class_(m, "VectorPartitioned") + + .def(py::init &, const xt::xtensor &, const xt::xtensor &>(), "Switch between dofval/nodevec/elemvec", py::arg("conn"), py::arg("dofs"), py::arg("iip")) + + .def("nelem", &M::VectorPartitioned::nelem, "Return number of element") + .def("nne" , &M::VectorPartitioned::nne , "Return number of nodes per element") + .def("nnode", &M::VectorPartitioned::nnode, "Return number of nodes") + .def("ndim" , &M::VectorPartitioned::ndim , "Return number of dimensions") + .def("ndof" , &M::VectorPartitioned::ndof , "Return number of degrees-of-freedom") + .def("nnu" , &M::VectorPartitioned::nnu , "Return number of unknown degrees-of-freedom") + .def("nnp" , &M::VectorPartitioned::nnp , "Return number of prescribed degrees-of-freedom") + + .def("dofs" , &M::VectorPartitioned::dofs , "Return degrees-of-freedom") + .def("iiu" , &M::VectorPartitioned::iiu , "Return unknown degrees-of-freedom") + .def("iip" , &M::VectorPartitioned::iip , "Return prescribed degrees-of-freedom") + + .def("asDofs" , py::overload_cast&,const xt::xtensor&>(&M::VectorPartitioned::asDofs , py::const_), "Set 'dofval" , py::arg("dofval_u"), py::arg("dofval_p")) + .def("asDofs" , py::overload_cast& >(&M::VectorPartitioned::asDofs , py::const_), "Set 'dofval" , py::arg("nodevec")) + .def("asDofs" , py::overload_cast& >(&M::VectorPartitioned::asDofs , py::const_), "Set 'dofval" , py::arg("elemvec")) + .def("asDofs_u" , py::overload_cast& >(&M::VectorPartitioned::asDofs_u , py::const_), "Set 'dofval" , py::arg("nodevec")) + .def("asDofs_u" , py::overload_cast& >(&M::VectorPartitioned::asDofs_u , py::const_), "Set 'dofval" , py::arg("elemvec")) + .def("asDofs_p" , py::overload_cast& >(&M::VectorPartitioned::asDofs_p , py::const_), "Set 'dofval" , py::arg("nodevec")) + .def("asDofs_p" , py::overload_cast& >(&M::VectorPartitioned::asDofs_p , py::const_), "Set 'dofval" , py::arg("elemvec")) + + .def("asNode" , py::overload_cast&,const xt::xtensor&>(&M::VectorPartitioned::asNode , py::const_), "Set 'nodevec", py::arg("dofval_u"), py::arg("dofval_p")) + .def("asNode" , py::overload_cast& >(&M::VectorPartitioned::asNode , py::const_), "Set 'nodevec", py::arg("dofval")) + .def("asNode" , py::overload_cast& >(&M::VectorPartitioned::asNode , py::const_), "Set 'nodevec", py::arg("elemvec")) + + .def("asElement", py::overload_cast&,const xt::xtensor&>(&M::VectorPartitioned::asElement, py::const_), "Set 'elemvec", py::arg("dofval_u"), py::arg("dofval_p")) + .def("asElement", py::overload_cast& >(&M::VectorPartitioned::asElement, py::const_), "Set 'elemvec", py::arg("dofval")) + .def("asElement", py::overload_cast& >(&M::VectorPartitioned::asElement, py::const_), "Set 'elemvec", py::arg("nodevec")) + + .def("assembleDofs" , py::overload_cast&>(&M::VectorPartitioned::assembleDofs , py::const_), "Assemble 'dofval'" , py::arg("nodevec")) + .def("assembleDofs" , py::overload_cast&>(&M::VectorPartitioned::assembleDofs , py::const_), "Assemble 'dofval'" , py::arg("elemvec")) + .def("assembleDofs_u", py::overload_cast&>(&M::VectorPartitioned::assembleDofs_u, py::const_), "Assemble 'dofval'" , py::arg("nodevec")) + .def("assembleDofs_u", py::overload_cast&>(&M::VectorPartitioned::assembleDofs_u, py::const_), "Assemble 'dofval'" , py::arg("elemvec")) + .def("assembleDofs_p", py::overload_cast&>(&M::VectorPartitioned::assembleDofs_p, py::const_), "Assemble 'dofval'" , py::arg("nodevec")) + .def("assembleDofs_p", py::overload_cast&>(&M::VectorPartitioned::assembleDofs_p, py::const_), "Assemble 'dofval'" , py::arg("elemvec")) + + .def("assembleNode" , py::overload_cast&>(&M::VectorPartitioned::assembleNode , py::const_), "Assemble 'nodevec'", py::arg("elemvec")) + + .def("__repr__", [](const GooseFEM::VectorPartitioned &){ return ""; }); + +// ==================================== GooseFEM.MatrixDiagonalPartitioned ==================================== + +py::class_(m, "MatrixDiagonalPartitioned") + + .def(py::init &, const xt::xtensor &, const xt::xtensor &>(), "Diagonal matrix", py::arg("conn"), py::arg("dofs"), py::arg("iip")) + + .def("nelem", &M::MatrixDiagonalPartitioned::nelem, "Return number of element") + .def("nne" , &M::MatrixDiagonalPartitioned::nne , "Return number of nodes per element") + .def("nnode", &M::MatrixDiagonalPartitioned::nnode, "Return number of nodes") + .def("ndim" , &M::MatrixDiagonalPartitioned::ndim , "Return number of dimensions") + .def("ndof" , &M::MatrixDiagonalPartitioned::ndof , "Return number of degrees-of-freedom") + .def("nnu" , &M::MatrixDiagonalPartitioned::nnu , "Return number of unknown degrees-of-freedom") + .def("nnp" , &M::MatrixDiagonalPartitioned::nnp , "Return number of prescribed degrees-of-freedom") + + .def("dofs" , &M::MatrixDiagonalPartitioned::dofs , "Return degrees-of-freedom") + .def("iiu" , &M::MatrixDiagonalPartitioned::iiu , "Return unknown degrees-of-freedom") + .def("iip" , &M::MatrixDiagonalPartitioned::iip , "Return prescribed degrees-of-freedom") + + .def("dot" , &M::MatrixDiagonalPartitioned::dot , "Dot product 'b_i = A_ij * x_j", py::arg("x")) + .def("dot_u", &M::MatrixDiagonalPartitioned::dot_u, "Dot product 'b_i = A_ij * x_j", py::arg("x_u"), py::arg("x_p")) + .def("dot_p", &M::MatrixDiagonalPartitioned::dot_p, "Dot product 'b_i = A_ij * x_j", py::arg("x_u"), py::arg("x_p")) + + .def("assemble", &M::MatrixDiagonalPartitioned::assemble, "Assemble from 'elemmat", py::arg("elemmat")) + + .def("solve", &M::MatrixDiagonalPartitioned::solve, "Solve", py::arg("b_u"), py::arg("x_p")) + + .def("asDiagonal", &M::MatrixDiagonalPartitioned::asDiagonal, "Return as diagonal matrix (column)") + + .def("__repr__", [](const GooseFEM::MatrixDiagonalPartitioned &){ return ""; }); + +// ======================================= GooseFEM.Dynamics ======================================= + +py::module mDynamics = m.def_submodule("Dynamics", "Solve routines for dynamic FEM"); + +// ------------------------------------------------------------------------------------------------- + +mDynamics.def("Verlet" , &GooseFEM::Dynamics::Verlet , "Verlet time integration" , py::arg("geometry"), py::arg("dt"), py::arg("nstep")=1); +mDynamics.def("velocityVerlet", &GooseFEM::Dynamics::velocityVerlet, "Velocity-Verlet time integration", py::arg("geometry"), py::arg("dt"), py::arg("nstep")=1); + +// ------------------------------------------------------------------------------------------------- + +py::class_(mDynamics, "Geometry") + + .def(py::init<>()) + + .def("solve_A" , &GooseFEM::Dynamics::Geometry::solve_A, "Solve for accelerations (dofval)" ) + .def("solve_V" , &GooseFEM::Dynamics::Geometry::solve_V, "Solve for velocities (dofval)" ) + + .def("u" , &GooseFEM::Dynamics::Geometry::u , "Return displacements (nodevec)") + .def("v" , &GooseFEM::Dynamics::Geometry::v , "Return velocities (nodevec)") + .def("a" , &GooseFEM::Dynamics::Geometry::a , "Return accelerations (nodevec)") + + .def("dofs_u" , &GooseFEM::Dynamics::Geometry::dofs_u , "Return displacements (dofval)" ) + .def("dofs_v" , &GooseFEM::Dynamics::Geometry::dofs_v , "Return velocities (dofval)" ) + .def("dofs_a" , &GooseFEM::Dynamics::Geometry::dofs_a , "Return accelerations (dofval)" ) + + .def("set_u" , py::overload_cast &>(&GooseFEM::Dynamics::Geometry::set_u), "Overwrite displacements", py::arg("dofval" )) + .def("set_u" , py::overload_cast &>(&GooseFEM::Dynamics::Geometry::set_u), "Overwrite displacements", py::arg("nodevec")) + .def("set_v" , &GooseFEM::Dynamics::Geometry::set_v , "Overwrite velocities" , py::arg("nodevec")) + .def("set_a" , &GooseFEM::Dynamics::Geometry::set_a , "Overwrite accelerations", py::arg("nodevec")) + + .def("__repr__", [](const GooseFEM::Dynamics::Geometry &){ return ""; }); + +// ======================================= GooseFEM.Element ======================================== + +py::module mElement = m.def_submodule("Element", "Generic element routines"); + +// ------------------------------------------------------------------------------------------------- + +mElement.def("asElementVector" , &GooseFEM::Element::asElementVector , "Covert to 'elemvec'", py::arg("conn"), py::arg("nodevec")); +mElement.def("assembleElementVector", &GooseFEM::Element::assembleNodeVector, "Assemble 'nodevec'" , py::arg("conn"), py::arg("elemvec")); + +// ==================================== GooseFEM.Element.Quad4 ===================================== + +{ + +py::module sm = mElement.def_submodule("Quad4", "Linear quadrilateral elements (2D)"); + +// ------------------------------------------------------------------------------------------------- + +py::class_(sm, "Quadrature") + + .def(py::init &>(), "Quadrature", py::arg("x")) + + .def(py::init &, const xt::xtensor &, const xt::xtensor &>(), "Quadrature", py::arg("x"), py::arg("xi"), py::arg("w")) + + .def("nelem", &GooseFEM::Element::Quad4::Quadrature::nelem, "Return number of elements" ) + .def("nne" , &GooseFEM::Element::Quad4::Quadrature::nne , "Return number of nodes per element" ) + .def("ndim" , &GooseFEM::Element::Quad4::Quadrature::ndim , "Return number of dimensions" ) + .def("nip" , &GooseFEM::Element::Quad4::Quadrature::nip , "Return number of integration points") + + .def("dV" , py::overload_cast<>(&GooseFEM::Element::Quad4::Quadrature::dV , py::const_), "Integration point volume (qscalar)") + .def("dVtensor", py::overload_cast<>(&GooseFEM::Element::Quad4::Quadrature::dVtensor, py::const_), "Integration point volume (qtensor)") + + .def("gradN_vector" , py::overload_cast &>(&GooseFEM::Element::Quad4::Quadrature::gradN_vector , py::const_), "Dyadic product, returns 'qtensor'", py::arg("elemvec")) + .def("gradN_vector_T" , py::overload_cast &>(&GooseFEM::Element::Quad4::Quadrature::gradN_vector_T , py::const_), "Dyadic product, returns 'qtensor'", py::arg("elemvec")) + .def("symGradN_vector", py::overload_cast &>(&GooseFEM::Element::Quad4::Quadrature::symGradN_vector, py::const_), "Dyadic product, returns 'qtensor'", py::arg("elemvec")) + + .def("int_N_scalar_NT_dV" , py::overload_cast &>(&GooseFEM::Element::Quad4::Quadrature::int_N_scalar_NT_dV , py::const_), "Integration, returns 'elemmat'", py::arg("qscalar")) + .def("int_gradN_dot_tensor2_dV", py::overload_cast &>(&GooseFEM::Element::Quad4::Quadrature::int_gradN_dot_tensor2_dV, py::const_), "Integration, returns 'elemvec'", py::arg("qtensor")) + + .def("__repr__", [](const GooseFEM::Element::Quad4::Quadrature &){ return ""; }); + +// ------------------------------------------------------------------------------------------------- + +{ + +py::module ssm = sm.def_submodule("Gauss", "Gauss quadrature"); + +ssm.def("nip", &GooseFEM::Element::Quad4::Gauss::nip, "Return number of integration point" ); +ssm.def("xi" , &GooseFEM::Element::Quad4::Gauss::xi , "Return integration point coordinates"); +ssm.def("w" , &GooseFEM::Element::Quad4::Gauss::w , "Return integration point weights" ); + +} + +// ------------------------------------------------------------------------------------------------- + +{ + +py::module ssm = sm.def_submodule("Nodal", "Nodal quadrature"); + +ssm.def("nip", &GooseFEM::Element::Quad4::Nodal::nip, "Return number of integration point" ); +ssm.def("xi" , &GooseFEM::Element::Quad4::Nodal::xi , "Return integration point coordinates"); +ssm.def("w" , &GooseFEM::Element::Quad4::Nodal::w , "Return integration point weights" ); + +} + +// ------------------------------------------------------------------------------------------------- + +} + +// ===================================== GooseFEM.Element.Hex8 ===================================== + +{ + +py::module sm = mElement.def_submodule("Hex8", "Linear hexahedron (brick) elements (3D)"); + +// ------------------------------------------------------------------------------------------------- + +py::class_(sm, "Quadrature") + + .def(py::init &>(), "Quadrature", py::arg("x")) + + .def(py::init &, const xt::xtensor &, const xt::xtensor &>(), "Quadrature", py::arg("x"), py::arg("xi"), py::arg("w")) + + .def("nelem", &GooseFEM::Element::Hex8::Quadrature::nelem, "Return number of elements" ) + .def("nne" , &GooseFEM::Element::Hex8::Quadrature::nne , "Return number of nodes per element" ) + .def("ndim" , &GooseFEM::Element::Hex8::Quadrature::ndim , "Return number of dimensions" ) + .def("nip" , &GooseFEM::Element::Hex8::Quadrature::nip , "Return number of integration points") + + .def("dV" , py::overload_cast<>(&GooseFEM::Element::Hex8::Quadrature::dV , py::const_), "Integration point volume (qscalar)") + .def("dVtensor", py::overload_cast<>(&GooseFEM::Element::Hex8::Quadrature::dVtensor, py::const_), "Integration point volume (qtensor)") + + .def("gradN_vector" , py::overload_cast &>(&GooseFEM::Element::Hex8::Quadrature::gradN_vector , py::const_), "Dyadic product, returns 'qtensor'", py::arg("elemvec")) + .def("gradN_vector_T" , py::overload_cast &>(&GooseFEM::Element::Hex8::Quadrature::gradN_vector_T , py::const_), "Dyadic product, returns 'qtensor'", py::arg("elemvec")) + .def("symGradN_vector", py::overload_cast &>(&GooseFEM::Element::Hex8::Quadrature::symGradN_vector, py::const_), "Dyadic product, returns 'qtensor'", py::arg("elemvec")) + + .def("int_N_scalar_NT_dV" , py::overload_cast &>(&GooseFEM::Element::Hex8::Quadrature::int_N_scalar_NT_dV , py::const_), "Integration, returns 'elemmat'", py::arg("qscalar")) + .def("int_gradN_dot_tensor2_dV", py::overload_cast &>(&GooseFEM::Element::Hex8::Quadrature::int_gradN_dot_tensor2_dV, py::const_), "Integration, returns 'elemvec'", py::arg("qtensor")) + + .def("__repr__", [](const GooseFEM::Element::Hex8::Quadrature &){ return ""; }); + +// ------------------------------------------------------------------------------------------------- + +{ + +py::module ssm = sm.def_submodule("Gauss", "Gauss quadrature"); + +ssm.def("nip", &GooseFEM::Element::Hex8::Gauss::nip, "Return number of integration point" ); +ssm.def("xi" , &GooseFEM::Element::Hex8::Gauss::xi , "Return integration point coordinates"); +ssm.def("w" , &GooseFEM::Element::Hex8::Gauss::w , "Return integration point weights" ); + +} + +// ------------------------------------------------------------------------------------------------- + +{ + +py::module ssm = sm.def_submodule("Nodal", "Nodal quadrature"); + +ssm.def("nip", &GooseFEM::Element::Hex8::Nodal::nip, "Return number of integration point" ); +ssm.def("xi" , &GooseFEM::Element::Hex8::Nodal::xi , "Return integration point coordinates"); +ssm.def("w" , &GooseFEM::Element::Hex8::Nodal::w , "Return integration point weights" ); + +} + +// ------------------------------------------------------------------------------------------------- + +} + +// ========================================= GooseFEM.Mesh ========================================= + +py::module mMesh = m.def_submodule("Mesh", "Generic mesh routines"); + +// ------------------------------------------------------------------------------------------------- + +mMesh.def("dofs", &GooseFEM::Mesh::dofs, "List with DOF-numbers (in sequential order)", py::arg("nnode"), py::arg("ndim")); + +mMesh.def("renumber", &GooseFEM::Mesh::renumber, "Renumber DOF-list to use the lowest possible index", py::arg("dofs")); + +mMesh.def("renumber_index", &GooseFEM::Mesh::renumber_index, "Index-list to renumber", py::arg("dofs")); + +mMesh.def("reorder", &GooseFEM::Mesh::reorder, "Renumber DOF-list to begin or end with 'idx'", py::arg("dofs"), py::arg("idx"), py::arg("location")="end"); + +mMesh.def("reorder_index", &GooseFEM::Mesh::reorder_index, "Index-list to reorder", py::arg("dofs"), py::arg("idx"), py::arg("location")="end"); + +mMesh.def("coordination", &GooseFEM::Mesh::coordination, "Coordination number of each node", py::arg("conn")); + +mMesh.def("elem2node", &GooseFEM::Mesh::elem2node, "Elements connect to each node", py::arg("conn")); + +// ====================================== GooseFEM.Mesh.Hex8 ======================================= + +{ + +py::module sm = mMesh.def_submodule("Hex8", "Linear hexahedron (brick) elements (3D)"); + +// ------------------------------------------------------------------------------------------------- + +py::class_(sm, "Regular") + + .def(py::init(), "mesh with nx*ny*nz 'pixels' and edge size h", py::arg("nx"), py::arg("ny"), py::arg("nz"), py::arg("h")=1.) + + .def("nelem" , &GooseFEM::Mesh::Hex8::Regular::nelem ) + .def("nnode" , &GooseFEM::Mesh::Hex8::Regular::nnode ) + .def("nne" , &GooseFEM::Mesh::Hex8::Regular::nne ) + .def("ndim" , &GooseFEM::Mesh::Hex8::Regular::ndim ) + + .def("coor" , &GooseFEM::Mesh::Hex8::Regular::coor ) + .def("conn" , &GooseFEM::Mesh::Hex8::Regular::conn ) + + .def("nodesFront" , &GooseFEM::Mesh::Hex8::Regular::nodesFront ) + .def("nodesBack" , &GooseFEM::Mesh::Hex8::Regular::nodesBack ) + .def("nodesLeft" , &GooseFEM::Mesh::Hex8::Regular::nodesLeft ) + .def("nodesRight" , &GooseFEM::Mesh::Hex8::Regular::nodesRight ) + .def("nodesBottom" , &GooseFEM::Mesh::Hex8::Regular::nodesBottom ) + .def("nodesTop" , &GooseFEM::Mesh::Hex8::Regular::nodesTop ) + + .def("nodesFrontFace" , &GooseFEM::Mesh::Hex8::Regular::nodesFrontFace ) + .def("nodesBackFace" , &GooseFEM::Mesh::Hex8::Regular::nodesBackFace ) + .def("nodesLeftFace" , &GooseFEM::Mesh::Hex8::Regular::nodesLeftFace ) + .def("nodesRightFace" , &GooseFEM::Mesh::Hex8::Regular::nodesRightFace ) + .def("nodesBottomFace" , &GooseFEM::Mesh::Hex8::Regular::nodesBottomFace ) + .def("nodesTopFace" , &GooseFEM::Mesh::Hex8::Regular::nodesTopFace ) + + .def("nodesFrontBottomEdge" , &GooseFEM::Mesh::Hex8::Regular::nodesFrontBottomEdge ) + .def("nodesFrontTopEdge" , &GooseFEM::Mesh::Hex8::Regular::nodesFrontTopEdge ) + .def("nodesFrontLeftEdge" , &GooseFEM::Mesh::Hex8::Regular::nodesFrontLeftEdge ) + .def("nodesFrontRightEdge" , &GooseFEM::Mesh::Hex8::Regular::nodesFrontRightEdge ) + .def("nodesBackBottomEdge" , &GooseFEM::Mesh::Hex8::Regular::nodesBackBottomEdge ) + .def("nodesBackTopEdge" , &GooseFEM::Mesh::Hex8::Regular::nodesBackTopEdge ) + .def("nodesBackLeftEdge" , &GooseFEM::Mesh::Hex8::Regular::nodesBackLeftEdge ) + .def("nodesBackRightEdge" , &GooseFEM::Mesh::Hex8::Regular::nodesBackRightEdge ) + .def("nodesBottomLeftEdge" , &GooseFEM::Mesh::Hex8::Regular::nodesBottomLeftEdge ) + .def("nodesBottomRightEdge" , &GooseFEM::Mesh::Hex8::Regular::nodesBottomRightEdge ) + .def("nodesTopLeftEdge" , &GooseFEM::Mesh::Hex8::Regular::nodesTopLeftEdge ) + .def("nodesTopRightEdge" , &GooseFEM::Mesh::Hex8::Regular::nodesTopRightEdge ) + + .def("nodesBottomFrontEdge" , &GooseFEM::Mesh::Hex8::Regular::nodesBottomFrontEdge ) + .def("nodesBottomBackEdge" , &GooseFEM::Mesh::Hex8::Regular::nodesBottomBackEdge ) + .def("nodesTopFrontEdge" , &GooseFEM::Mesh::Hex8::Regular::nodesTopFrontEdge ) + .def("nodesTopBackEdge" , &GooseFEM::Mesh::Hex8::Regular::nodesTopBackEdge ) + .def("nodesLeftBottomEdge" , &GooseFEM::Mesh::Hex8::Regular::nodesLeftBottomEdge ) + .def("nodesLeftFrontEdge" , &GooseFEM::Mesh::Hex8::Regular::nodesLeftFrontEdge ) + .def("nodesLeftBackEdge" , &GooseFEM::Mesh::Hex8::Regular::nodesLeftBackEdge ) + .def("nodesLeftTopEdge" , &GooseFEM::Mesh::Hex8::Regular::nodesLeftTopEdge ) + .def("nodesRightBottomEdge" , &GooseFEM::Mesh::Hex8::Regular::nodesRightBottomEdge ) + .def("nodesRightTopEdge" , &GooseFEM::Mesh::Hex8::Regular::nodesRightTopEdge ) + .def("nodesRightFrontEdge" , &GooseFEM::Mesh::Hex8::Regular::nodesRightFrontEdge ) + .def("nodesRightBackEdge" , &GooseFEM::Mesh::Hex8::Regular::nodesRightBackEdge ) + + .def("nodesFrontBottomOpenEdge" , &GooseFEM::Mesh::Hex8::Regular::nodesFrontBottomOpenEdge ) + .def("nodesFrontTopOpenEdge" , &GooseFEM::Mesh::Hex8::Regular::nodesFrontTopOpenEdge ) + .def("nodesFrontLeftOpenEdge" , &GooseFEM::Mesh::Hex8::Regular::nodesFrontLeftOpenEdge ) + .def("nodesFrontRightOpenEdge" , &GooseFEM::Mesh::Hex8::Regular::nodesFrontRightOpenEdge ) + .def("nodesBackBottomOpenEdge" , &GooseFEM::Mesh::Hex8::Regular::nodesBackBottomOpenEdge ) + .def("nodesBackTopOpenEdge" , &GooseFEM::Mesh::Hex8::Regular::nodesBackTopOpenEdge ) + .def("nodesBackLeftOpenEdge" , &GooseFEM::Mesh::Hex8::Regular::nodesBackLeftOpenEdge ) + .def("nodesBackRightOpenEdge" , &GooseFEM::Mesh::Hex8::Regular::nodesBackRightOpenEdge ) + .def("nodesBottomLeftOpenEdge" , &GooseFEM::Mesh::Hex8::Regular::nodesBottomLeftOpenEdge ) + .def("nodesBottomRightOpenEdge" , &GooseFEM::Mesh::Hex8::Regular::nodesBottomRightOpenEdge ) + .def("nodesTopLeftOpenEdge" , &GooseFEM::Mesh::Hex8::Regular::nodesTopLeftOpenEdge ) + .def("nodesTopRightOpenEdge" , &GooseFEM::Mesh::Hex8::Regular::nodesTopRightOpenEdge ) + + .def("nodesBottomFrontOpenEdge" , &GooseFEM::Mesh::Hex8::Regular::nodesBottomFrontOpenEdge ) + .def("nodesBottomBackOpenEdge" , &GooseFEM::Mesh::Hex8::Regular::nodesBottomBackOpenEdge ) + .def("nodesTopFrontOpenEdge" , &GooseFEM::Mesh::Hex8::Regular::nodesTopFrontOpenEdge ) + .def("nodesTopBackOpenEdge" , &GooseFEM::Mesh::Hex8::Regular::nodesTopBackOpenEdge ) + .def("nodesLeftBottomOpenEdge" , &GooseFEM::Mesh::Hex8::Regular::nodesLeftBottomOpenEdge ) + .def("nodesLeftFrontOpenEdge" , &GooseFEM::Mesh::Hex8::Regular::nodesLeftFrontOpenEdge ) + .def("nodesLeftBackOpenEdge" , &GooseFEM::Mesh::Hex8::Regular::nodesLeftBackOpenEdge ) + .def("nodesLeftTopOpenEdge" , &GooseFEM::Mesh::Hex8::Regular::nodesLeftTopOpenEdge ) + .def("nodesRightBottomOpenEdge" , &GooseFEM::Mesh::Hex8::Regular::nodesRightBottomOpenEdge ) + .def("nodesRightTopOpenEdge" , &GooseFEM::Mesh::Hex8::Regular::nodesRightTopOpenEdge ) + .def("nodesRightFrontOpenEdge" , &GooseFEM::Mesh::Hex8::Regular::nodesRightFrontOpenEdge ) + .def("nodesRightBackOpenEdge" , &GooseFEM::Mesh::Hex8::Regular::nodesRightBackOpenEdge ) + + .def("nodesFrontBottomLeftCorner" , &GooseFEM::Mesh::Hex8::Regular::nodesFrontBottomLeftCorner ) + .def("nodesFrontBottomRightCorner", &GooseFEM::Mesh::Hex8::Regular::nodesFrontBottomRightCorner) + .def("nodesFrontTopLeftCorner" , &GooseFEM::Mesh::Hex8::Regular::nodesFrontTopLeftCorner ) + .def("nodesFrontTopRightCorner" , &GooseFEM::Mesh::Hex8::Regular::nodesFrontTopRightCorner ) + .def("nodesBackBottomLeftCorner" , &GooseFEM::Mesh::Hex8::Regular::nodesBackBottomLeftCorner ) + .def("nodesBackBottomRightCorner" , &GooseFEM::Mesh::Hex8::Regular::nodesBackBottomRightCorner ) + .def("nodesBackTopLeftCorner" , &GooseFEM::Mesh::Hex8::Regular::nodesBackTopLeftCorner ) + .def("nodesBackTopRightCorner" , &GooseFEM::Mesh::Hex8::Regular::nodesBackTopRightCorner ) + + .def("nodesFrontLeftBottomCorner" , &GooseFEM::Mesh::Hex8::Regular::nodesFrontLeftBottomCorner ) + .def("nodesBottomFrontLeftCorner" , &GooseFEM::Mesh::Hex8::Regular::nodesBottomFrontLeftCorner ) + .def("nodesBottomLeftFrontCorner" , &GooseFEM::Mesh::Hex8::Regular::nodesBottomLeftFrontCorner ) + .def("nodesLeftFrontBottomCorner" , &GooseFEM::Mesh::Hex8::Regular::nodesLeftFrontBottomCorner ) + .def("nodesLeftBottomFrontCorner" , &GooseFEM::Mesh::Hex8::Regular::nodesLeftBottomFrontCorner ) + .def("nodesFrontRightBottomCorner", &GooseFEM::Mesh::Hex8::Regular::nodesFrontRightBottomCorner) + .def("nodesBottomFrontRightCorner", &GooseFEM::Mesh::Hex8::Regular::nodesBottomFrontRightCorner) + .def("nodesBottomRightFrontCorner", &GooseFEM::Mesh::Hex8::Regular::nodesBottomRightFrontCorner) + .def("nodesRightFrontBottomCorner", &GooseFEM::Mesh::Hex8::Regular::nodesRightFrontBottomCorner) + .def("nodesRightBottomFrontCorner", &GooseFEM::Mesh::Hex8::Regular::nodesRightBottomFrontCorner) + .def("nodesFrontLeftTopCorner" , &GooseFEM::Mesh::Hex8::Regular::nodesFrontLeftTopCorner ) + .def("nodesTopFrontLeftCorner" , &GooseFEM::Mesh::Hex8::Regular::nodesTopFrontLeftCorner ) + .def("nodesTopLeftFrontCorner" , &GooseFEM::Mesh::Hex8::Regular::nodesTopLeftFrontCorner ) + .def("nodesLeftFrontTopCorner" , &GooseFEM::Mesh::Hex8::Regular::nodesLeftFrontTopCorner ) + .def("nodesLeftTopFrontCorner" , &GooseFEM::Mesh::Hex8::Regular::nodesLeftTopFrontCorner ) + .def("nodesFrontRightTopCorner" , &GooseFEM::Mesh::Hex8::Regular::nodesFrontRightTopCorner ) + .def("nodesTopFrontRightCorner" , &GooseFEM::Mesh::Hex8::Regular::nodesTopFrontRightCorner ) + .def("nodesTopRightFrontCorner" , &GooseFEM::Mesh::Hex8::Regular::nodesTopRightFrontCorner ) + .def("nodesRightFrontTopCorner" , &GooseFEM::Mesh::Hex8::Regular::nodesRightFrontTopCorner ) + .def("nodesRightTopFrontCorner" , &GooseFEM::Mesh::Hex8::Regular::nodesRightTopFrontCorner ) + .def("nodesBackLeftBottomCorner" , &GooseFEM::Mesh::Hex8::Regular::nodesBackLeftBottomCorner ) + .def("nodesBottomBackLeftCorner" , &GooseFEM::Mesh::Hex8::Regular::nodesBottomBackLeftCorner ) + .def("nodesBottomLeftBackCorner" , &GooseFEM::Mesh::Hex8::Regular::nodesBottomLeftBackCorner ) + .def("nodesLeftBackBottomCorner" , &GooseFEM::Mesh::Hex8::Regular::nodesLeftBackBottomCorner ) + .def("nodesLeftBottomBackCorner" , &GooseFEM::Mesh::Hex8::Regular::nodesLeftBottomBackCorner ) + .def("nodesBackRightBottomCorner" , &GooseFEM::Mesh::Hex8::Regular::nodesBackRightBottomCorner ) + .def("nodesBottomBackRightCorner" , &GooseFEM::Mesh::Hex8::Regular::nodesBottomBackRightCorner ) + .def("nodesBottomRightBackCorner" , &GooseFEM::Mesh::Hex8::Regular::nodesBottomRightBackCorner ) + .def("nodesRightBackBottomCorner" , &GooseFEM::Mesh::Hex8::Regular::nodesRightBackBottomCorner ) + .def("nodesRightBottomBackCorner" , &GooseFEM::Mesh::Hex8::Regular::nodesRightBottomBackCorner ) + .def("nodesBackLeftTopCorner" , &GooseFEM::Mesh::Hex8::Regular::nodesBackLeftTopCorner ) + .def("nodesTopBackLeftCorner" , &GooseFEM::Mesh::Hex8::Regular::nodesTopBackLeftCorner ) + .def("nodesTopLeftBackCorner" , &GooseFEM::Mesh::Hex8::Regular::nodesTopLeftBackCorner ) + .def("nodesLeftBackTopCorner" , &GooseFEM::Mesh::Hex8::Regular::nodesLeftBackTopCorner ) + .def("nodesLeftTopBackCorner" , &GooseFEM::Mesh::Hex8::Regular::nodesLeftTopBackCorner ) + .def("nodesBackRightTopCorner" , &GooseFEM::Mesh::Hex8::Regular::nodesBackRightTopCorner ) + .def("nodesTopBackRightCorner" , &GooseFEM::Mesh::Hex8::Regular::nodesTopBackRightCorner ) + .def("nodesTopRightBackCorner" , &GooseFEM::Mesh::Hex8::Regular::nodesTopRightBackCorner ) + .def("nodesRightBackTopCorner" , &GooseFEM::Mesh::Hex8::Regular::nodesRightBackTopCorner ) + .def("nodesRightTopBackCorner" , &GooseFEM::Mesh::Hex8::Regular::nodesRightTopBackCorner ) + + .def("nodesPeriodic" , &GooseFEM::Mesh::Hex8::Regular::nodesPeriodic ) + .def("nodesOrigin" , &GooseFEM::Mesh::Hex8::Regular::nodesOrigin ) + .def("dofs" , &GooseFEM::Mesh::Hex8::Regular::dofs ) + .def("dofsPeriodic" , &GooseFEM::Mesh::Hex8::Regular::dofsPeriodic ) + + .def("__repr__", [](const GooseFEM::Mesh::Hex8::Regular &){ return ""; }); + +// ------------------------------------------------------------------------------------------------- + +py::class_(sm, "FineLayer") + + .def(py::init(), "mesh with nx*ny*nz 'pixels' and edge size h", py::arg("nx"), py::arg("ny"), py::arg("nz"), py::arg("h")=1., py::arg("nfine")=1) + + .def("nelem" , &GooseFEM::Mesh::Hex8::FineLayer::nelem ) + .def("nnode" , &GooseFEM::Mesh::Hex8::FineLayer::nnode ) + .def("nne" , &GooseFEM::Mesh::Hex8::FineLayer::nne ) + .def("ndim" , &GooseFEM::Mesh::Hex8::FineLayer::ndim ) + .def("shape" , &GooseFEM::Mesh::Hex8::FineLayer::shape ) + + .def("coor" , &GooseFEM::Mesh::Hex8::FineLayer::coor ) + .def("conn" , &GooseFEM::Mesh::Hex8::FineLayer::conn ) + + .def("elementsMiddleLayer" , &GooseFEM::Mesh::Hex8::FineLayer::elementsMiddleLayer ) + + .def("nodesFront" , &GooseFEM::Mesh::Hex8::FineLayer::nodesFront ) + .def("nodesBack" , &GooseFEM::Mesh::Hex8::FineLayer::nodesBack ) + .def("nodesLeft" , &GooseFEM::Mesh::Hex8::FineLayer::nodesLeft ) + .def("nodesRight" , &GooseFEM::Mesh::Hex8::FineLayer::nodesRight ) + .def("nodesBottom" , &GooseFEM::Mesh::Hex8::FineLayer::nodesBottom ) + .def("nodesTop" , &GooseFEM::Mesh::Hex8::FineLayer::nodesTop ) + + .def("nodesFrontFace" , &GooseFEM::Mesh::Hex8::FineLayer::nodesFrontFace ) + .def("nodesBackFace" , &GooseFEM::Mesh::Hex8::FineLayer::nodesBackFace ) + .def("nodesLeftFace" , &GooseFEM::Mesh::Hex8::FineLayer::nodesLeftFace ) + .def("nodesRightFace" , &GooseFEM::Mesh::Hex8::FineLayer::nodesRightFace ) + .def("nodesBottomFace" , &GooseFEM::Mesh::Hex8::FineLayer::nodesBottomFace ) + .def("nodesTopFace" , &GooseFEM::Mesh::Hex8::FineLayer::nodesTopFace ) + + .def("nodesFrontBottomEdge" , &GooseFEM::Mesh::Hex8::FineLayer::nodesFrontBottomEdge ) + .def("nodesFrontTopEdge" , &GooseFEM::Mesh::Hex8::FineLayer::nodesFrontTopEdge ) + .def("nodesFrontLeftEdge" , &GooseFEM::Mesh::Hex8::FineLayer::nodesFrontLeftEdge ) + .def("nodesFrontRightEdge" , &GooseFEM::Mesh::Hex8::FineLayer::nodesFrontRightEdge ) + .def("nodesBackBottomEdge" , &GooseFEM::Mesh::Hex8::FineLayer::nodesBackBottomEdge ) + .def("nodesBackTopEdge" , &GooseFEM::Mesh::Hex8::FineLayer::nodesBackTopEdge ) + .def("nodesBackLeftEdge" , &GooseFEM::Mesh::Hex8::FineLayer::nodesBackLeftEdge ) + .def("nodesBackRightEdge" , &GooseFEM::Mesh::Hex8::FineLayer::nodesBackRightEdge ) + .def("nodesBottomLeftEdge" , &GooseFEM::Mesh::Hex8::FineLayer::nodesBottomLeftEdge ) + .def("nodesBottomRightEdge" , &GooseFEM::Mesh::Hex8::FineLayer::nodesBottomRightEdge ) + .def("nodesTopLeftEdge" , &GooseFEM::Mesh::Hex8::FineLayer::nodesTopLeftEdge ) + .def("nodesTopRightEdge" , &GooseFEM::Mesh::Hex8::FineLayer::nodesTopRightEdge ) + + .def("nodesBottomFrontEdge" , &GooseFEM::Mesh::Hex8::FineLayer::nodesBottomFrontEdge ) + .def("nodesBottomBackEdge" , &GooseFEM::Mesh::Hex8::FineLayer::nodesBottomBackEdge ) + .def("nodesTopFrontEdge" , &GooseFEM::Mesh::Hex8::FineLayer::nodesTopFrontEdge ) + .def("nodesTopBackEdge" , &GooseFEM::Mesh::Hex8::FineLayer::nodesTopBackEdge ) + .def("nodesLeftBottomEdge" , &GooseFEM::Mesh::Hex8::FineLayer::nodesLeftBottomEdge ) + .def("nodesLeftFrontEdge" , &GooseFEM::Mesh::Hex8::FineLayer::nodesLeftFrontEdge ) + .def("nodesLeftBackEdge" , &GooseFEM::Mesh::Hex8::FineLayer::nodesLeftBackEdge ) + .def("nodesLeftTopEdge" , &GooseFEM::Mesh::Hex8::FineLayer::nodesLeftTopEdge ) + .def("nodesRightBottomEdge" , &GooseFEM::Mesh::Hex8::FineLayer::nodesRightBottomEdge ) + .def("nodesRightTopEdge" , &GooseFEM::Mesh::Hex8::FineLayer::nodesRightTopEdge ) + .def("nodesRightFrontEdge" , &GooseFEM::Mesh::Hex8::FineLayer::nodesRightFrontEdge ) + .def("nodesRightBackEdge" , &GooseFEM::Mesh::Hex8::FineLayer::nodesRightBackEdge ) + + .def("nodesFrontBottomOpenEdge" , &GooseFEM::Mesh::Hex8::FineLayer::nodesFrontBottomOpenEdge ) + .def("nodesFrontTopOpenEdge" , &GooseFEM::Mesh::Hex8::FineLayer::nodesFrontTopOpenEdge ) + .def("nodesFrontLeftOpenEdge" , &GooseFEM::Mesh::Hex8::FineLayer::nodesFrontLeftOpenEdge ) + .def("nodesFrontRightOpenEdge" , &GooseFEM::Mesh::Hex8::FineLayer::nodesFrontRightOpenEdge ) + .def("nodesBackBottomOpenEdge" , &GooseFEM::Mesh::Hex8::FineLayer::nodesBackBottomOpenEdge ) + .def("nodesBackTopOpenEdge" , &GooseFEM::Mesh::Hex8::FineLayer::nodesBackTopOpenEdge ) + .def("nodesBackLeftOpenEdge" , &GooseFEM::Mesh::Hex8::FineLayer::nodesBackLeftOpenEdge ) + .def("nodesBackRightOpenEdge" , &GooseFEM::Mesh::Hex8::FineLayer::nodesBackRightOpenEdge ) + .def("nodesBottomLeftOpenEdge" , &GooseFEM::Mesh::Hex8::FineLayer::nodesBottomLeftOpenEdge ) + .def("nodesBottomRightOpenEdge" , &GooseFEM::Mesh::Hex8::FineLayer::nodesBottomRightOpenEdge ) + .def("nodesTopLeftOpenEdge" , &GooseFEM::Mesh::Hex8::FineLayer::nodesTopLeftOpenEdge ) + .def("nodesTopRightOpenEdge" , &GooseFEM::Mesh::Hex8::FineLayer::nodesTopRightOpenEdge ) + + .def("nodesBottomFrontOpenEdge" , &GooseFEM::Mesh::Hex8::FineLayer::nodesBottomFrontOpenEdge ) + .def("nodesBottomBackOpenEdge" , &GooseFEM::Mesh::Hex8::FineLayer::nodesBottomBackOpenEdge ) + .def("nodesTopFrontOpenEdge" , &GooseFEM::Mesh::Hex8::FineLayer::nodesTopFrontOpenEdge ) + .def("nodesTopBackOpenEdge" , &GooseFEM::Mesh::Hex8::FineLayer::nodesTopBackOpenEdge ) + .def("nodesLeftBottomOpenEdge" , &GooseFEM::Mesh::Hex8::FineLayer::nodesLeftBottomOpenEdge ) + .def("nodesLeftFrontOpenEdge" , &GooseFEM::Mesh::Hex8::FineLayer::nodesLeftFrontOpenEdge ) + .def("nodesLeftBackOpenEdge" , &GooseFEM::Mesh::Hex8::FineLayer::nodesLeftBackOpenEdge ) + .def("nodesLeftTopOpenEdge" , &GooseFEM::Mesh::Hex8::FineLayer::nodesLeftTopOpenEdge ) + .def("nodesRightBottomOpenEdge" , &GooseFEM::Mesh::Hex8::FineLayer::nodesRightBottomOpenEdge ) + .def("nodesRightTopOpenEdge" , &GooseFEM::Mesh::Hex8::FineLayer::nodesRightTopOpenEdge ) + .def("nodesRightFrontOpenEdge" , &GooseFEM::Mesh::Hex8::FineLayer::nodesRightFrontOpenEdge ) + .def("nodesRightBackOpenEdge" , &GooseFEM::Mesh::Hex8::FineLayer::nodesRightBackOpenEdge ) + + .def("nodesFrontBottomLeftCorner" , &GooseFEM::Mesh::Hex8::FineLayer::nodesFrontBottomLeftCorner ) + .def("nodesFrontBottomRightCorner", &GooseFEM::Mesh::Hex8::FineLayer::nodesFrontBottomRightCorner) + .def("nodesFrontTopLeftCorner" , &GooseFEM::Mesh::Hex8::FineLayer::nodesFrontTopLeftCorner ) + .def("nodesFrontTopRightCorner" , &GooseFEM::Mesh::Hex8::FineLayer::nodesFrontTopRightCorner ) + .def("nodesBackBottomLeftCorner" , &GooseFEM::Mesh::Hex8::FineLayer::nodesBackBottomLeftCorner ) + .def("nodesBackBottomRightCorner" , &GooseFEM::Mesh::Hex8::FineLayer::nodesBackBottomRightCorner ) + .def("nodesBackTopLeftCorner" , &GooseFEM::Mesh::Hex8::FineLayer::nodesBackTopLeftCorner ) + .def("nodesBackTopRightCorner" , &GooseFEM::Mesh::Hex8::FineLayer::nodesBackTopRightCorner ) + + .def("nodesFrontLeftBottomCorner" , &GooseFEM::Mesh::Hex8::FineLayer::nodesFrontLeftBottomCorner ) + .def("nodesBottomFrontLeftCorner" , &GooseFEM::Mesh::Hex8::FineLayer::nodesBottomFrontLeftCorner ) + .def("nodesBottomLeftFrontCorner" , &GooseFEM::Mesh::Hex8::FineLayer::nodesBottomLeftFrontCorner ) + .def("nodesLeftFrontBottomCorner" , &GooseFEM::Mesh::Hex8::FineLayer::nodesLeftFrontBottomCorner ) + .def("nodesLeftBottomFrontCorner" , &GooseFEM::Mesh::Hex8::FineLayer::nodesLeftBottomFrontCorner ) + .def("nodesFrontRightBottomCorner", &GooseFEM::Mesh::Hex8::FineLayer::nodesFrontRightBottomCorner) + .def("nodesBottomFrontRightCorner", &GooseFEM::Mesh::Hex8::FineLayer::nodesBottomFrontRightCorner) + .def("nodesBottomRightFrontCorner", &GooseFEM::Mesh::Hex8::FineLayer::nodesBottomRightFrontCorner) + .def("nodesRightFrontBottomCorner", &GooseFEM::Mesh::Hex8::FineLayer::nodesRightFrontBottomCorner) + .def("nodesRightBottomFrontCorner", &GooseFEM::Mesh::Hex8::FineLayer::nodesRightBottomFrontCorner) + .def("nodesFrontLeftTopCorner" , &GooseFEM::Mesh::Hex8::FineLayer::nodesFrontLeftTopCorner ) + .def("nodesTopFrontLeftCorner" , &GooseFEM::Mesh::Hex8::FineLayer::nodesTopFrontLeftCorner ) + .def("nodesTopLeftFrontCorner" , &GooseFEM::Mesh::Hex8::FineLayer::nodesTopLeftFrontCorner ) + .def("nodesLeftFrontTopCorner" , &GooseFEM::Mesh::Hex8::FineLayer::nodesLeftFrontTopCorner ) + .def("nodesLeftTopFrontCorner" , &GooseFEM::Mesh::Hex8::FineLayer::nodesLeftTopFrontCorner ) + .def("nodesFrontRightTopCorner" , &GooseFEM::Mesh::Hex8::FineLayer::nodesFrontRightTopCorner ) + .def("nodesTopFrontRightCorner" , &GooseFEM::Mesh::Hex8::FineLayer::nodesTopFrontRightCorner ) + .def("nodesTopRightFrontCorner" , &GooseFEM::Mesh::Hex8::FineLayer::nodesTopRightFrontCorner ) + .def("nodesRightFrontTopCorner" , &GooseFEM::Mesh::Hex8::FineLayer::nodesRightFrontTopCorner ) + .def("nodesRightTopFrontCorner" , &GooseFEM::Mesh::Hex8::FineLayer::nodesRightTopFrontCorner ) + .def("nodesBackLeftBottomCorner" , &GooseFEM::Mesh::Hex8::FineLayer::nodesBackLeftBottomCorner ) + .def("nodesBottomBackLeftCorner" , &GooseFEM::Mesh::Hex8::FineLayer::nodesBottomBackLeftCorner ) + .def("nodesBottomLeftBackCorner" , &GooseFEM::Mesh::Hex8::FineLayer::nodesBottomLeftBackCorner ) + .def("nodesLeftBackBottomCorner" , &GooseFEM::Mesh::Hex8::FineLayer::nodesLeftBackBottomCorner ) + .def("nodesLeftBottomBackCorner" , &GooseFEM::Mesh::Hex8::FineLayer::nodesLeftBottomBackCorner ) + .def("nodesBackRightBottomCorner" , &GooseFEM::Mesh::Hex8::FineLayer::nodesBackRightBottomCorner ) + .def("nodesBottomBackRightCorner" , &GooseFEM::Mesh::Hex8::FineLayer::nodesBottomBackRightCorner ) + .def("nodesBottomRightBackCorner" , &GooseFEM::Mesh::Hex8::FineLayer::nodesBottomRightBackCorner ) + .def("nodesRightBackBottomCorner" , &GooseFEM::Mesh::Hex8::FineLayer::nodesRightBackBottomCorner ) + .def("nodesRightBottomBackCorner" , &GooseFEM::Mesh::Hex8::FineLayer::nodesRightBottomBackCorner ) + .def("nodesBackLeftTopCorner" , &GooseFEM::Mesh::Hex8::FineLayer::nodesBackLeftTopCorner ) + .def("nodesTopBackLeftCorner" , &GooseFEM::Mesh::Hex8::FineLayer::nodesTopBackLeftCorner ) + .def("nodesTopLeftBackCorner" , &GooseFEM::Mesh::Hex8::FineLayer::nodesTopLeftBackCorner ) + .def("nodesLeftBackTopCorner" , &GooseFEM::Mesh::Hex8::FineLayer::nodesLeftBackTopCorner ) + .def("nodesLeftTopBackCorner" , &GooseFEM::Mesh::Hex8::FineLayer::nodesLeftTopBackCorner ) + .def("nodesBackRightTopCorner" , &GooseFEM::Mesh::Hex8::FineLayer::nodesBackRightTopCorner ) + .def("nodesTopBackRightCorner" , &GooseFEM::Mesh::Hex8::FineLayer::nodesTopBackRightCorner ) + .def("nodesTopRightBackCorner" , &GooseFEM::Mesh::Hex8::FineLayer::nodesTopRightBackCorner ) + .def("nodesRightBackTopCorner" , &GooseFEM::Mesh::Hex8::FineLayer::nodesRightBackTopCorner ) + .def("nodesRightTopBackCorner" , &GooseFEM::Mesh::Hex8::FineLayer::nodesRightTopBackCorner ) + + .def("nodesPeriodic" , &GooseFEM::Mesh::Hex8::FineLayer::nodesPeriodic ) + .def("nodesOrigin" , &GooseFEM::Mesh::Hex8::FineLayer::nodesOrigin ) + + .def("dofs" , &GooseFEM::Mesh::Hex8::FineLayer::dofs ) + .def("dofsPeriodic" , &GooseFEM::Mesh::Hex8::FineLayer::dofsPeriodic ) + + .def("__repr__", [](const GooseFEM::Mesh::Hex8::FineLayer &){ return ""; }); + +// ------------------------------------------------------------------------------------------------- + +} + +// ====================================== GooseFEM.Mesh.Quad4 ====================================== + +{ + +py::module sm = mMesh.def_submodule("Quad4", "Linear quadrilateral elements (2D)"); + +// ------------------------------------------------------------------------------------------------- + +py::class_(sm, "Regular") + + .def(py::init(), "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("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("nodesPeriodic" , &GooseFEM::Mesh::Quad4::Regular::nodesPeriodic ) + .def("nodesOrigin" , &GooseFEM::Mesh::Quad4::Regular::nodesOrigin ) + + .def("dofs" , &GooseFEM::Mesh::Quad4::Regular::dofs ) + .def("dofsPeriodic" , &GooseFEM::Mesh::Quad4::Regular::dofsPeriodic ) + + .def("__repr__", [](const GooseFEM::Mesh::Quad4::Regular &){ return ""; }); + +// ------------------------------------------------------------------------------------------------- + +py::class_(sm, "FineLayer") + + .def( + py::init(), + "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("shape" , &GooseFEM::Mesh::Quad4::FineLayer::shape ) + .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("elementsMiddleLayer" , &GooseFEM::Mesh::Quad4::FineLayer::elementsMiddleLayer ) + .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("nodesPeriodic" , &GooseFEM::Mesh::Quad4::FineLayer::nodesPeriodic ) + .def("nodesOrigin" , &GooseFEM::Mesh::Quad4::FineLayer::nodesOrigin ) + .def("dofs" , &GooseFEM::Mesh::Quad4::FineLayer::dofs ) + .def("dofsPeriodic" , &GooseFEM::Mesh::Quad4::FineLayer::dofsPeriodic ) + + .def("__repr__", + [](const GooseFEM::Mesh::Quad4::FineLayer &){ return ""; } + ); + +// ------------------------------------------------------------------------------------------------- + +} + +// ====================================== GooseFEM.Mesh.Tri3 ======================================= + +{ + +py::module sm = mMesh.def_submodule("Tri3" , "Linear triangular elements (2D)"); + +// ------------------------------------------------------------------------------------------------- + +py::class_(sm, "Regular") + + .def( + py::init(), + "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::Tri3::Regular::coor ) + .def("conn" , &GooseFEM::Mesh::Tri3::Regular::conn ) + .def("nelem" , &GooseFEM::Mesh::Tri3::Regular::nelem ) + .def("nnode" , &GooseFEM::Mesh::Tri3::Regular::nnode ) + .def("nne" , &GooseFEM::Mesh::Tri3::Regular::nne ) + .def("ndim" , &GooseFEM::Mesh::Tri3::Regular::ndim ) + + .def("nodesBottomEdge" , &GooseFEM::Mesh::Tri3::Regular::nodesBottomEdge ) + .def("nodesTopEdge" , &GooseFEM::Mesh::Tri3::Regular::nodesTopEdge ) + .def("nodesLeftEdge" , &GooseFEM::Mesh::Tri3::Regular::nodesLeftEdge ) + .def("nodesRightEdge" , &GooseFEM::Mesh::Tri3::Regular::nodesRightEdge ) + .def("nodesBottomOpenEdge" , &GooseFEM::Mesh::Tri3::Regular::nodesBottomOpenEdge ) + .def("nodesTopOpenEdge" , &GooseFEM::Mesh::Tri3::Regular::nodesTopOpenEdge ) + .def("nodesLeftOpenEdge" , &GooseFEM::Mesh::Tri3::Regular::nodesLeftOpenEdge ) + .def("nodesRightOpenEdge" , &GooseFEM::Mesh::Tri3::Regular::nodesRightOpenEdge ) + + .def("nodesBottomLeftCorner" , &GooseFEM::Mesh::Tri3::Regular::nodesBottomLeftCorner ) + .def("nodesBottomRightCorner", &GooseFEM::Mesh::Tri3::Regular::nodesBottomRightCorner) + .def("nodesTopLeftCorner" , &GooseFEM::Mesh::Tri3::Regular::nodesTopLeftCorner ) + .def("nodesTopRightCorner" , &GooseFEM::Mesh::Tri3::Regular::nodesTopRightCorner ) + .def("nodesLeftBottomCorner" , &GooseFEM::Mesh::Tri3::Regular::nodesLeftBottomCorner ) + .def("nodesLeftTopCorner" , &GooseFEM::Mesh::Tri3::Regular::nodesLeftTopCorner ) + .def("nodesRightBottomCorner", &GooseFEM::Mesh::Tri3::Regular::nodesRightBottomCorner) + .def("nodesRightTopCorner" , &GooseFEM::Mesh::Tri3::Regular::nodesRightTopCorner ) + + .def("nodesPeriodic" , &GooseFEM::Mesh::Tri3::Regular::nodesPeriodic ) + .def("nodesOrigin" , &GooseFEM::Mesh::Tri3::Regular::nodesOrigin ) + + .def("dofs" , &GooseFEM::Mesh::Tri3::Regular::dofs ) + .def("dofsPeriodic" , &GooseFEM::Mesh::Tri3::Regular::dofsPeriodic ) + + .def("__repr__", [](const GooseFEM::Mesh::Tri3::Regular &){ return ""; }); + +// ------------------------------------------------------------------------------------------------- + +sm.def("getOrientation", &GooseFEM::Mesh::Tri3::getOrientation, "Get the orientation of each element", py::arg("coor"), py::arg("conn")); + +sm.def("retriangulate", &GooseFEM::Mesh::Tri3::retriangulate, "Re-triangulate existing mesh", py::arg("coor"), py::arg("conn"), py::arg("orientation")=-1); + +// ------------------------------------------------------------------------------------------------- + +} + +// ================================================================================================= + +} + diff --git a/include/xGooseFEM/python.cpp b/include/xGooseFEM/python.cpp deleted file mode 100644 index 20fb0c5..0000000 --- a/include/xGooseFEM/python.cpp +++ /dev/null @@ -1,761 +0,0 @@ -/* ================================================================================================= - -(c - GPLv3) T.W.J. de Geus (Tom) | tom@geus.me | www.geus.me | github.com/tdegeus/GooseFEM - -================================================================================================= */ - -#include -#include - -#include -#include - -#include - -#include - -#include "GooseFEM.h" - -// ================================================================================================= - -namespace py = pybind11; -namespace M = xGooseFEM; - -// ======================================= trampoline class ======================================== - -class PyGeometry : public xGooseFEM::Dynamics::Geometry -{ -public: - using xGooseFEM::Dynamics::Geometry::Geometry; - using Arr1 = xt::xtensor; - using Arr2 = xt::xtensor; - using Arr3 = xt::xtensor; - - xt::xtensor solve_A() override { PYBIND11_OVERLOAD_PURE( Arr1, xGooseFEM::Dynamics::Geometry, solve_A ); } - xt::xtensor solve_V() override { PYBIND11_OVERLOAD_PURE( Arr1, xGooseFEM::Dynamics::Geometry, solve_V ); } - xt::xtensor u() const override { PYBIND11_OVERLOAD_PURE( Arr2, xGooseFEM::Dynamics::Geometry, u ); } - xt::xtensor v() const override { PYBIND11_OVERLOAD_PURE( Arr2, xGooseFEM::Dynamics::Geometry, v ); } - xt::xtensor a() const override { PYBIND11_OVERLOAD_PURE( Arr2, xGooseFEM::Dynamics::Geometry, a ); } - xt::xtensor dofs_u() const override { PYBIND11_OVERLOAD_PURE( Arr1, xGooseFEM::Dynamics::Geometry, dofs_u ); } - xt::xtensor dofs_v() const override { PYBIND11_OVERLOAD_PURE( Arr1, xGooseFEM::Dynamics::Geometry, dofs_v ); } - xt::xtensor dofs_a() const override { PYBIND11_OVERLOAD_PURE( Arr1, xGooseFEM::Dynamics::Geometry, dofs_a ); } - - void set_u(const xt::xtensor &nodevec) override { PYBIND11_OVERLOAD_PURE( void, xGooseFEM::Dynamics::Geometry, set_u , nodevec); } - void set_u(const xt::xtensor &dofval ) override { PYBIND11_OVERLOAD_PURE( void, xGooseFEM::Dynamics::Geometry, set_u , dofval ); } - void set_v(const xt::xtensor &dofval ) override { PYBIND11_OVERLOAD_PURE( void, xGooseFEM::Dynamics::Geometry, set_v , dofval ); } - void set_a(const xt::xtensor &dofval ) override { PYBIND11_OVERLOAD_PURE( void, xGooseFEM::Dynamics::Geometry, set_a , dofval ); } -}; - -// =========================================== GooseFEM ============================================ - -PYBIND11_MODULE(xGooseFEM, m) { - -m.doc() = "Some simple finite element meshes and operations"; - -// ======================================== GooseFEM.Vector ======================================== - -py::class_(m, "Vector") - - .def(py::init &, const xt::xtensor & >(), "Switch between dofval/nodevec/elemvec", py::arg("conn"), py::arg("dofs")) - .def(py::init &, const xt::xtensor &, const xt::xtensor &>(), "Switch between dofval/nodevec/elemvec", py::arg("conn"), py::arg("dofs"), py::arg("iip")) - - .def("nelem", &M::Vector::nelem, "Return number of element") - .def("nne" , &M::Vector::nne , "Return number of nodes per element") - .def("nnode", &M::Vector::nnode, "Return number of nodes") - .def("ndim" , &M::Vector::ndim , "Return number of dimensions") - .def("ndof" , &M::Vector::ndof , "Return number of degrees-of-freedom") - .def("nnu" , &M::Vector::nnu , "Return number of unknown degrees-of-freedom") - .def("nnp" , &M::Vector::nnp , "Return number of prescribed degrees-of-freedom") - - .def("dofs" , &M::Vector::dofs , "Return degrees-of-freedom") - .def("iiu" , &M::Vector::iiu , "Return unknown degrees-of-freedom") - .def("iip" , &M::Vector::iip , "Return prescribed degrees-of-freedom") - - .def("asDofs" , py::overload_cast&,const xt::xtensor&>(&M::Vector::asDofs , py::const_), "Set 'dofval" , py::arg("dofval_u"), py::arg("dofval_p")) - .def("asDofs" , py::overload_cast& >(&M::Vector::asDofs , py::const_), "Set 'dofval" , py::arg("nodevec")) - .def("asDofs" , py::overload_cast& >(&M::Vector::asDofs , py::const_), "Set 'dofval" , py::arg("elemvec")) - .def("asDofs_u" , py::overload_cast& >(&M::Vector::asDofs_u , py::const_), "Set 'dofval" , py::arg("nodevec")) - .def("asDofs_u" , py::overload_cast& >(&M::Vector::asDofs_u , py::const_), "Set 'dofval" , py::arg("elemvec")) - .def("asDofs_p" , py::overload_cast& >(&M::Vector::asDofs_p , py::const_), "Set 'dofval" , py::arg("nodevec")) - .def("asDofs_p" , py::overload_cast& >(&M::Vector::asDofs_p , py::const_), "Set 'dofval" , py::arg("elemvec")) - - .def("asNode" , py::overload_cast&,const xt::xtensor&>(&M::Vector::asNode , py::const_), "Set 'nodevec", py::arg("dofval_u"), py::arg("dofval_p")) - .def("asNode" , py::overload_cast& >(&M::Vector::asNode , py::const_), "Set 'nodevec", py::arg("dofval")) - .def("asNode" , py::overload_cast& >(&M::Vector::asNode , py::const_), "Set 'nodevec", py::arg("elemvec")) - - .def("asElement", py::overload_cast&,const xt::xtensor&>(&M::Vector::asElement, py::const_), "Set 'elemvec", py::arg("dofval_u"), py::arg("dofval_p")) - .def("asElement", py::overload_cast& >(&M::Vector::asElement, py::const_), "Set 'elemvec", py::arg("dofval")) - .def("asElement", py::overload_cast& >(&M::Vector::asElement, py::const_), "Set 'elemvec", py::arg("nodevec")) - - .def("assembleDofs" , py::overload_cast&>(&M::Vector::assembleDofs , py::const_), "Assemble 'dofval'" , py::arg("nodevec")) - .def("assembleDofs" , py::overload_cast&>(&M::Vector::assembleDofs , py::const_), "Assemble 'dofval'" , py::arg("elemvec")) - .def("assembleDofs_u", py::overload_cast&>(&M::Vector::assembleDofs_u, py::const_), "Assemble 'dofval'" , py::arg("nodevec")) - .def("assembleDofs_u", py::overload_cast&>(&M::Vector::assembleDofs_u, py::const_), "Assemble 'dofval'" , py::arg("elemvec")) - .def("assembleDofs_p", py::overload_cast&>(&M::Vector::assembleDofs_p, py::const_), "Assemble 'dofval'" , py::arg("nodevec")) - .def("assembleDofs_p", py::overload_cast&>(&M::Vector::assembleDofs_p, py::const_), "Assemble 'dofval'" , py::arg("elemvec")) - - .def("assembleNode" , py::overload_cast&>(&M::Vector::assembleNode , py::const_), "Assemble 'nodevec'", py::arg("elemvec")) - - .def("__repr__", [](const xGooseFEM::Vector &){ return ""; }); - -// ==================================== GooseFEM.MatrixDiagonal ==================================== - -py::class_(m, "MatrixDiagonal") - - .def(py::init &, const xt::xtensor & >(), "Diagonal matrix", py::arg("conn"), py::arg("dofs")) - .def(py::init &, const xt::xtensor &, const xt::xtensor &>(), "Diagonal matrix", py::arg("conn"), py::arg("dofs"), py::arg("iip")) - - .def("nelem", &M::MatrixDiagonal::nelem, "Return number of element") - .def("nne" , &M::MatrixDiagonal::nne , "Return number of nodes per element") - .def("nnode", &M::MatrixDiagonal::nnode, "Return number of nodes") - .def("ndim" , &M::MatrixDiagonal::ndim , "Return number of dimensions") - .def("ndof" , &M::MatrixDiagonal::ndof , "Return number of degrees-of-freedom") - .def("nnu" , &M::MatrixDiagonal::nnu , "Return number of unknown degrees-of-freedom") - .def("nnp" , &M::MatrixDiagonal::nnp , "Return number of prescribed degrees-of-freedom") - - .def("dofs" , &M::MatrixDiagonal::dofs , "Return degrees-of-freedom") - .def("iiu" , &M::MatrixDiagonal::iiu , "Return unknown degrees-of-freedom") - .def("iip" , &M::MatrixDiagonal::iip , "Return prescribed degrees-of-freedom") - - .def("dot" , &M::MatrixDiagonal::dot , "Dot product 'b_i = A_ij * x_j", py::arg("x")) - .def("dot_u", &M::MatrixDiagonal::dot_u, "Dot product 'b_i = A_ij * x_j", py::arg("x_u"), py::arg("x_p")) - .def("dot_p", &M::MatrixDiagonal::dot_p, "Dot product 'b_i = A_ij * x_j", py::arg("x_u"), py::arg("x_p")) - - .def("assemble", &M::MatrixDiagonal::assemble, "Assemble from 'elemmat", py::arg("elemmat")) - - .def("solve" , py::overload_cast& >(&M::MatrixDiagonal::solve ), "Solve", py::arg("b" ) ) - .def("solve" , py::overload_cast&, const xt::xtensor&>(&M::MatrixDiagonal::solve ), "Solve", py::arg("b" ), py::arg("x_p")) - .def("solve_u", py::overload_cast&, const xt::xtensor&>(&M::MatrixDiagonal::solve_u), "Solve", py::arg("b_u"), py::arg("x_p")) - - .def("asDiagonal", &M::MatrixDiagonal::asDiagonal, "Return as diagonal matrix (column)") - - .def("__repr__", [](const xGooseFEM::MatrixDiagonal &){ return ""; }); - -// ======================================= GooseFEM.Dynamics ======================================= - -py::module mDynamics = m.def_submodule("Dynamics", "Solve routines for dynamic FEM"); - -// ------------------------------------------------------------------------------------------------- - -mDynamics.def("Verlet" , &xGooseFEM::Dynamics::Verlet , "Verlet time integration" , py::arg("geometry"), py::arg("dt"), py::arg("nstep")=1); -mDynamics.def("velocityVerlet", &xGooseFEM::Dynamics::velocityVerlet, "Velocity-Verlet time integration", py::arg("geometry"), py::arg("dt"), py::arg("nstep")=1); - -// ------------------------------------------------------------------------------------------------- - -py::class_(mDynamics, "Geometry") - - .def(py::init<>()) - - .def("solve_A" , &xGooseFEM::Dynamics::Geometry::solve_A, "Solve for accelerations (dofval)" ) - .def("solve_V" , &xGooseFEM::Dynamics::Geometry::solve_V, "Solve for velocities (dofval)" ) - - .def("u" , &xGooseFEM::Dynamics::Geometry::u , "Return displacements (nodevec)") - .def("v" , &xGooseFEM::Dynamics::Geometry::v , "Return velocities (nodevec)") - .def("a" , &xGooseFEM::Dynamics::Geometry::a , "Return accelerations (nodevec)") - - .def("dofs_u" , &xGooseFEM::Dynamics::Geometry::dofs_u , "Return displacements (dofval)" ) - .def("dofs_v" , &xGooseFEM::Dynamics::Geometry::dofs_v , "Return velocities (dofval)" ) - .def("dofs_a" , &xGooseFEM::Dynamics::Geometry::dofs_a , "Return accelerations (dofval)" ) - - .def("set_u" , py::overload_cast &>(&xGooseFEM::Dynamics::Geometry::set_u), "Overwrite displacements", py::arg("dofval" )) - .def("set_u" , py::overload_cast &>(&xGooseFEM::Dynamics::Geometry::set_u), "Overwrite displacements", py::arg("nodevec")) - .def("set_v" , &xGooseFEM::Dynamics::Geometry::set_v , "Overwrite velocities" , py::arg("nodevec")) - .def("set_a" , &xGooseFEM::Dynamics::Geometry::set_a , "Overwrite accelerations", py::arg("nodevec")) - - .def("__repr__", [](const xGooseFEM::Dynamics::Geometry &){ return ""; }); - -// ======================================= GooseFEM.Element ======================================== - -py::module mElement = m.def_submodule("Element", "Generic element routines"); - -// ------------------------------------------------------------------------------------------------- - -mElement.def("asElementVector" , &xGooseFEM::Element::asElementVector , "Covert to 'elemvec'", py::arg("conn"), py::arg("nodevec")); -mElement.def("assembleElementVector", &xGooseFEM::Element::assembleNodeVector, "Assemble 'nodevec'" , py::arg("conn"), py::arg("elemvec")); - -// ==================================== GooseFEM.Element.Quad4 ===================================== - -{ - -py::module sm = mElement.def_submodule("Quad4", "Linear quadrilateral elements (2D)"); - -// ------------------------------------------------------------------------------------------------- - -py::class_(sm, "Quadrature") - - .def(py::init &>(), "Quadrature", py::arg("x")) - - .def(py::init &, const xt::xtensor &, const xt::xtensor &>(), "Quadrature", py::arg("x"), py::arg("xi"), py::arg("w")) - - .def("nelem", &xGooseFEM::Element::Quad4::Quadrature::nelem, "Return number of elements" ) - .def("nne" , &xGooseFEM::Element::Quad4::Quadrature::nne , "Return number of nodes per element" ) - .def("ndim" , &xGooseFEM::Element::Quad4::Quadrature::ndim , "Return number of dimensions" ) - .def("nip" , &xGooseFEM::Element::Quad4::Quadrature::nip , "Return number of integration points") - - .def("dV" , py::overload_cast<>(&xGooseFEM::Element::Quad4::Quadrature::dV , py::const_), "Integration point volume (qscalar)") - .def("dVtensor", py::overload_cast<>(&xGooseFEM::Element::Quad4::Quadrature::dVtensor, py::const_), "Integration point volume (qtensor)") - - .def("gradN_vector" , py::overload_cast &>(&xGooseFEM::Element::Quad4::Quadrature::gradN_vector , py::const_), "Dyadic product, returns 'qtensor'", py::arg("elemvec")) - .def("gradN_vector_T" , py::overload_cast &>(&xGooseFEM::Element::Quad4::Quadrature::gradN_vector_T , py::const_), "Dyadic product, returns 'qtensor'", py::arg("elemvec")) - .def("symGradN_vector", py::overload_cast &>(&xGooseFEM::Element::Quad4::Quadrature::symGradN_vector, py::const_), "Dyadic product, returns 'qtensor'", py::arg("elemvec")) - - .def("int_N_scalar_NT_dV" , py::overload_cast &>(&xGooseFEM::Element::Quad4::Quadrature::int_N_scalar_NT_dV , py::const_), "Integration, returns 'elemmat'", py::arg("qscalar")) - .def("int_gradN_dot_tensor2_dV", py::overload_cast &>(&xGooseFEM::Element::Quad4::Quadrature::int_gradN_dot_tensor2_dV, py::const_), "Integration, returns 'elemvec'", py::arg("qtensor")) - - .def("__repr__", [](const xGooseFEM::Element::Quad4::Quadrature &){ return ""; }); - -// ------------------------------------------------------------------------------------------------- - -{ - -py::module ssm = sm.def_submodule("Gauss", "Gauss quadrature"); - -ssm.def("nip", &xGooseFEM::Element::Quad4::Gauss::nip, "Return number of integration point" ); -ssm.def("xi" , &xGooseFEM::Element::Quad4::Gauss::xi , "Return integration point coordinates"); -ssm.def("w" , &xGooseFEM::Element::Quad4::Gauss::w , "Return integration point weights" ); - -} - -// ------------------------------------------------------------------------------------------------- - -{ - -py::module ssm = sm.def_submodule("Nodal", "Nodal quadrature"); - -ssm.def("nip", &xGooseFEM::Element::Quad4::Nodal::nip, "Return number of integration point" ); -ssm.def("xi" , &xGooseFEM::Element::Quad4::Nodal::xi , "Return integration point coordinates"); -ssm.def("w" , &xGooseFEM::Element::Quad4::Nodal::w , "Return integration point weights" ); - -} - -// ------------------------------------------------------------------------------------------------- - -} - -// ===================================== GooseFEM.Element.Hex8 ===================================== - -{ - -py::module sm = mElement.def_submodule("Hex8", "Linear hexahedron (brick) elements (3D)"); - -// ------------------------------------------------------------------------------------------------- - -py::class_(sm, "Quadrature") - - .def(py::init &>(), "Quadrature", py::arg("x")) - - .def(py::init &, const xt::xtensor &, const xt::xtensor &>(), "Quadrature", py::arg("x"), py::arg("xi"), py::arg("w")) - - .def("nelem", &xGooseFEM::Element::Hex8::Quadrature::nelem, "Return number of elements" ) - .def("nne" , &xGooseFEM::Element::Hex8::Quadrature::nne , "Return number of nodes per element" ) - .def("ndim" , &xGooseFEM::Element::Hex8::Quadrature::ndim , "Return number of dimensions" ) - .def("nip" , &xGooseFEM::Element::Hex8::Quadrature::nip , "Return number of integration points") - - .def("dV" , py::overload_cast<>(&xGooseFEM::Element::Hex8::Quadrature::dV , py::const_), "Integration point volume (qscalar)") - .def("dVtensor", py::overload_cast<>(&xGooseFEM::Element::Hex8::Quadrature::dVtensor, py::const_), "Integration point volume (qtensor)") - - .def("gradN_vector" , py::overload_cast &>(&xGooseFEM::Element::Hex8::Quadrature::gradN_vector , py::const_), "Dyadic product, returns 'qtensor'", py::arg("elemvec")) - .def("gradN_vector_T" , py::overload_cast &>(&xGooseFEM::Element::Hex8::Quadrature::gradN_vector_T , py::const_), "Dyadic product, returns 'qtensor'", py::arg("elemvec")) - .def("symGradN_vector", py::overload_cast &>(&xGooseFEM::Element::Hex8::Quadrature::symGradN_vector, py::const_), "Dyadic product, returns 'qtensor'", py::arg("elemvec")) - - .def("int_N_scalar_NT_dV" , py::overload_cast &>(&xGooseFEM::Element::Hex8::Quadrature::int_N_scalar_NT_dV , py::const_), "Integration, returns 'elemmat'", py::arg("qscalar")) - .def("int_gradN_dot_tensor2_dV", py::overload_cast &>(&xGooseFEM::Element::Hex8::Quadrature::int_gradN_dot_tensor2_dV, py::const_), "Integration, returns 'elemvec'", py::arg("qtensor")) - - .def("__repr__", [](const xGooseFEM::Element::Hex8::Quadrature &){ return ""; }); - -// ------------------------------------------------------------------------------------------------- - -{ - -py::module ssm = sm.def_submodule("Gauss", "Gauss quadrature"); - -ssm.def("nip", &xGooseFEM::Element::Hex8::Gauss::nip, "Return number of integration point" ); -ssm.def("xi" , &xGooseFEM::Element::Hex8::Gauss::xi , "Return integration point coordinates"); -ssm.def("w" , &xGooseFEM::Element::Hex8::Gauss::w , "Return integration point weights" ); - -} - -// ------------------------------------------------------------------------------------------------- - -{ - -py::module ssm = sm.def_submodule("Nodal", "Nodal quadrature"); - -ssm.def("nip", &xGooseFEM::Element::Hex8::Nodal::nip, "Return number of integration point" ); -ssm.def("xi" , &xGooseFEM::Element::Hex8::Nodal::xi , "Return integration point coordinates"); -ssm.def("w" , &xGooseFEM::Element::Hex8::Nodal::w , "Return integration point weights" ); - -} - -// ------------------------------------------------------------------------------------------------- - -} - -// ========================================= GooseFEM.Mesh ========================================= - -py::module mMesh = m.def_submodule("Mesh", "Generic mesh routines"); - -// ------------------------------------------------------------------------------------------------- - -mMesh.def("dofs", &xGooseFEM::Mesh::dofs, "List with DOF-numbers (in sequential order)", py::arg("nnode"), py::arg("ndim")); - -mMesh.def("renumber", &xGooseFEM::Mesh::renumber, "Renumber DOF-list to use the lowest possible index", py::arg("dofs")); - -mMesh.def("renumber_index", &xGooseFEM::Mesh::renumber_index, "Index-list to renumber", py::arg("dofs")); - -mMesh.def("reorder", &xGooseFEM::Mesh::reorder, "Renumber DOF-list to begin or end with 'idx'", py::arg("dofs"), py::arg("idx"), py::arg("location")="end"); - -mMesh.def("reorder_index", &xGooseFEM::Mesh::reorder_index, "Index-list to reorder", py::arg("dofs"), py::arg("idx"), py::arg("location")="end"); - -mMesh.def("coordination", &xGooseFEM::Mesh::coordination, "Coordination number of each node", py::arg("conn")); - -mMesh.def("elem2node", &xGooseFEM::Mesh::elem2node, "Elements connect to each node", py::arg("conn")); - -// ====================================== GooseFEM.Mesh.Hex8 ======================================= - -{ - -py::module sm = mMesh.def_submodule("Hex8", "Linear hexahedron (brick) elements (3D)"); - -// ------------------------------------------------------------------------------------------------- - -py::class_(sm, "Regular") - - .def(py::init(), "mesh with nx*ny*nz 'pixels' and edge size h", py::arg("nx"), py::arg("ny"), py::arg("nz"), py::arg("h")=1.) - - .def("nelem" , &xGooseFEM::Mesh::Hex8::Regular::nelem ) - .def("nnode" , &xGooseFEM::Mesh::Hex8::Regular::nnode ) - .def("nne" , &xGooseFEM::Mesh::Hex8::Regular::nne ) - .def("ndim" , &xGooseFEM::Mesh::Hex8::Regular::ndim ) - - .def("coor" , &xGooseFEM::Mesh::Hex8::Regular::coor ) - .def("conn" , &xGooseFEM::Mesh::Hex8::Regular::conn ) - - .def("nodesFront" , &xGooseFEM::Mesh::Hex8::Regular::nodesFront ) - .def("nodesBack" , &xGooseFEM::Mesh::Hex8::Regular::nodesBack ) - .def("nodesLeft" , &xGooseFEM::Mesh::Hex8::Regular::nodesLeft ) - .def("nodesRight" , &xGooseFEM::Mesh::Hex8::Regular::nodesRight ) - .def("nodesBottom" , &xGooseFEM::Mesh::Hex8::Regular::nodesBottom ) - .def("nodesTop" , &xGooseFEM::Mesh::Hex8::Regular::nodesTop ) - - .def("nodesFrontFace" , &xGooseFEM::Mesh::Hex8::Regular::nodesFrontFace ) - .def("nodesBackFace" , &xGooseFEM::Mesh::Hex8::Regular::nodesBackFace ) - .def("nodesLeftFace" , &xGooseFEM::Mesh::Hex8::Regular::nodesLeftFace ) - .def("nodesRightFace" , &xGooseFEM::Mesh::Hex8::Regular::nodesRightFace ) - .def("nodesBottomFace" , &xGooseFEM::Mesh::Hex8::Regular::nodesBottomFace ) - .def("nodesTopFace" , &xGooseFEM::Mesh::Hex8::Regular::nodesTopFace ) - - .def("nodesFrontBottomEdge" , &xGooseFEM::Mesh::Hex8::Regular::nodesFrontBottomEdge ) - .def("nodesFrontTopEdge" , &xGooseFEM::Mesh::Hex8::Regular::nodesFrontTopEdge ) - .def("nodesFrontLeftEdge" , &xGooseFEM::Mesh::Hex8::Regular::nodesFrontLeftEdge ) - .def("nodesFrontRightEdge" , &xGooseFEM::Mesh::Hex8::Regular::nodesFrontRightEdge ) - .def("nodesBackBottomEdge" , &xGooseFEM::Mesh::Hex8::Regular::nodesBackBottomEdge ) - .def("nodesBackTopEdge" , &xGooseFEM::Mesh::Hex8::Regular::nodesBackTopEdge ) - .def("nodesBackLeftEdge" , &xGooseFEM::Mesh::Hex8::Regular::nodesBackLeftEdge ) - .def("nodesBackRightEdge" , &xGooseFEM::Mesh::Hex8::Regular::nodesBackRightEdge ) - .def("nodesBottomLeftEdge" , &xGooseFEM::Mesh::Hex8::Regular::nodesBottomLeftEdge ) - .def("nodesBottomRightEdge" , &xGooseFEM::Mesh::Hex8::Regular::nodesBottomRightEdge ) - .def("nodesTopLeftEdge" , &xGooseFEM::Mesh::Hex8::Regular::nodesTopLeftEdge ) - .def("nodesTopRightEdge" , &xGooseFEM::Mesh::Hex8::Regular::nodesTopRightEdge ) - - .def("nodesBottomFrontEdge" , &xGooseFEM::Mesh::Hex8::Regular::nodesBottomFrontEdge ) - .def("nodesBottomBackEdge" , &xGooseFEM::Mesh::Hex8::Regular::nodesBottomBackEdge ) - .def("nodesTopFrontEdge" , &xGooseFEM::Mesh::Hex8::Regular::nodesTopFrontEdge ) - .def("nodesTopBackEdge" , &xGooseFEM::Mesh::Hex8::Regular::nodesTopBackEdge ) - .def("nodesLeftBottomEdge" , &xGooseFEM::Mesh::Hex8::Regular::nodesLeftBottomEdge ) - .def("nodesLeftFrontEdge" , &xGooseFEM::Mesh::Hex8::Regular::nodesLeftFrontEdge ) - .def("nodesLeftBackEdge" , &xGooseFEM::Mesh::Hex8::Regular::nodesLeftBackEdge ) - .def("nodesLeftTopEdge" , &xGooseFEM::Mesh::Hex8::Regular::nodesLeftTopEdge ) - .def("nodesRightBottomEdge" , &xGooseFEM::Mesh::Hex8::Regular::nodesRightBottomEdge ) - .def("nodesRightTopEdge" , &xGooseFEM::Mesh::Hex8::Regular::nodesRightTopEdge ) - .def("nodesRightFrontEdge" , &xGooseFEM::Mesh::Hex8::Regular::nodesRightFrontEdge ) - .def("nodesRightBackEdge" , &xGooseFEM::Mesh::Hex8::Regular::nodesRightBackEdge ) - - .def("nodesFrontBottomOpenEdge" , &xGooseFEM::Mesh::Hex8::Regular::nodesFrontBottomOpenEdge ) - .def("nodesFrontTopOpenEdge" , &xGooseFEM::Mesh::Hex8::Regular::nodesFrontTopOpenEdge ) - .def("nodesFrontLeftOpenEdge" , &xGooseFEM::Mesh::Hex8::Regular::nodesFrontLeftOpenEdge ) - .def("nodesFrontRightOpenEdge" , &xGooseFEM::Mesh::Hex8::Regular::nodesFrontRightOpenEdge ) - .def("nodesBackBottomOpenEdge" , &xGooseFEM::Mesh::Hex8::Regular::nodesBackBottomOpenEdge ) - .def("nodesBackTopOpenEdge" , &xGooseFEM::Mesh::Hex8::Regular::nodesBackTopOpenEdge ) - .def("nodesBackLeftOpenEdge" , &xGooseFEM::Mesh::Hex8::Regular::nodesBackLeftOpenEdge ) - .def("nodesBackRightOpenEdge" , &xGooseFEM::Mesh::Hex8::Regular::nodesBackRightOpenEdge ) - .def("nodesBottomLeftOpenEdge" , &xGooseFEM::Mesh::Hex8::Regular::nodesBottomLeftOpenEdge ) - .def("nodesBottomRightOpenEdge" , &xGooseFEM::Mesh::Hex8::Regular::nodesBottomRightOpenEdge ) - .def("nodesTopLeftOpenEdge" , &xGooseFEM::Mesh::Hex8::Regular::nodesTopLeftOpenEdge ) - .def("nodesTopRightOpenEdge" , &xGooseFEM::Mesh::Hex8::Regular::nodesTopRightOpenEdge ) - - .def("nodesBottomFrontOpenEdge" , &xGooseFEM::Mesh::Hex8::Regular::nodesBottomFrontOpenEdge ) - .def("nodesBottomBackOpenEdge" , &xGooseFEM::Mesh::Hex8::Regular::nodesBottomBackOpenEdge ) - .def("nodesTopFrontOpenEdge" , &xGooseFEM::Mesh::Hex8::Regular::nodesTopFrontOpenEdge ) - .def("nodesTopBackOpenEdge" , &xGooseFEM::Mesh::Hex8::Regular::nodesTopBackOpenEdge ) - .def("nodesLeftBottomOpenEdge" , &xGooseFEM::Mesh::Hex8::Regular::nodesLeftBottomOpenEdge ) - .def("nodesLeftFrontOpenEdge" , &xGooseFEM::Mesh::Hex8::Regular::nodesLeftFrontOpenEdge ) - .def("nodesLeftBackOpenEdge" , &xGooseFEM::Mesh::Hex8::Regular::nodesLeftBackOpenEdge ) - .def("nodesLeftTopOpenEdge" , &xGooseFEM::Mesh::Hex8::Regular::nodesLeftTopOpenEdge ) - .def("nodesRightBottomOpenEdge" , &xGooseFEM::Mesh::Hex8::Regular::nodesRightBottomOpenEdge ) - .def("nodesRightTopOpenEdge" , &xGooseFEM::Mesh::Hex8::Regular::nodesRightTopOpenEdge ) - .def("nodesRightFrontOpenEdge" , &xGooseFEM::Mesh::Hex8::Regular::nodesRightFrontOpenEdge ) - .def("nodesRightBackOpenEdge" , &xGooseFEM::Mesh::Hex8::Regular::nodesRightBackOpenEdge ) - - .def("nodesFrontBottomLeftCorner" , &xGooseFEM::Mesh::Hex8::Regular::nodesFrontBottomLeftCorner ) - .def("nodesFrontBottomRightCorner", &xGooseFEM::Mesh::Hex8::Regular::nodesFrontBottomRightCorner) - .def("nodesFrontTopLeftCorner" , &xGooseFEM::Mesh::Hex8::Regular::nodesFrontTopLeftCorner ) - .def("nodesFrontTopRightCorner" , &xGooseFEM::Mesh::Hex8::Regular::nodesFrontTopRightCorner ) - .def("nodesBackBottomLeftCorner" , &xGooseFEM::Mesh::Hex8::Regular::nodesBackBottomLeftCorner ) - .def("nodesBackBottomRightCorner" , &xGooseFEM::Mesh::Hex8::Regular::nodesBackBottomRightCorner ) - .def("nodesBackTopLeftCorner" , &xGooseFEM::Mesh::Hex8::Regular::nodesBackTopLeftCorner ) - .def("nodesBackTopRightCorner" , &xGooseFEM::Mesh::Hex8::Regular::nodesBackTopRightCorner ) - - .def("nodesFrontLeftBottomCorner" , &xGooseFEM::Mesh::Hex8::Regular::nodesFrontLeftBottomCorner ) - .def("nodesBottomFrontLeftCorner" , &xGooseFEM::Mesh::Hex8::Regular::nodesBottomFrontLeftCorner ) - .def("nodesBottomLeftFrontCorner" , &xGooseFEM::Mesh::Hex8::Regular::nodesBottomLeftFrontCorner ) - .def("nodesLeftFrontBottomCorner" , &xGooseFEM::Mesh::Hex8::Regular::nodesLeftFrontBottomCorner ) - .def("nodesLeftBottomFrontCorner" , &xGooseFEM::Mesh::Hex8::Regular::nodesLeftBottomFrontCorner ) - .def("nodesFrontRightBottomCorner", &xGooseFEM::Mesh::Hex8::Regular::nodesFrontRightBottomCorner) - .def("nodesBottomFrontRightCorner", &xGooseFEM::Mesh::Hex8::Regular::nodesBottomFrontRightCorner) - .def("nodesBottomRightFrontCorner", &xGooseFEM::Mesh::Hex8::Regular::nodesBottomRightFrontCorner) - .def("nodesRightFrontBottomCorner", &xGooseFEM::Mesh::Hex8::Regular::nodesRightFrontBottomCorner) - .def("nodesRightBottomFrontCorner", &xGooseFEM::Mesh::Hex8::Regular::nodesRightBottomFrontCorner) - .def("nodesFrontLeftTopCorner" , &xGooseFEM::Mesh::Hex8::Regular::nodesFrontLeftTopCorner ) - .def("nodesTopFrontLeftCorner" , &xGooseFEM::Mesh::Hex8::Regular::nodesTopFrontLeftCorner ) - .def("nodesTopLeftFrontCorner" , &xGooseFEM::Mesh::Hex8::Regular::nodesTopLeftFrontCorner ) - .def("nodesLeftFrontTopCorner" , &xGooseFEM::Mesh::Hex8::Regular::nodesLeftFrontTopCorner ) - .def("nodesLeftTopFrontCorner" , &xGooseFEM::Mesh::Hex8::Regular::nodesLeftTopFrontCorner ) - .def("nodesFrontRightTopCorner" , &xGooseFEM::Mesh::Hex8::Regular::nodesFrontRightTopCorner ) - .def("nodesTopFrontRightCorner" , &xGooseFEM::Mesh::Hex8::Regular::nodesTopFrontRightCorner ) - .def("nodesTopRightFrontCorner" , &xGooseFEM::Mesh::Hex8::Regular::nodesTopRightFrontCorner ) - .def("nodesRightFrontTopCorner" , &xGooseFEM::Mesh::Hex8::Regular::nodesRightFrontTopCorner ) - .def("nodesRightTopFrontCorner" , &xGooseFEM::Mesh::Hex8::Regular::nodesRightTopFrontCorner ) - .def("nodesBackLeftBottomCorner" , &xGooseFEM::Mesh::Hex8::Regular::nodesBackLeftBottomCorner ) - .def("nodesBottomBackLeftCorner" , &xGooseFEM::Mesh::Hex8::Regular::nodesBottomBackLeftCorner ) - .def("nodesBottomLeftBackCorner" , &xGooseFEM::Mesh::Hex8::Regular::nodesBottomLeftBackCorner ) - .def("nodesLeftBackBottomCorner" , &xGooseFEM::Mesh::Hex8::Regular::nodesLeftBackBottomCorner ) - .def("nodesLeftBottomBackCorner" , &xGooseFEM::Mesh::Hex8::Regular::nodesLeftBottomBackCorner ) - .def("nodesBackRightBottomCorner" , &xGooseFEM::Mesh::Hex8::Regular::nodesBackRightBottomCorner ) - .def("nodesBottomBackRightCorner" , &xGooseFEM::Mesh::Hex8::Regular::nodesBottomBackRightCorner ) - .def("nodesBottomRightBackCorner" , &xGooseFEM::Mesh::Hex8::Regular::nodesBottomRightBackCorner ) - .def("nodesRightBackBottomCorner" , &xGooseFEM::Mesh::Hex8::Regular::nodesRightBackBottomCorner ) - .def("nodesRightBottomBackCorner" , &xGooseFEM::Mesh::Hex8::Regular::nodesRightBottomBackCorner ) - .def("nodesBackLeftTopCorner" , &xGooseFEM::Mesh::Hex8::Regular::nodesBackLeftTopCorner ) - .def("nodesTopBackLeftCorner" , &xGooseFEM::Mesh::Hex8::Regular::nodesTopBackLeftCorner ) - .def("nodesTopLeftBackCorner" , &xGooseFEM::Mesh::Hex8::Regular::nodesTopLeftBackCorner ) - .def("nodesLeftBackTopCorner" , &xGooseFEM::Mesh::Hex8::Regular::nodesLeftBackTopCorner ) - .def("nodesLeftTopBackCorner" , &xGooseFEM::Mesh::Hex8::Regular::nodesLeftTopBackCorner ) - .def("nodesBackRightTopCorner" , &xGooseFEM::Mesh::Hex8::Regular::nodesBackRightTopCorner ) - .def("nodesTopBackRightCorner" , &xGooseFEM::Mesh::Hex8::Regular::nodesTopBackRightCorner ) - .def("nodesTopRightBackCorner" , &xGooseFEM::Mesh::Hex8::Regular::nodesTopRightBackCorner ) - .def("nodesRightBackTopCorner" , &xGooseFEM::Mesh::Hex8::Regular::nodesRightBackTopCorner ) - .def("nodesRightTopBackCorner" , &xGooseFEM::Mesh::Hex8::Regular::nodesRightTopBackCorner ) - - .def("nodesPeriodic" , &xGooseFEM::Mesh::Hex8::Regular::nodesPeriodic ) - .def("nodesOrigin" , &xGooseFEM::Mesh::Hex8::Regular::nodesOrigin ) - .def("dofs" , &xGooseFEM::Mesh::Hex8::Regular::dofs ) - .def("dofsPeriodic" , &xGooseFEM::Mesh::Hex8::Regular::dofsPeriodic ) - - .def("__repr__", [](const xGooseFEM::Mesh::Hex8::Regular &){ return ""; }); - -// ------------------------------------------------------------------------------------------------- - -py::class_(sm, "FineLayer") - - .def(py::init(), "mesh with nx*ny*nz 'pixels' and edge size h", py::arg("nx"), py::arg("ny"), py::arg("nz"), py::arg("h")=1., py::arg("nfine")=1) - - .def("nelem" , &xGooseFEM::Mesh::Hex8::FineLayer::nelem ) - .def("nnode" , &xGooseFEM::Mesh::Hex8::FineLayer::nnode ) - .def("nne" , &xGooseFEM::Mesh::Hex8::FineLayer::nne ) - .def("ndim" , &xGooseFEM::Mesh::Hex8::FineLayer::ndim ) - .def("shape" , &xGooseFEM::Mesh::Hex8::FineLayer::shape ) - - .def("coor" , &xGooseFEM::Mesh::Hex8::FineLayer::coor ) - .def("conn" , &xGooseFEM::Mesh::Hex8::FineLayer::conn ) - - .def("elementsMiddleLayer" , &xGooseFEM::Mesh::Hex8::FineLayer::elementsMiddleLayer ) - - .def("nodesFront" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesFront ) - .def("nodesBack" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesBack ) - .def("nodesLeft" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesLeft ) - .def("nodesRight" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesRight ) - .def("nodesBottom" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesBottom ) - .def("nodesTop" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesTop ) - - .def("nodesFrontFace" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesFrontFace ) - .def("nodesBackFace" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesBackFace ) - .def("nodesLeftFace" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesLeftFace ) - .def("nodesRightFace" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesRightFace ) - .def("nodesBottomFace" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesBottomFace ) - .def("nodesTopFace" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesTopFace ) - - .def("nodesFrontBottomEdge" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesFrontBottomEdge ) - .def("nodesFrontTopEdge" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesFrontTopEdge ) - .def("nodesFrontLeftEdge" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesFrontLeftEdge ) - .def("nodesFrontRightEdge" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesFrontRightEdge ) - .def("nodesBackBottomEdge" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesBackBottomEdge ) - .def("nodesBackTopEdge" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesBackTopEdge ) - .def("nodesBackLeftEdge" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesBackLeftEdge ) - .def("nodesBackRightEdge" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesBackRightEdge ) - .def("nodesBottomLeftEdge" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesBottomLeftEdge ) - .def("nodesBottomRightEdge" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesBottomRightEdge ) - .def("nodesTopLeftEdge" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesTopLeftEdge ) - .def("nodesTopRightEdge" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesTopRightEdge ) - - .def("nodesBottomFrontEdge" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesBottomFrontEdge ) - .def("nodesBottomBackEdge" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesBottomBackEdge ) - .def("nodesTopFrontEdge" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesTopFrontEdge ) - .def("nodesTopBackEdge" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesTopBackEdge ) - .def("nodesLeftBottomEdge" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesLeftBottomEdge ) - .def("nodesLeftFrontEdge" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesLeftFrontEdge ) - .def("nodesLeftBackEdge" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesLeftBackEdge ) - .def("nodesLeftTopEdge" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesLeftTopEdge ) - .def("nodesRightBottomEdge" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesRightBottomEdge ) - .def("nodesRightTopEdge" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesRightTopEdge ) - .def("nodesRightFrontEdge" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesRightFrontEdge ) - .def("nodesRightBackEdge" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesRightBackEdge ) - - .def("nodesFrontBottomOpenEdge" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesFrontBottomOpenEdge ) - .def("nodesFrontTopOpenEdge" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesFrontTopOpenEdge ) - .def("nodesFrontLeftOpenEdge" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesFrontLeftOpenEdge ) - .def("nodesFrontRightOpenEdge" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesFrontRightOpenEdge ) - .def("nodesBackBottomOpenEdge" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesBackBottomOpenEdge ) - .def("nodesBackTopOpenEdge" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesBackTopOpenEdge ) - .def("nodesBackLeftOpenEdge" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesBackLeftOpenEdge ) - .def("nodesBackRightOpenEdge" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesBackRightOpenEdge ) - .def("nodesBottomLeftOpenEdge" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesBottomLeftOpenEdge ) - .def("nodesBottomRightOpenEdge" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesBottomRightOpenEdge ) - .def("nodesTopLeftOpenEdge" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesTopLeftOpenEdge ) - .def("nodesTopRightOpenEdge" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesTopRightOpenEdge ) - - .def("nodesBottomFrontOpenEdge" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesBottomFrontOpenEdge ) - .def("nodesBottomBackOpenEdge" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesBottomBackOpenEdge ) - .def("nodesTopFrontOpenEdge" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesTopFrontOpenEdge ) - .def("nodesTopBackOpenEdge" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesTopBackOpenEdge ) - .def("nodesLeftBottomOpenEdge" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesLeftBottomOpenEdge ) - .def("nodesLeftFrontOpenEdge" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesLeftFrontOpenEdge ) - .def("nodesLeftBackOpenEdge" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesLeftBackOpenEdge ) - .def("nodesLeftTopOpenEdge" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesLeftTopOpenEdge ) - .def("nodesRightBottomOpenEdge" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesRightBottomOpenEdge ) - .def("nodesRightTopOpenEdge" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesRightTopOpenEdge ) - .def("nodesRightFrontOpenEdge" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesRightFrontOpenEdge ) - .def("nodesRightBackOpenEdge" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesRightBackOpenEdge ) - - .def("nodesFrontBottomLeftCorner" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesFrontBottomLeftCorner ) - .def("nodesFrontBottomRightCorner", &xGooseFEM::Mesh::Hex8::FineLayer::nodesFrontBottomRightCorner) - .def("nodesFrontTopLeftCorner" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesFrontTopLeftCorner ) - .def("nodesFrontTopRightCorner" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesFrontTopRightCorner ) - .def("nodesBackBottomLeftCorner" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesBackBottomLeftCorner ) - .def("nodesBackBottomRightCorner" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesBackBottomRightCorner ) - .def("nodesBackTopLeftCorner" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesBackTopLeftCorner ) - .def("nodesBackTopRightCorner" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesBackTopRightCorner ) - - .def("nodesFrontLeftBottomCorner" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesFrontLeftBottomCorner ) - .def("nodesBottomFrontLeftCorner" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesBottomFrontLeftCorner ) - .def("nodesBottomLeftFrontCorner" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesBottomLeftFrontCorner ) - .def("nodesLeftFrontBottomCorner" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesLeftFrontBottomCorner ) - .def("nodesLeftBottomFrontCorner" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesLeftBottomFrontCorner ) - .def("nodesFrontRightBottomCorner", &xGooseFEM::Mesh::Hex8::FineLayer::nodesFrontRightBottomCorner) - .def("nodesBottomFrontRightCorner", &xGooseFEM::Mesh::Hex8::FineLayer::nodesBottomFrontRightCorner) - .def("nodesBottomRightFrontCorner", &xGooseFEM::Mesh::Hex8::FineLayer::nodesBottomRightFrontCorner) - .def("nodesRightFrontBottomCorner", &xGooseFEM::Mesh::Hex8::FineLayer::nodesRightFrontBottomCorner) - .def("nodesRightBottomFrontCorner", &xGooseFEM::Mesh::Hex8::FineLayer::nodesRightBottomFrontCorner) - .def("nodesFrontLeftTopCorner" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesFrontLeftTopCorner ) - .def("nodesTopFrontLeftCorner" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesTopFrontLeftCorner ) - .def("nodesTopLeftFrontCorner" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesTopLeftFrontCorner ) - .def("nodesLeftFrontTopCorner" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesLeftFrontTopCorner ) - .def("nodesLeftTopFrontCorner" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesLeftTopFrontCorner ) - .def("nodesFrontRightTopCorner" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesFrontRightTopCorner ) - .def("nodesTopFrontRightCorner" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesTopFrontRightCorner ) - .def("nodesTopRightFrontCorner" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesTopRightFrontCorner ) - .def("nodesRightFrontTopCorner" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesRightFrontTopCorner ) - .def("nodesRightTopFrontCorner" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesRightTopFrontCorner ) - .def("nodesBackLeftBottomCorner" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesBackLeftBottomCorner ) - .def("nodesBottomBackLeftCorner" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesBottomBackLeftCorner ) - .def("nodesBottomLeftBackCorner" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesBottomLeftBackCorner ) - .def("nodesLeftBackBottomCorner" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesLeftBackBottomCorner ) - .def("nodesLeftBottomBackCorner" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesLeftBottomBackCorner ) - .def("nodesBackRightBottomCorner" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesBackRightBottomCorner ) - .def("nodesBottomBackRightCorner" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesBottomBackRightCorner ) - .def("nodesBottomRightBackCorner" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesBottomRightBackCorner ) - .def("nodesRightBackBottomCorner" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesRightBackBottomCorner ) - .def("nodesRightBottomBackCorner" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesRightBottomBackCorner ) - .def("nodesBackLeftTopCorner" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesBackLeftTopCorner ) - .def("nodesTopBackLeftCorner" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesTopBackLeftCorner ) - .def("nodesTopLeftBackCorner" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesTopLeftBackCorner ) - .def("nodesLeftBackTopCorner" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesLeftBackTopCorner ) - .def("nodesLeftTopBackCorner" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesLeftTopBackCorner ) - .def("nodesBackRightTopCorner" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesBackRightTopCorner ) - .def("nodesTopBackRightCorner" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesTopBackRightCorner ) - .def("nodesTopRightBackCorner" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesTopRightBackCorner ) - .def("nodesRightBackTopCorner" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesRightBackTopCorner ) - .def("nodesRightTopBackCorner" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesRightTopBackCorner ) - - .def("nodesPeriodic" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesPeriodic ) - .def("nodesOrigin" , &xGooseFEM::Mesh::Hex8::FineLayer::nodesOrigin ) - - .def("dofs" , &xGooseFEM::Mesh::Hex8::FineLayer::dofs ) - .def("dofsPeriodic" , &xGooseFEM::Mesh::Hex8::FineLayer::dofsPeriodic ) - - .def("__repr__", [](const xGooseFEM::Mesh::Hex8::FineLayer &){ return ""; }); - -// ------------------------------------------------------------------------------------------------- - -} - -// ====================================== GooseFEM.Mesh.Quad4 ====================================== - -{ - -py::module sm = mMesh.def_submodule("Quad4", "Linear quadrilateral elements (2D)"); - -// ------------------------------------------------------------------------------------------------- - -py::class_(sm, "Regular") - - .def(py::init(), "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" , &xGooseFEM::Mesh::Quad4::Regular::coor ) - .def("conn" , &xGooseFEM::Mesh::Quad4::Regular::conn ) - .def("nelem" , &xGooseFEM::Mesh::Quad4::Regular::nelem ) - .def("nnode" , &xGooseFEM::Mesh::Quad4::Regular::nnode ) - .def("nne" , &xGooseFEM::Mesh::Quad4::Regular::nne ) - .def("ndim" , &xGooseFEM::Mesh::Quad4::Regular::ndim ) - - .def("nodesBottomEdge" , &xGooseFEM::Mesh::Quad4::Regular::nodesBottomEdge ) - .def("nodesTopEdge" , &xGooseFEM::Mesh::Quad4::Regular::nodesTopEdge ) - .def("nodesLeftEdge" , &xGooseFEM::Mesh::Quad4::Regular::nodesLeftEdge ) - .def("nodesRightEdge" , &xGooseFEM::Mesh::Quad4::Regular::nodesRightEdge ) - .def("nodesBottomOpenEdge" , &xGooseFEM::Mesh::Quad4::Regular::nodesBottomOpenEdge ) - .def("nodesTopOpenEdge" , &xGooseFEM::Mesh::Quad4::Regular::nodesTopOpenEdge ) - .def("nodesLeftOpenEdge" , &xGooseFEM::Mesh::Quad4::Regular::nodesLeftOpenEdge ) - .def("nodesRightOpenEdge" , &xGooseFEM::Mesh::Quad4::Regular::nodesRightOpenEdge ) - - .def("nodesBottomLeftCorner" , &xGooseFEM::Mesh::Quad4::Regular::nodesBottomLeftCorner ) - .def("nodesBottomRightCorner", &xGooseFEM::Mesh::Quad4::Regular::nodesBottomRightCorner) - .def("nodesTopLeftCorner" , &xGooseFEM::Mesh::Quad4::Regular::nodesTopLeftCorner ) - .def("nodesTopRightCorner" , &xGooseFEM::Mesh::Quad4::Regular::nodesTopRightCorner ) - .def("nodesLeftBottomCorner" , &xGooseFEM::Mesh::Quad4::Regular::nodesLeftBottomCorner ) - .def("nodesLeftTopCorner" , &xGooseFEM::Mesh::Quad4::Regular::nodesLeftTopCorner ) - .def("nodesRightBottomCorner", &xGooseFEM::Mesh::Quad4::Regular::nodesRightBottomCorner) - .def("nodesRightTopCorner" , &xGooseFEM::Mesh::Quad4::Regular::nodesRightTopCorner ) - - .def("nodesPeriodic" , &xGooseFEM::Mesh::Quad4::Regular::nodesPeriodic ) - .def("nodesOrigin" , &xGooseFEM::Mesh::Quad4::Regular::nodesOrigin ) - - .def("dofs" , &xGooseFEM::Mesh::Quad4::Regular::dofs ) - .def("dofsPeriodic" , &xGooseFEM::Mesh::Quad4::Regular::dofsPeriodic ) - - .def("__repr__", [](const xGooseFEM::Mesh::Quad4::Regular &){ return ""; }); - -// ------------------------------------------------------------------------------------------------- - -py::class_(sm, "FineLayer") - - .def( - py::init(), - "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("shape" , &xGooseFEM::Mesh::Quad4::FineLayer::shape ) - .def("coor" , &xGooseFEM::Mesh::Quad4::FineLayer::coor ) - .def("conn" , &xGooseFEM::Mesh::Quad4::FineLayer::conn ) - .def("nelem" , &xGooseFEM::Mesh::Quad4::FineLayer::nelem ) - .def("nnode" , &xGooseFEM::Mesh::Quad4::FineLayer::nnode ) - .def("nne" , &xGooseFEM::Mesh::Quad4::FineLayer::nne ) - .def("ndim" , &xGooseFEM::Mesh::Quad4::FineLayer::ndim ) - .def("elementsMiddleLayer" , &xGooseFEM::Mesh::Quad4::FineLayer::elementsMiddleLayer ) - .def("nodesBottomEdge" , &xGooseFEM::Mesh::Quad4::FineLayer::nodesBottomEdge ) - .def("nodesTopEdge" , &xGooseFEM::Mesh::Quad4::FineLayer::nodesTopEdge ) - .def("nodesLeftEdge" , &xGooseFEM::Mesh::Quad4::FineLayer::nodesLeftEdge ) - .def("nodesRightEdge" , &xGooseFEM::Mesh::Quad4::FineLayer::nodesRightEdge ) - .def("nodesBottomOpenEdge" , &xGooseFEM::Mesh::Quad4::FineLayer::nodesBottomOpenEdge ) - .def("nodesTopOpenEdge" , &xGooseFEM::Mesh::Quad4::FineLayer::nodesTopOpenEdge ) - .def("nodesLeftOpenEdge" , &xGooseFEM::Mesh::Quad4::FineLayer::nodesLeftOpenEdge ) - .def("nodesRightOpenEdge" , &xGooseFEM::Mesh::Quad4::FineLayer::nodesRightOpenEdge ) - .def("nodesBottomLeftCorner" , &xGooseFEM::Mesh::Quad4::FineLayer::nodesBottomLeftCorner ) - .def("nodesBottomRightCorner", &xGooseFEM::Mesh::Quad4::FineLayer::nodesBottomRightCorner) - .def("nodesTopLeftCorner" , &xGooseFEM::Mesh::Quad4::FineLayer::nodesTopLeftCorner ) - .def("nodesTopRightCorner" , &xGooseFEM::Mesh::Quad4::FineLayer::nodesTopRightCorner ) - .def("nodesLeftBottomCorner" , &xGooseFEM::Mesh::Quad4::FineLayer::nodesLeftBottomCorner ) - .def("nodesLeftTopCorner" , &xGooseFEM::Mesh::Quad4::FineLayer::nodesLeftTopCorner ) - .def("nodesRightBottomCorner", &xGooseFEM::Mesh::Quad4::FineLayer::nodesRightBottomCorner) - .def("nodesRightTopCorner" , &xGooseFEM::Mesh::Quad4::FineLayer::nodesRightTopCorner ) - .def("nodesPeriodic" , &xGooseFEM::Mesh::Quad4::FineLayer::nodesPeriodic ) - .def("nodesOrigin" , &xGooseFEM::Mesh::Quad4::FineLayer::nodesOrigin ) - .def("dofs" , &xGooseFEM::Mesh::Quad4::FineLayer::dofs ) - .def("dofsPeriodic" , &xGooseFEM::Mesh::Quad4::FineLayer::dofsPeriodic ) - - .def("__repr__", - [](const xGooseFEM::Mesh::Quad4::FineLayer &){ return ""; } - ); - -// ------------------------------------------------------------------------------------------------- - -} - -// ====================================== GooseFEM.Mesh.Tri3 ======================================= - -{ - -py::module sm = mMesh.def_submodule("Tri3" , "Linear triangular elements (2D)"); - -// ------------------------------------------------------------------------------------------------- - -py::class_(sm, "Regular") - - .def( - py::init(), - "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" , &xGooseFEM::Mesh::Tri3::Regular::coor ) - .def("conn" , &xGooseFEM::Mesh::Tri3::Regular::conn ) - .def("nelem" , &xGooseFEM::Mesh::Tri3::Regular::nelem ) - .def("nnode" , &xGooseFEM::Mesh::Tri3::Regular::nnode ) - .def("nne" , &xGooseFEM::Mesh::Tri3::Regular::nne ) - .def("ndim" , &xGooseFEM::Mesh::Tri3::Regular::ndim ) - - .def("nodesBottomEdge" , &xGooseFEM::Mesh::Tri3::Regular::nodesBottomEdge ) - .def("nodesTopEdge" , &xGooseFEM::Mesh::Tri3::Regular::nodesTopEdge ) - .def("nodesLeftEdge" , &xGooseFEM::Mesh::Tri3::Regular::nodesLeftEdge ) - .def("nodesRightEdge" , &xGooseFEM::Mesh::Tri3::Regular::nodesRightEdge ) - .def("nodesBottomOpenEdge" , &xGooseFEM::Mesh::Tri3::Regular::nodesBottomOpenEdge ) - .def("nodesTopOpenEdge" , &xGooseFEM::Mesh::Tri3::Regular::nodesTopOpenEdge ) - .def("nodesLeftOpenEdge" , &xGooseFEM::Mesh::Tri3::Regular::nodesLeftOpenEdge ) - .def("nodesRightOpenEdge" , &xGooseFEM::Mesh::Tri3::Regular::nodesRightOpenEdge ) - - .def("nodesBottomLeftCorner" , &xGooseFEM::Mesh::Tri3::Regular::nodesBottomLeftCorner ) - .def("nodesBottomRightCorner", &xGooseFEM::Mesh::Tri3::Regular::nodesBottomRightCorner) - .def("nodesTopLeftCorner" , &xGooseFEM::Mesh::Tri3::Regular::nodesTopLeftCorner ) - .def("nodesTopRightCorner" , &xGooseFEM::Mesh::Tri3::Regular::nodesTopRightCorner ) - .def("nodesLeftBottomCorner" , &xGooseFEM::Mesh::Tri3::Regular::nodesLeftBottomCorner ) - .def("nodesLeftTopCorner" , &xGooseFEM::Mesh::Tri3::Regular::nodesLeftTopCorner ) - .def("nodesRightBottomCorner", &xGooseFEM::Mesh::Tri3::Regular::nodesRightBottomCorner) - .def("nodesRightTopCorner" , &xGooseFEM::Mesh::Tri3::Regular::nodesRightTopCorner ) - - .def("nodesPeriodic" , &xGooseFEM::Mesh::Tri3::Regular::nodesPeriodic ) - .def("nodesOrigin" , &xGooseFEM::Mesh::Tri3::Regular::nodesOrigin ) - - .def("dofs" , &xGooseFEM::Mesh::Tri3::Regular::dofs ) - .def("dofsPeriodic" , &xGooseFEM::Mesh::Tri3::Regular::dofsPeriodic ) - - .def("__repr__", [](const xGooseFEM::Mesh::Tri3::Regular &){ return ""; }); - -// ------------------------------------------------------------------------------------------------- - -sm.def("getOrientation", &xGooseFEM::Mesh::Tri3::getOrientation, "Get the orientation of each element", py::arg("coor"), py::arg("conn")); - -sm.def("retriangulate", &xGooseFEM::Mesh::Tri3::retriangulate, "Re-triangulate existing mesh", py::arg("coor"), py::arg("conn"), py::arg("orientation")=-1); - -// ------------------------------------------------------------------------------------------------- - -} - -// ================================================================================================= - -} - diff --git a/setup.py b/setup.py index 3a175c3..ba69979 100644 --- a/setup.py +++ b/setup.py @@ -1,51 +1,51 @@ desc = ''' GooseFEM is a C++ module, wrapped in Python, that provides several predefined finite element meshes. The original C++ module also includes element definitions and several standard finite element simulations. ''' from setuptools import setup, Extension import sys, re import setuptools import pybind11 import pyxtensor -header = open('include/xGooseFEM/GooseFEM.h','r').read() -world = re.split(r'(.*)(\#define XGOOSEFEM_WORLD_VERSION\ )([0-9]+)(.*)',header)[3] -major = re.split(r'(.*)(\#define XGOOSEFEM_MAJOR_VERSION\ )([0-9]+)(.*)',header)[3] -minor = re.split(r'(.*)(\#define XGOOSEFEM_MINOR_VERSION\ )([0-9]+)(.*)',header)[3] +header = open('include/GooseFEM/GooseFEM.h','r').read() +world = re.split(r'(.*)(\#define GOOSEFEM_WORLD_VERSION\ )([0-9]+)(.*)',header)[3] +major = re.split(r'(.*)(\#define GOOSEFEM_MAJOR_VERSION\ )([0-9]+)(.*)',header)[3] +minor = re.split(r'(.*)(\#define GOOSEFEM_MINOR_VERSION\ )([0-9]+)(.*)',header)[3] __version__ = '.'.join([world,major,minor]) ext_modules = [ Extension( 'GooseFEM', - ['include/xGooseFEM/python.cpp'], + ['include/GooseFEM/python.cpp'], include_dirs=[ pybind11 .get_include(False), pybind11 .get_include(True ), pyxtensor.get_include(False), pyxtensor.get_include(True ), pyxtensor.find_xtensor(), pyxtensor.find_xtl(), pyxtensor.find_eigen(), ], language='c++' ), ] setup( name = 'GooseFEM', description = 'Finite element meshes, quadrature, and assembly tools', long_description = desc, version = __version__, license = 'GPLv3', author = 'Tom de Geus', author_email = 'tom@geus.me', url = 'https://github.com/tdegeus/GooseFEM', ext_modules = ext_modules, install_requires = ['pybind11>=2.2.0','pyxtensor>=0.0.1'], cmdclass = {'build_ext': pyxtensor.BuildExt}, zip_safe = False, ) diff --git a/test/ElementHex8.cpp b/test/ElementHex8.cpp index ad459ea..6d4acf5 100644 --- a/test/ElementHex8.cpp +++ b/test/ElementHex8.cpp @@ -1,148 +1,148 @@ #include "support.h" // ================================================================================================= -TEST_CASE("xGooseFEM::ElementHex8", "ElementHex8.h") +TEST_CASE("GooseFEM::ElementHex8", "ElementHex8.h") { using T2 = xt::xtensor_fixed>; // ================================================================================================= SECTION( "int_N_scalar_NT_dV" ) { // mesh - xGooseFEM::Mesh::Hex8::Regular mesh(3,3,3); + GooseFEM::Mesh::Hex8::Regular mesh(3,3,3); // vector-definition, and a diagonal matrix - xGooseFEM::Vector vec(mesh.conn(), mesh.dofsPeriodic()); - xGooseFEM::MatrixDiagonal mat(mesh.conn(), mesh.dofsPeriodic()); + GooseFEM::Vector vec(mesh.conn(), mesh.dofsPeriodic()); + GooseFEM::MatrixDiagonal mat(mesh.conn(), mesh.dofsPeriodic()); // element definition, with nodal quadrature - xGooseFEM::Element::Hex8::Quadrature quad( + GooseFEM::Element::Hex8::Quadrature quad( vec.asElement(mesh.coor()), - xGooseFEM::Element::Hex8::Nodal::xi(), - xGooseFEM::Element::Hex8::Nodal::w() + GooseFEM::Element::Hex8::Nodal::xi(), + GooseFEM::Element::Hex8::Nodal::w() ); // scalar per quadrature point (e.g. mass-density "rho") xt::xtensor rho = xt::ones({mesh.nelem(), quad.nip()}); // evaluate integral and assemble diagonal matrix (e.g. mass matrix) mat.assemble(quad.int_N_scalar_NT_dV(rho)); // check matrix // - get the matrix xt::xtensor M = mat.asDiagonal(); // - check the size REQUIRE( M.size() == vec.ndof() ); // - check each component REQUIRE( xt::allclose(M, 1.) ); } // ================================================================================================= SECTION( "symGradN_vector" ) { // mesh - xGooseFEM::Mesh::Hex8::FineLayer mesh(27,27,27); + GooseFEM::Mesh::Hex8::FineLayer mesh(27,27,27); // vector-definition - xGooseFEM::Vector vec(mesh.conn(), mesh.dofs()); + GooseFEM::Vector vec(mesh.conn(), mesh.dofs()); // element definition, with Gauss quadrature - xGooseFEM::Element::Hex8::Quadrature quad( vec.asElement(mesh.coor()) ); + GooseFEM::Element::Hex8::Quadrature quad( vec.asElement(mesh.coor()) ); // macroscopic deformation gradient and strain // - zero-initialize T2 F = xt::zeros({3,3}); T2 EPS = xt::zeros({3,3}); // - set non-zero components F (0,1) = 0.1; EPS(0,1) = 0.05; EPS(1,0) = 0.05; // nodal coordinates and displacement xt::xtensor coor = mesh.coor();; xt::xtensor disp = xt::zeros(coor.shape()); // apply macroscopic deformation gradient for ( size_t n = 0 ; n < mesh.nnode() ; ++n ) for ( size_t i = 0 ; i < F.shape()[0] ; ++i ) for ( size_t j = 0 ; j < F.shape()[1] ; ++j ) disp(n,i) += F(i,j) * coor(n,j); // compute quadrature point tensors xt::xtensor eps = quad.symGradN_vector(vec.asElement(disp)); // integration point volume xt::xtensor dV = eps; quad.dV(dV); // volume averaged strain tensor auto epsbar = xt::average(eps, dV, {0,1}); // check local strain tensors // - check sizes REQUIRE( eps.shape()[0] == mesh.nelem() ); REQUIRE( eps.shape()[1] == quad.nip() ); REQUIRE( eps.shape()[2] == mesh.ndim() ); REQUIRE( eps.shape()[3] == mesh.ndim() ); // - check all components for ( size_t e = 0 ; e < mesh.nelem() ; ++e ) { for ( size_t k = 0 ; k < quad.nip() ; ++k ) { auto Eps = xt::view(eps, e, k); REQUIRE( xt::allclose(Eps, EPS)); } } // check macroscopic tensor REQUIRE( xt::allclose(epsbar, EPS)); } // ================================================================================================= SECTION( "symGradN_vector, int_gradN_dot_tensor2s_dV" ) { // mesh - xGooseFEM::Mesh::Hex8::FineLayer mesh(27,27,27); + GooseFEM::Mesh::Hex8::FineLayer mesh(27,27,27); // vector-definition - xGooseFEM::Vector vec(mesh.conn(), mesh.dofsPeriodic()); + GooseFEM::Vector vec(mesh.conn(), mesh.dofsPeriodic()); // element definition, with Gauss quadrature - xGooseFEM::Element::Hex8::Quadrature quad( vec.asElement(mesh.coor()) ); + GooseFEM::Element::Hex8::Quadrature quad( vec.asElement(mesh.coor()) ); // macroscopic deformation gradient and strain // - zero-initialize T2 F = xt::zeros({3,3}); // - set non-zero components F(0,1) = 0.1; // nodal coordinates and displacement xt::xtensor coor = mesh.coor();; xt::xtensor disp = xt::zeros(coor.shape()); // apply macroscopic deformation gradient for ( size_t n = 0 ; n < mesh.nnode() ; ++n ) for ( size_t i = 0 ; i < F.shape()[0] ; ++i ) for ( size_t j = 0 ; j < F.shape()[1] ; ++j ) disp(n,i) += F(i,j) * coor(n,j); // compute quadrature point tensors xt::xtensor eps = quad.symGradN_vector(vec.asElement(disp)); // nodal force vector (should be zero, as it is only sensitive to periodic fluctuations) xt::xtensor Fi = vec.assembleDofs(quad.int_gradN_dot_tensor2_dV(eps)); // check // - size REQUIRE( Fi.size() == vec.ndof() ); // - check each component REQUIRE( xt::allclose(Fi, 0.) ); } // ================================================================================================= } diff --git a/test/ElementQuad4.cpp b/test/ElementQuad4.cpp index 3320a54..fbaea1e 100644 --- a/test/ElementQuad4.cpp +++ b/test/ElementQuad4.cpp @@ -1,148 +1,148 @@ #include "support.h" // ================================================================================================= -TEST_CASE("xGooseFEM::ElementQuad4", "ElementQuad4.h") +TEST_CASE("GooseFEM::ElementQuad4", "ElementQuad4.h") { using T2 = xt::xtensor_fixed>; // ================================================================================================= SECTION( "int_N_scalar_NT_dV" ) { // mesh - xGooseFEM::Mesh::Quad4::Regular mesh(3,3); + GooseFEM::Mesh::Quad4::Regular mesh(3,3); // vector-definition, and a diagonal matrix - xGooseFEM::Vector vec(mesh.conn(), mesh.dofsPeriodic()); - xGooseFEM::MatrixDiagonal mat(mesh.conn(), mesh.dofsPeriodic()); + GooseFEM::Vector vec(mesh.conn(), mesh.dofsPeriodic()); + GooseFEM::MatrixDiagonal mat(mesh.conn(), mesh.dofsPeriodic()); // element definition, with nodal quadrature - xGooseFEM::Element::Quad4::Quadrature quad( + GooseFEM::Element::Quad4::Quadrature quad( vec.asElement(mesh.coor()), - xGooseFEM::Element::Quad4::Nodal::xi(), - xGooseFEM::Element::Quad4::Nodal::w() + GooseFEM::Element::Quad4::Nodal::xi(), + GooseFEM::Element::Quad4::Nodal::w() ); // scalar per quadrature point (e.g. mass-density "rho") xt::xtensor rho = xt::ones({mesh.nelem(), quad.nip()}); // evaluate integral and assemble diagonal matrix (e.g. mass matrix) mat.assemble(quad.int_N_scalar_NT_dV(rho)); // check matrix // - get the matrix xt::xtensor M = mat.asDiagonal(); // - check the size REQUIRE( M.size() == vec.ndof() ); // - check each component REQUIRE( xt::allclose(M, 1.) ); } // ================================================================================================= SECTION( "symGradN_vector" ) { // mesh - xGooseFEM::Mesh::Quad4::FineLayer mesh(27,27); + GooseFEM::Mesh::Quad4::FineLayer mesh(27,27); // vector-definition - xGooseFEM::Vector vec(mesh.conn(), mesh.dofs()); + GooseFEM::Vector vec(mesh.conn(), mesh.dofs()); // element definition, with Gauss quadrature - xGooseFEM::Element::Quad4::Quadrature quad( vec.asElement(mesh.coor()) ); + GooseFEM::Element::Quad4::Quadrature quad( vec.asElement(mesh.coor()) ); // macroscopic deformation gradient and strain // - zero-initialize T2 F = xt::zeros({2,2}); T2 EPS = xt::zeros({2,2}); // - set non-zero components F (0,1) = 0.1; EPS(0,1) = 0.05; EPS(1,0) = 0.05; // nodal coordinates and displacement xt::xtensor coor = mesh.coor();; xt::xtensor disp = xt::zeros(coor.shape()); // apply macroscopic deformation gradient for ( size_t n = 0 ; n < mesh.nnode() ; ++n ) for ( size_t i = 0 ; i < F.shape()[0] ; ++i ) for ( size_t j = 0 ; j < F.shape()[1] ; ++j ) disp(n,i) += F(i,j) * coor(n,j); // compute quadrature point tensors xt::xtensor eps = quad.symGradN_vector(vec.asElement(disp)); // integration point volume xt::xtensor dV = eps; quad.dV(dV); // volume averaged strain tensor auto epsbar = xt::average(eps, dV, {0,1}); // check local strain tensors // - check sizes REQUIRE( eps.shape()[0] == mesh.nelem() ); REQUIRE( eps.shape()[1] == quad.nip() ); REQUIRE( eps.shape()[2] == mesh.ndim() ); REQUIRE( eps.shape()[3] == mesh.ndim() ); // - check all components for ( size_t e = 0 ; e < mesh.nelem() ; ++e ) { for ( size_t k = 0 ; k < quad.nip() ; ++k ) { auto Eps = xt::view(eps, e, k); REQUIRE( xt::allclose(Eps, EPS)); } } // check macroscopic tensor REQUIRE( xt::allclose(epsbar, EPS)); } // ================================================================================================= SECTION( "symGradN_vector, int_gradN_dot_tensor2s_dV" ) { // mesh - xGooseFEM::Mesh::Quad4::FineLayer mesh(27,27); + GooseFEM::Mesh::Quad4::FineLayer mesh(27,27); // vector-definition - xGooseFEM::Vector vec(mesh.conn(), mesh.dofsPeriodic()); + GooseFEM::Vector vec(mesh.conn(), mesh.dofsPeriodic()); // element definition, with Gauss quadrature - xGooseFEM::Element::Quad4::Quadrature quad( vec.asElement(mesh.coor()) ); + GooseFEM::Element::Quad4::Quadrature quad( vec.asElement(mesh.coor()) ); // macroscopic deformation gradient and strain // - zero-initialize T2 F = xt::zeros({2,2}); // - set non-zero components F(0,1) = 0.1; // nodal coordinates and displacement xt::xtensor coor = mesh.coor();; xt::xtensor disp = xt::zeros(coor.shape()); // apply macroscopic deformation gradient for ( size_t n = 0 ; n < mesh.nnode() ; ++n ) for ( size_t i = 0 ; i < F.shape()[0] ; ++i ) for ( size_t j = 0 ; j < F.shape()[1] ; ++j ) disp(n,i) += F(i,j) * coor(n,j); // compute quadrature point tensors xt::xtensor eps = quad.symGradN_vector(vec.asElement(disp)); // nodal force vector (should be zero, as it is only sensitive to periodic fluctuations) xt::xtensor Fi = vec.assembleDofs(quad.int_gradN_dot_tensor2_dV(eps)); // check // - size REQUIRE( Fi.size() == vec.ndof() ); // - check each component REQUIRE( xt::allclose(Fi, 0.) ); } // ================================================================================================= } diff --git a/test/Iterate.cpp b/test/Iterate.cpp index f72505a..06e2229 100644 --- a/test/Iterate.cpp +++ b/test/Iterate.cpp @@ -1,29 +1,29 @@ #include "support.h" // ================================================================================================= -TEST_CASE("xGooseFEM::Iterate", "Iterate.h") +TEST_CASE("GooseFEM::Iterate", "Iterate.h") { // ================================================================================================= SECTION( "StopList" ) { - xGooseFEM::Iterate::StopList stop(5); + GooseFEM::Iterate::StopList stop(5); REQUIRE( stop.stop(5.e+0, 1.e-3) == false ); REQUIRE( stop.stop(5.e+1, 1.e-3) == false ); REQUIRE( stop.stop(5.e-1, 1.e-3) == false ); REQUIRE( stop.stop(5.e-2, 1.e-3) == false ); REQUIRE( stop.stop(5.e-3, 1.e-3) == false ); REQUIRE( stop.stop(5.e-4, 1.e-3) == false ); REQUIRE( stop.stop(5.e-4, 1.e-3) == false ); REQUIRE( stop.stop(5.e-4, 1.e-3) == false ); REQUIRE( stop.stop(5.e-4, 1.e-3) == false ); REQUIRE( stop.stop(5.e-4, 1.e-3) == true ); } // ================================================================================================= } diff --git a/test/MatrixDiagonal.cpp b/test/MatrixDiagonal.cpp index d1b9245..34c4f1f 100644 --- a/test/MatrixDiagonal.cpp +++ b/test/MatrixDiagonal.cpp @@ -1,78 +1,78 @@ #include "support.h" // ================================================================================================= -TEST_CASE("xGooseFEM::MatrixDiagonal", "MatrixDiagonal.h") +TEST_CASE("GooseFEM::MatrixDiagonal", "MatrixDiagonal.h") { // ================================================================================================= SECTION( "dot" ) { // mesh - xGooseFEM::Mesh::Quad4::Regular mesh(2,2); + GooseFEM::Mesh::Quad4::Regular mesh(2,2); // random matrix and column xt::xtensor a = xt::random::rand({mesh.nnode()*mesh.ndim()}); xt::xtensor b = xt::random::rand({mesh.nnode()*mesh.ndim()}); xt::xtensor c; // compute product c = a * b; - // convert to xGooseFEM + // convert to GooseFEM // - allocate - xGooseFEM::MatrixDiagonal A(mesh.conn(), mesh.dofs()); + GooseFEM::MatrixDiagonal A(mesh.conn(), mesh.dofs()); xt::xtensor C; // - set A.set(a); // compute product C = A.dot(b); // check // - size REQUIRE( C.size() == c.size() ); // - components REQUIRE( xt::allclose(C, c) ); } // ------------------------------------------------------------------------------------------------- SECTION( "solve" ) { // mesh - xGooseFEM::Mesh::Quad4::Regular mesh(2,2); + GooseFEM::Mesh::Quad4::Regular mesh(2,2); // random matrix and column xt::xtensor a = xt::random::rand({mesh.nnode()*mesh.ndim()}); xt::xtensor b = xt::random::rand({mesh.nnode()*mesh.ndim()}); xt::xtensor c; // compute product c = a * b; - // convert to xGooseFEM + // convert to GooseFEM // - allocate - xGooseFEM::MatrixDiagonal A(mesh.conn(), mesh.dofs()); + GooseFEM::MatrixDiagonal A(mesh.conn(), mesh.dofs()); xt::xtensor B, C; // - set A.set(a); // compute product C = A.dot(b); // solve B = A.solve(C); // check // - size REQUIRE( B.size() == b.size() ); // - components REQUIRE( xt::allclose(B, b) ); } // // ================================================================================================= } diff --git a/test/Vector.cpp b/test/Vector.cpp index 035943f..82a1a1e 100644 --- a/test/Vector.cpp +++ b/test/Vector.cpp @@ -1,177 +1,177 @@ #include "support.h" // ================================================================================================= -TEST_CASE("xGooseFEM::Vector", "Vector.h") +TEST_CASE("GooseFEM::Vector", "Vector.h") { // ================================================================================================= SECTION( "asDofs - nodevec" ) { // mesh - xGooseFEM::Mesh::Quad4::Regular mesh(2,2); + GooseFEM::Mesh::Quad4::Regular mesh(2,2); // vector-definition - xGooseFEM::Vector vector(mesh.conn(), mesh.dofsPeriodic()); + GooseFEM::Vector vector(mesh.conn(), mesh.dofsPeriodic()); // velocity field // - allocate xt::xtensor v = xt::empty({mesh.nnode(), std::size_t(2)}); // - set periodic v(0,0) = 1.0; v(0,1) = 0.0; v(1,0) = 1.0; v(1,1) = 0.0; v(2,0) = 1.0; v(2,1) = 0.0; v(3,0) = 1.5; v(3,1) = 0.0; v(4,0) = 1.5; v(4,1) = 0.0; v(5,0) = 1.5; v(5,1) = 0.0; v(6,0) = 1.0; v(6,1) = 0.0; v(7,0) = 1.0; v(7,1) = 0.0; v(8,0) = 1.0; v(8,1) = 0.0; // convert to DOFs xt::xtensor V = vector.asDofs(v); // check // - size REQUIRE( V.size() == mesh.nnodePeriodic() * mesh.ndim() ); // - individual entries EQ( V(0), v(0,0) ); EQ( V(1), v(0,1) ); EQ( V(2), v(1,0) ); EQ( V(3), v(1,1) ); EQ( V(4), v(3,0) ); EQ( V(5), v(3,1) ); EQ( V(6), v(4,0) ); EQ( V(7), v(4,1) ); } // ------------------------------------------------------------------------------------------------- SECTION( "asDofs - elemvec" ) { // mesh - xGooseFEM::Mesh::Quad4::Regular mesh(2,2); + GooseFEM::Mesh::Quad4::Regular mesh(2,2); // vector-definition - xGooseFEM::Vector vector(mesh.conn(), mesh.dofsPeriodic()); + GooseFEM::Vector vector(mesh.conn(), mesh.dofsPeriodic()); // velocity field // - allocate xt::xtensor v = xt::empty({mesh.nnode(), std::size_t(2)}); // - set periodic v(0,0) = 1.0; v(0,1) = 0.0; v(1,0) = 1.0; v(1,1) = 0.0; v(2,0) = 1.0; v(2,1) = 0.0; v(3,0) = 1.5; v(3,1) = 0.0; v(4,0) = 1.5; v(4,1) = 0.0; v(5,0) = 1.5; v(5,1) = 0.0; v(6,0) = 1.0; v(6,1) = 0.0; v(7,0) = 1.0; v(7,1) = 0.0; v(8,0) = 1.0; v(8,1) = 0.0; // convert to DOFs - element - DOFs xt::xtensor V = vector.asDofs(vector.asElement(vector.asDofs(v))); // check // - size REQUIRE( V.size() == mesh.nnodePeriodic() * mesh.ndim() ); // - individual entries EQ( V(0), v(0,0) ); EQ( V(1), v(0,1) ); EQ( V(2), v(1,0) ); EQ( V(3), v(1,1) ); EQ( V(4), v(3,0) ); EQ( V(5), v(3,1) ); EQ( V(6), v(4,0) ); EQ( V(7), v(4,1) ); } // ------------------------------------------------------------------------------------------------- SECTION( "asDofs - assembleDofs" ) { // mesh - xGooseFEM::Mesh::Quad4::Regular mesh(2,2); + GooseFEM::Mesh::Quad4::Regular mesh(2,2); // vector-definition - xGooseFEM::Vector vector(mesh.conn(), mesh.dofsPeriodic()); + GooseFEM::Vector vector(mesh.conn(), mesh.dofsPeriodic()); // force field // - allocate xt::xtensor f = xt::empty({mesh.nnode(), std::size_t(2)}); // - set periodic f(0,0) = -1.0; f(0,1) = -1.0; f(1,0) = 0.0; f(1,1) = -1.0; f(2,0) = 1.0; f(2,1) = -1.0; f(3,0) = -1.0; f(3,1) = 0.0; f(4,0) = 0.0; f(4,1) = 0.0; f(5,0) = 1.0; f(5,1) = 0.0; f(6,0) = -1.0; f(6,1) = 1.0; f(7,0) = 0.0; f(7,1) = 1.0; f(8,0) = 1.0; f(8,1) = 1.0; // assemble as DOFs xt::xtensor F = vector.assembleDofs(f); // check // - size REQUIRE( F.size() == mesh.nnodePeriodic() * mesh.ndim() ); // - 'analytical' result EQ( F(0), 0 ); EQ( F(1), 0 ); EQ( F(2), 0 ); EQ( F(3), 0 ); EQ( F(4), 0 ); EQ( F(5), 0 ); EQ( F(6), 0 ); EQ( F(7), 0 ); } // ------------------------------------------------------------------------------------------------- SECTION( "asDofs - assembleNode" ) { // mesh - xGooseFEM::Mesh::Quad4::Regular mesh(2,2); + GooseFEM::Mesh::Quad4::Regular mesh(2,2); // vector-definition - xGooseFEM::Vector vector(mesh.conn(), mesh.dofsPeriodic()); + GooseFEM::Vector vector(mesh.conn(), mesh.dofsPeriodic()); // force field // - allocate xt::xtensor f = xt::empty({mesh.nnode(), std::size_t(2)}); // - set periodic f(0,0) = -1.0; f(0,1) = -1.0; f(1,0) = 0.0; f(1,1) = -1.0; f(2,0) = 1.0; f(2,1) = -1.0; f(3,0) = -1.0; f(3,1) = 0.0; f(4,0) = 0.0; f(4,1) = 0.0; f(5,0) = 1.0; f(5,1) = 0.0; f(6,0) = -1.0; f(6,1) = 1.0; f(7,0) = 0.0; f(7,1) = 1.0; f(8,0) = 1.0; f(8,1) = 1.0; // convert to element, assemble as DOFs xt::xtensor F = vector.assembleDofs( vector.asElement(f) ); // check // - size REQUIRE( F.size() == mesh.nnodePeriodic() * mesh.ndim() ); // - 'analytical' result EQ( F(0), 0 ); EQ( F(1), 0 ); EQ( F(2), 0 ); EQ( F(3), 0 ); EQ( F(4), 0 ); EQ( F(5), 0 ); EQ( F(6), 0 ); EQ( F(7), 0 ); } // ------------------------------------------------------------------------------------------------- // ================================================================================================= } diff --git a/test/support.h b/test/support.h index dbf7865..41a6535 100644 --- a/test/support.h +++ b/test/support.h @@ -1,14 +1,14 @@ #ifndef SUPPORT_H #define SUPPORT_H #include #include #include -#include "../include/xGooseFEM/GooseFEM.h" +#include "../include/GooseFEM/GooseFEM.h" #define EQ(a,b) REQUIRE_THAT( (a), Catch::WithinAbs((b), 1.e-12) ); #endif