diff --git a/CMakeLists.txt b/CMakeLists.txt index b2d2d88..a6686cc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,123 +1,102 @@ # # (c - GPLv3) T.W.J. de Geus (Tom) | tom@geus.me | www.geus.me | github.com/tdegeus/GooseFEM # cmake_minimum_required(VERSION 3.0) # Basic settings # ============== project(GooseFEM) option(BUILD_TESTS "Build tests" OFF) option(BUILD_EXAMPLES "Build examples" OFF) # Version # ======= -file(STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/include/GooseFEM/config.h" GooseFEM_version_defines - REGEX "#define GOOSEFEM_VERSION_(MAJOR|MINOR|PATCH)") - -foreach(ver ${GooseFEM_version_defines}) - if(ver MATCHES "#define GOOSEFEM_VERSION_(MAJOR|MINOR|PATCH) ([0-9]*)(.*)") - set(GOOSEFEM_VERSION_${CMAKE_MATCH_1} - "${CMAKE_MATCH_2}" - CACHE INTERNAL "") - endif() -endforeach() - -set(GOOSEFEM_VERSION ${GOOSEFEM_VERSION_MAJOR}.${GOOSEFEM_VERSION_MINOR}.${GOOSEFEM_VERSION_PATCH}) +IF(DEFINED ENV{PKG_VERSION}) + set(GOOSEFEM_VERSION $ENV{PKG_VERSION}) +else() + execute_process( + COMMAND python -c "from setuptools_scm import get_version; print(get_version())" + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + OUTPUT_VARIABLE GOOSEFEM_VERSION + OUTPUT_STRIP_TRAILING_WHITESPACE) +endif() -message(STATUS "Building GooseFEM v${GOOSEFEM_VERSION}") +message(STATUS "Building GooseFEM ${GOOSEFEM_VERSION}") # Set target # ========== find_package(xtensor REQUIRED) add_library(GooseFEM INTERFACE) target_include_directories(GooseFEM INTERFACE $ $) target_link_libraries(GooseFEM INTERFACE xtensor) # Installation # ============ include(CMakePackageConfigHelpers) include(GNUInstallDirs) install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/include/" DESTINATION include) +configure_file("include/${PROJECT_NAME}/version.h" + "${CMAKE_CURRENT_BINARY_DIR}/version.h" + @ONLY) + +install(FILES "${CMAKE_CURRENT_BINARY_DIR}/version.h" + DESTINATION "include/${PROJECT_NAME}/") + install(TARGETS GooseFEM EXPORT GooseFEM-targets) install( EXPORT GooseFEM-targets FILE GooseFEMTargets.cmake DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/GooseFEM") set(_GOOSEFEM ${CMAKE_SIZEOF_VOID_P}) unset(CMAKE_SIZEOF_VOID_P) write_basic_package_version_file("${CMAKE_CURRENT_BINARY_DIR}/GooseFEMConfigVersion.cmake" VERSION ${GOOSEFEM_VERSION} COMPATIBILITY AnyNewerVersion) set(CMAKE_SIZEOF_VOID_P ${_GOOSEFEM}) install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/GooseFEMConfig.cmake" "${CMAKE_CURRENT_BINARY_DIR}/GooseFEMConfigVersion.cmake" DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/GooseFEM") configure_file("${CMAKE_CURRENT_SOURCE_DIR}/GooseFEM.pc.in" "${CMAKE_CURRENT_BINARY_DIR}/GooseFEM.pc" @ONLY) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/GooseFEM.pc" DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig/") -# Adding git-hash to separate header -# ================================== - -# Get the current working branch -execute_process( - COMMAND git rev-parse --abbrev-ref HEAD - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} - OUTPUT_VARIABLE GIT_BRANCH - OUTPUT_STRIP_TRAILING_WHITESPACE) - -# Get the latest commit hash -execute_process( - COMMAND git rev-parse HEAD - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} - OUTPUT_VARIABLE GIT_COMMIT_HASH - OUTPUT_STRIP_TRAILING_WHITESPACE) - -# Write a "git.h" overwrite with the current branch/hash -file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/git.h" - "#define GOOSEFEM_GIT_HASH \"${GIT_COMMIT_HASH}\"\n" - "#define GOOSEFEM_GIT_BRANCH \"${GIT_BRANCH}\"\n") - -# Overwrite the installed "include/GooseFEM/git.h" dummy -install(FILES "${CMAKE_CURRENT_BINARY_DIR}/git.h" DESTINATION "include/GooseFEM/") - # Add builds # ========== include("GooseFEMConfig.cmake") include(CTest) if(BUILD_TESTS) enable_testing() add_subdirectory(test/basic) enable_testing() add_subdirectory(test/gmat) endif() if(BUILD_EXAMPLES) enable_testing() add_subdirectory(docs/examples) endif() diff --git a/docs/Doxyfile b/docs/Doxyfile index a9635ff..113cdca 100644 --- a/docs/Doxyfile +++ b/docs/Doxyfile @@ -1,25 +1,26 @@ PROJECT_NAME = "GooseFEM" XML_OUTPUT = xml INPUT = ../include doxy_landing.md GENERATE_LATEX = NO GENERATE_MAN = NO GENERATE_RTF = NO CASE_SENSE_NAMES = NO GENERATE_HTML = YES GENERATE_XML = YES RECURSIVE = YES QUIET = YES JAVADOC_AUTOBRIEF = YES WARN_IF_UNDOCUMENTED = NO MACRO_EXPANSION = YES PREDEFINED = IN_DOXYGEN EXCLUDE_SYMBOLS = detail GENERATE_TREEVIEW = YES SOURCE_BROWSER = YES +# WARN_IF_UNDOCUMENTED = YES # Allow for rst directives and advanced functions e.g. grid tables ALIASES = "rst=\verbatim embed:rst:leading-asterisk" ALIASES += "endrst=\endverbatim" # Add license command ALIASES += "license=@par License:" diff --git a/docs/examples/environment.yaml b/docs/examples/environment.yaml index 76580cd..1f3f2c3 100644 --- a/docs/examples/environment.yaml +++ b/docs/examples/environment.yaml @@ -1,35 +1,36 @@ channels: - conda-forge dependencies: # dependencies - xtensor - eigen # optional dependencies - xsimd # build tools - cmake + - setuptools_scm # Python API - python - numpy - pyxtensor # to run tests - catch2 - gmatelastic - gmatelastoplasticqpot # to run examples - h5py - highfive - xdmfwrite_highfive - xdmfwrite_h5py - gmatelastic - gmatnonlinearelastic - gmatelastoplastic - gmatelastoplasticfinitestrainsimo - gmatelastoplasticqpot - python-gmatelastic diff --git a/environment.yaml b/environment.yaml index b29e522..13b8592 100644 --- a/environment.yaml +++ b/environment.yaml @@ -1,22 +1,23 @@ channels: - conda-forge dependencies: # dependencies - xtensor - eigen # optional dependencies - xsimd # build tools - cmake + - setuptools_scm # Python API - python - numpy - pyxtensor # to run tests - catch2 - gmatelastic - gmatelastoplasticqpot diff --git a/include/GooseFEM/GooseFEM.h b/include/GooseFEM/GooseFEM.h index c623e28..9f035bd 100644 --- a/include/GooseFEM/GooseFEM.h +++ b/include/GooseFEM/GooseFEM.h @@ -1,39 +1,40 @@ /* (c - GPLv3) T.W.J. de Geus (Tom) | tom@geus.me | www.geus.me | github.com/tdegeus/GooseFEM */ #ifndef GOOSEFEM_H #define GOOSEFEM_H #ifdef EIGEN_WORLD_VERSION #define GOOSEFEM_EIGEN #endif +#include "version.h" + #include "Allocate.h" #include "Element.h" #include "ElementHex8.h" #include "ElementQuad4.h" #include "ElementQuad4Axisymmetric.h" #include "ElementQuad4Planar.h" #include "Iterate.h" #include "MatrixDiagonal.h" #include "MatrixDiagonalPartitioned.h" #include "Mesh.h" #include "MeshHex8.h" #include "MeshQuad4.h" #include "MeshTri3.h" #include "Vector.h" #include "VectorPartitioned.h" -#include "Version.h" #ifdef GOOSEFEM_EIGEN #include "Matrix.h" #include "MatrixPartitioned.h" #include "MatrixPartitionedTyings.h" #include "TyingsPeriodic.h" #include "VectorPartitionedTyings.h" #endif #endif diff --git a/include/GooseFEM/MeshQuad4.h b/include/GooseFEM/MeshQuad4.h index 3822777..d1512bd 100644 --- a/include/GooseFEM/MeshQuad4.h +++ b/include/GooseFEM/MeshQuad4.h @@ -1,382 +1,454 @@ /** Generate mesh with 4-noded quadrilateral elements. \file MeshQuad4.h \copyright Copyright 2017. Tom de Geus. All rights reserved. \license This project is released under the GNU Public License (GPLv3). */ #ifndef GOOSEFEM_MESHQUAD4_H #define GOOSEFEM_MESHQUAD4_H #include "config.h" namespace GooseFEM { namespace Mesh { namespace Quad4 { // pre-allocation namespace Map { class FineLayer2Regular; } /** Regular mesh: equi-sized elements. */ class Regular { public: Regular() = default; /** Constructor. \param nelx Number of elements in horizontal (x) direction. \param nely Number of elements in vertical (y) direction. \param h Edge size (width == height). */ Regular(size_t nelx, size_t nely, double h = 1.0); /** Number of elements. \return unsigned int. */ size_t nelem() const; /** Number of nodes. \return unsigned int. */ size_t nnode() const; /** Number of nodes-per-element. \return unsigned int. */ size_t nne() const; /** Number of dimensions. \return unsigned int. */ size_t ndim() const; /** - Number of elements in x-direction. + Number of elements in x-direction == width of the mesh in units of h(). \return unsigned int. */ size_t nelx() const; /** - Number of elements in y-direction. + Number of elements in y-direction == height of the mesh, in units of h(), \return unsigned int. */ size_t nely() const; /** - Edge size. + Edge size of one element. \return double. */ double h() const; /** - Get the element type. + Element type. \return GooseFEM::Mesh::ElementType(). */ ElementType getElementType() const; - // mesh - xt::xtensor coor() const; // nodal positions [nnode, ndim] - xt::xtensor conn() const; // connectivity [nelem, nne] + /** + Nodal coordinates. + + \return ``[nnode, ndim]``. + */ + xt::xtensor coor() const; + + /** + Connectivity. + + \return ``[nelem, nne]``. + */ + xt::xtensor conn() const; // boundary nodes: edges xt::xtensor nodesBottomEdge() const; xt::xtensor nodesTopEdge() const; xt::xtensor nodesLeftEdge() const; xt::xtensor nodesRightEdge() const; // boundary nodes: edges, without corners xt::xtensor nodesBottomOpenEdge() const; xt::xtensor nodesTopOpenEdge() const; xt::xtensor nodesLeftOpenEdge() const; xt::xtensor nodesRightOpenEdge() const; // boundary nodes: corners (including aliases) size_t nodesBottomLeftCorner() const; size_t nodesBottomRightCorner() const; size_t nodesTopLeftCorner() const; size_t nodesTopRightCorner() const; size_t nodesLeftBottomCorner() const; size_t nodesLeftTopCorner() const; size_t nodesRightBottomCorner() const; size_t nodesRightTopCorner() const; // DOF-numbers for each component of each node (sequential) xt::xtensor dofs() const; // DOF-numbers for the case that the periodicity if fully eliminated xt::xtensor dofsPeriodic() const; // periodic node pairs [:,2]: (independent, dependent) xt::xtensor nodesPeriodic() const; // front-bottom-left node, used as reference for periodicity size_t nodesOrigin() const; // element numbers as matrix xt::xtensor elementgrid() const; private: double m_h; // elementary element edge-size (in all directions) size_t m_nelx; // number of elements in x-direction (length == "m_nelx * m_h") size_t m_nely; // number of elements in y-direction (length == "m_nely * m_h") size_t m_nelem; // number of elements size_t m_nnode; // number of nodes static const size_t m_nne = 4; // number of nodes-per-element static const size_t m_ndim = 2; // number of dimensions }; // Mesh with fine middle layer, and coarser elements towards the top and bottom class FineLayer { public: + FineLayer() = default; + FineLayer(size_t nelx, size_t nely, double h = 1.0, size_t nfine = 1); - // Reconstruct class for given coordinates / connectivity + /** + Reconstruct class for given coordinates / connectivity. + + \param coor Nodal coordinates ``[nnode, ndim]`` with ``ndim == 2``. + \param conn Connectivity ``[nne, nne]`` with ``nne == 4``. + \throw GOOSEFEM_CHECK() + */ FineLayer(const xt::xtensor& coor, const xt::xtensor& conn); - // size - size_t nelem() const; // number of elements - size_t nnode() const; // number of nodes - size_t nne() const; // number of nodes-per-element - size_t ndim() const; // number of dimensions - size_t nelx() const; // number of elements in x-direction - size_t nely() const; // number of elements in y-direction - double h() const; // edge size + /** + Number of elements. + + \return unsigned int. + */ + size_t nelem() const; + + /** + Number of nodes. + + \return unsigned int. + */ + size_t nnode() const; + + /** + Number of nodes-per-element. + + \return unsigned int. + */ + size_t nne() const; + + /** + Number of dimensions. + + \return unsigned int. + */ + size_t ndim() const; + + /** + Number of elements in x-direction along the middle layer == width of the mesh in units of h(). + + \return unsigned int. + */ + size_t nelx() const; + + /** + Height of the mesh, in units of h() + + \return unsigned int. + */ + size_t nely() const; + + /** + Edge size of the smallest elements (along the middle layer). + + \return double. + */ + double h() const; // edge size, per row of elements (in units of "h") xt::xtensor elemrow_nhx() const; xt::xtensor elemrow_nhy() const; xt::xtensor elemrow_nelem() const; - // type + /** + Element type. + + \return GooseFEM::Mesh::ElementType(). + */ ElementType getElementType() const; - // mesh - xt::xtensor coor() const; // nodal positions [nnode, ndim] - xt::xtensor conn() const; // connectivity [nelem, nne] + /** + Nodal coordinates. + + \return ``[nnode, ndim]``. + */ + xt::xtensor coor() const; + + /** + Connectivity. + + \return ``[nelem, nne]``. + */ + xt::xtensor conn() const; // elements in the middle (fine) layer xt::xtensor elementsMiddleLayer() const; // extract elements along a layer xt::xtensor elementsLayer(size_t layer) const; // select region of elements from 'matrix' of element numbers xt::xtensor elementgrid_ravel( std::vector rows_start_stop, std::vector cols_start_stop) const; /** Select region of elements from 'matrix' of element numbers around an element: square box with edge-size ``(2 * size + 1) * h``, around ``element``. \param element The element around which to select elements. \param size Edge size of the square box encapsulating the selected element. \param periodic Assume the mesh periodic. \returns List of elements. */ xt::xtensor elementgrid_around_ravel( size_t element, size_t size, bool periodic = true); /** Select region of elements from 'matrix' of element numbers around an element: left/right from ``element`` (on the same layer). \param element The element around which to select elements. \param left Number of elements to select to the left. \param right Number of elements to select to the right. \param periodic Assume the mesh periodic. \returns List of elements. */ // - xt::xtensor elementgrid_leftright( size_t element, size_t left, size_t right, bool periodic = true); // boundary nodes: edges xt::xtensor nodesBottomEdge() const; xt::xtensor nodesTopEdge() const; xt::xtensor nodesLeftEdge() const; xt::xtensor nodesRightEdge() const; // boundary nodes: edges, without corners xt::xtensor nodesBottomOpenEdge() const; xt::xtensor nodesTopOpenEdge() const; xt::xtensor nodesLeftOpenEdge() const; xt::xtensor nodesRightOpenEdge() const; // boundary nodes: corners (including aliases) size_t nodesBottomLeftCorner() const; size_t nodesBottomRightCorner() const; size_t nodesTopLeftCorner() const; size_t nodesTopRightCorner() const; size_t nodesLeftBottomCorner() const; size_t nodesLeftTopCorner() const; size_t nodesRightBottomCorner() const; size_t nodesRightTopCorner() const; // DOF-numbers for each component of each node (sequential) xt::xtensor dofs() const; // DOF-numbers for the case that the periodicity if fully eliminated xt::xtensor dofsPeriodic() const; // periodic node pairs [:,2]: (independent, dependent) xt::xtensor nodesPeriodic() const; // front-bottom-left node, used as reference for periodicity size_t nodesOrigin() const; // mapping to 'roll' periodically in the x-direction, // returns element mapping, such that: new_elemvar = elemvar[elem_map] xt::xtensor roll(size_t n); private: double m_h; // elementary element edge-size (in all directions) double m_Lx; // mesh size in "x" size_t m_nelem; // number of elements size_t m_nnode; // number of nodes static const size_t m_nne = 4; // number of nodes-per-element static const size_t m_ndim = 2; // number of dimensions xt::xtensor m_nelx; // number of elements in "x" (*) xt::xtensor m_nnd; // total number of nodes in the main node layer (**) xt::xtensor m_nhx; // element size in x-direction (*) xt::xtensor m_nhy; // element size in y-direction (*) xt::xtensor m_refine; // refine direction (-1:no refine, 0:"x" (*) xt::xtensor m_startElem; // start element (*) xt::xtensor m_startNode; // start node (**) // (*) per element layer in "y" // (**) per node layer in "y" void init(size_t nelx, size_t nely, double h, size_t nfine = 1); void map(const xt::xtensor& coor, const xt::xtensor& conn); friend class GooseFEM::Mesh::Quad4::Map::FineLayer2Regular; }; // Mesh mappings namespace Map { // Return "FineLayer"-class responsible for generating a connectivity // Throws if conversion is not possible GooseFEM::Mesh::Quad4::FineLayer FineLayer( const xt::xtensor& coor, const xt::xtensor& conn); // Refine a regular mesh: sub-divide elements in several smaller elements class RefineRegular { public: // Constructors RefineRegular() = default; RefineRegular(const GooseFEM::Mesh::Quad4::Regular& mesh, size_t nx, size_t ny); // return the coarse or the fine mesh objects GooseFEM::Mesh::Quad4::Regular getCoarseMesh() const; GooseFEM::Mesh::Quad4::Regular getFineMesh() const; // elements of the fine mesh per element of the coarse mesh xt::xtensor getMap() const; // map field xt::xtensor mapToCoarse(const xt::xtensor& data) const; // scalar per el xt::xtensor mapToCoarse(const xt::xtensor& data) const; // scalar per intpnt xt::xtensor mapToCoarse(const xt::xtensor& data) const; // tensor per intpnt // map field xt::xtensor mapToFine(const xt::xtensor& data) const; // scalar per el xt::xtensor mapToFine(const xt::xtensor& data) const; // scalar per intpnt xt::xtensor mapToFine(const xt::xtensor& data) const; // tensor per intpnt private: // the meshes GooseFEM::Mesh::Quad4::Regular m_coarse; GooseFEM::Mesh::Quad4::Regular m_fine; // mapping xt::xtensor m_fine2coarse; xt::xtensor m_fine2coarse_index; xt::xtensor m_coarse2fine; }; class FineLayer2Regular { public: // constructor FineLayer2Regular() = default; FineLayer2Regular(const GooseFEM::Mesh::Quad4::FineLayer& mesh); // return either of the meshes GooseFEM::Mesh::Quad4::Regular getRegularMesh() const; GooseFEM::Mesh::Quad4::FineLayer getFineLayerMesh() const; // elements of the Regular mesh per element of the FineLayer mesh // and the fraction by which the overlap is std::vector> getMap() const; std::vector> getMapFraction() const; /** Map element quantities to Regular. The mapping is a bit simplistic: no interpolation is involved, the function just accounts the fraction of overlap between the FineLayer element and the Regular element. The mapping is such that:: ret[e, :, :] <- arg[e, :, :] (for arbitrary rank). \tparam T The type of the data (e.g. ``double``). \tparam rank Rank of the data. \param arg The data. \return The mapped data. */ template xt::xtensor mapToRegular(const xt::xtensor& arg) const; private: // the "FineLayer" mesh to map GooseFEM::Mesh::Quad4::FineLayer m_finelayer; // the new "Regular" mesh to which to map GooseFEM::Mesh::Quad4::Regular m_regular; // mapping std::vector> m_elem_regular; std::vector> m_frac_regular; }; } // namespace Map } // namespace Quad4 } // namespace Mesh } // namespace GooseFEM #include "MeshQuad4.hpp" #endif diff --git a/include/GooseFEM/Version.h b/include/GooseFEM/Version.h deleted file mode 100644 index 8503909..0000000 --- a/include/GooseFEM/Version.h +++ /dev/null @@ -1,43 +0,0 @@ -/** -Version information. - -\file Version.h -\copyright Copyright 2017. Tom de Geus. All rights reserved. -\license This project is released under the GNU Public License (GPLv3). -*/ - -#ifndef GOOSEFEM_VERSION_H -#define GOOSEFEM_VERSION_H - -#include "config.h" - -namespace GooseFEM { - -/** -Return git branch and hash (at the time of configuring). -See GOOSEFEM_GIT_HASH() and GOOSEFEM_GIT_BRANCH(). - -\return ``{branch, hash}`` -*/ -inline std::vector git(); - -/** -Return version as string. -See GOOSEFEM_VERSION_MAJOR(), GOOSEFEM_VERSION_MINOR(), and GOOSEFEM_VERSION_PATCH() - -\return Version string, e.g. ``v0.5.2``. -*/ -inline std::string version(); - -/** -Return versions of this library and of all of its dependencies. - -\return List of strings with version information. -*/ -inline std::vector version_dependencies(); - -} // namespace GooseFEM - -#include "Version.hpp" - -#endif diff --git a/include/GooseFEM/config.h b/include/GooseFEM/config.h index 499bc91..52978dc 100644 --- a/include/GooseFEM/config.h +++ b/include/GooseFEM/config.h @@ -1,113 +1,102 @@ /** Basic configuration: - Include general dependencies. - Define assertions. - Define version. - Define git commit hash/branch. \file config.h \copyright Copyright 2017. Tom de Geus. All rights reserved. \license This project is released under the GNU Public License (GPLv3). */ #ifndef GOOSEFEM_CONFIG_H #define GOOSEFEM_CONFIG_H #define _USE_MATH_DEFINES // to use "M_PI" from "math.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace xt::placeholders; #define UNUSED(p) ((void)(p)) /** All assertions are implementation as:: GOOSEFEM_ASSERT(...) They can be enabled by:: #define GOOSEFEM_ENABLE_ASSERT (before including GooseFEM). The advantage is that: - File and line-number are displayed if the assertion fails. - GooseFEM's assertions can be enabled/disabled independently from those of other libraries. + +\throw std::runtime_error */ #ifdef GOOSEFEM_ENABLE_ASSERT #define GOOSEFEM_ASSERT(expr) GOOSEFEM_ASSERT_IMPL(expr, __FILE__, __LINE__) #define GOOSEFEM_ASSERT_IMPL(expr, file, line) \ if (!(expr)) { \ throw std::runtime_error( \ std::string(file) + ':' + std::to_string(line) + \ ": assertion failed (" #expr ") \n\t"); \ } #else #define GOOSEFEM_ASSERT(expr) #endif +/** +Assertion that cannot be switched of. Implement assertion by:: + + GOOSEFEM_CHECK(...) + +\throw std::runtime_error +*/ #define GOOSEFEM_CHECK(expr) GOOSEFEM_CHECK_IMPL(expr, __FILE__, __LINE__) #define GOOSEFEM_CHECK_IMPL(expr, file, line) \ if (!(expr)) { \ throw std::runtime_error( \ std::string(file) + ':' + std::to_string(line) + \ ": assertion failed (" #expr ") \n\t"); \ } #define GOOSEFEM_WIP_ASSERT(expr) GOOSEFEM_CHECK_IMPL(expr, __FILE__, __LINE__) #define GOOSEFEM_WIP_ASSERT_IMPL(expr, file, line) \ if (!(expr)) { \ throw std::runtime_error( \ std::string(file) + ':' + std::to_string(line) + \ ": WIP, please extend the code, assertion failed (" #expr ") \n\t"); \ } -#define GOOSEFEM_VERSION_MAJOR 0 ///< Define major version -#define GOOSEFEM_VERSION_MINOR 8 ///< Define minor version -#define GOOSEFEM_VERSION_PATCH 1 ///< Define patch version (no API changes) - -#define GOOSEFEM_VERSION_AT_LEAST(x, y, z) \ - (GOOSEFEM_VERSION_MAJOR > x || (GOOSEFEM_VERSION_MAJOR >= x && \ - (GOOSEFEM_VERSION_MINOR > y || (GOOSEFEM_VERSION_MINOR >= y && \ - GOOSEFEM_VERSION_PATCH >= z)))) - -#define GOOSEFEM_VERSION(x, y, z) \ - (GOOSEFEM_VERSION_MAJOR == x && \ - GOOSEFEM_VERSION_MINOR == y && \ - GOOSEFEM_VERSION_PATCH == z) - -#endif - -#ifndef GOOSEFEM_GIT_HASH - - #include "git.h" - #endif diff --git a/include/GooseFEM/git.h b/include/GooseFEM/git.h deleted file mode 100644 index 9fe3872..0000000 --- a/include/GooseFEM/git.h +++ /dev/null @@ -1,30 +0,0 @@ -/** -\file git.h -\brief Git information at install time. -*/ - -/** -Git commit hash. - -Note that the actual value is filled by -- CMake: at install time. - ``CMakeLists.txt`` overwrite this file. -- Python: at build time. - ``setup.py`` defines this variable, this files is then never included on config.h. - -If you install from conda the variables are filled at the server. -*/ -#define GOOSEFEM_GIT_HASH "None" - -/** -Git commit branch. - -Note that the actual value is filled by -- CMake: at install time. - ``CMakeLists.txt`` overwrite this file. -- Python: at build time. - ``setup.py`` defines this variable, this files is then never included on config.h. - -If you install from conda the variables are filled at the server. -*/ -#define GOOSEFEM_GIT_BRANCH "None" diff --git a/include/GooseFEM/version.h b/include/GooseFEM/version.h new file mode 100644 index 0000000..374f3b8 --- /dev/null +++ b/include/GooseFEM/version.h @@ -0,0 +1,62 @@ +/** +Version information. + +\file version.h +\copyright Copyright 2017. Tom de Geus. All rights reserved. +\license This project is released under the GNU Public License (GPLv3). +*/ + +#ifndef GOOSEFEM_VERSION_H +#define GOOSEFEM_VERSION_H + +#include "config.h" + +/** +Current version. + +Either: + +- Configure using CMake at install time. Internally uses:: + + python -c "from setuptools_scm import get_version; print(get_version())" + +- Define externally using:: + + -DGOOSEFEM_VERSION="`python -c "from setuptools_scm import get_version; print(get_version())"`" + + From the root of this project. This is what ``setup.py`` does. + +Note that both ``CMakeLists.txt`` and ``setup.py`` will construct the version string using +*setuptools_scm* **unless** an environment ``PKG_VERSION`` is defined. +If ``PKG_VERSION`` is defined the version string will be read from that variable. +*/ +#ifndef GOOSEFEM_VERSION +#define GOOSEFEM_VERSION "@GOOSEFEM_VERSION@" +#endif + +namespace GooseFEM { + +/** +Return version string, e.g. "0.8.0" + +\return std::string +*/ +inline std::string version(); + +/** +Return versions of this library and of all of its dependencies. +The output is a list of strings, e.g.:: + + "goosefem=0.7.0", + "xtensor=0.20.1" + ... + +\return List of strings. +*/ +inline std::vector version_dependencies(); + +} // namespace GooseFEM + +#include "version.hpp" + +#endif diff --git a/include/GooseFEM/Version.hpp b/include/GooseFEM/version.hpp similarity index 59% rename from include/GooseFEM/Version.hpp rename to include/GooseFEM/version.hpp index 3a86f9c..f130ac5 100644 --- a/include/GooseFEM/Version.hpp +++ b/include/GooseFEM/version.hpp @@ -1,56 +1,44 @@ /** -\file Version.hpp +\file version.hpp \copyright Copyright 2017. Tom de Geus. All rights reserved. \license This project is released under the GNU Public License (GPLv3). */ #ifndef GOOSEFEM_VERSION_HPP #define GOOSEFEM_VERSION_HPP -#include "Version.h" +#include "version.h" namespace GooseFEM { -inline std::vector git() -{ - return std::vector{std::string(GOOSEFEM_GIT_BRANCH), - std::string(GOOSEFEM_GIT_HASH)}; -} - inline std::string version() { - return std::to_string(GOOSEFEM_VERSION_MAJOR) + "." + - std::to_string(GOOSEFEM_VERSION_MINOR) + "." + - std::to_string(GOOSEFEM_VERSION_PATCH); + return std::string(GOOSEFEM_VERSION); } inline std::vector version_dependencies() { std::vector ret; - ret.push_back("goosefem=" + - std::to_string(GOOSEFEM_VERSION_MAJOR) + "." + - std::to_string(GOOSEFEM_VERSION_MINOR) + "." + - std::to_string(GOOSEFEM_VERSION_PATCH)); + ret.push_back("goosefem=" + version()); ret.push_back("xtensor=" + std::to_string(XTENSOR_VERSION_MAJOR) + "." + std::to_string(XTENSOR_VERSION_MINOR) + "." + std::to_string(XTENSOR_VERSION_PATCH)); #if defined(GOOSEFEM_EIGEN) || defined(EIGEN_WORLD_VERSION) ret.push_back("eigen=" + std::to_string(EIGEN_WORLD_VERSION) + "." + std::to_string(EIGEN_MAJOR_VERSION) + "." + std::to_string(EIGEN_MINOR_VERSION)); #endif return ret; } - } // namespace GooseFEM #endif diff --git a/python/Version.hpp b/python/Version.hpp index e5efec6..8f87871 100644 --- a/python/Version.hpp +++ b/python/Version.hpp @@ -1,33 +1,28 @@ /* ================================================================================================= (c - GPLv3) T.W.J. de Geus (Tom) | tom@geus.me | www.geus.me | github.com/tdegeus/GooseFEM ================================================================================================= */ #include #include #include #include #include namespace py = pybind11; -void init_Version(py::module& m) +void init_version(py::module& m) { - m.def("version_dependencies", - &GooseFEM::version_dependencies, - "Return version information of library and its dependencies." - "See :cpp:class:`GooseFEM::version_dependencies`."); - - m.def("git", - &GooseFEM::git, - "Return git branch and hash at the time of building this library." - "See :cpp:class:`GooseFEM::git`."); - m.def("version", &GooseFEM::version, "Return version string." "See :cpp:class:`GooseFEM::version`."); + m.def("version_dependencies", + &GooseFEM::version_dependencies, + "Return version information of library and its dependencies." + "See :cpp:class:`GooseFEM::version_dependencies`."); + } diff --git a/python/main.cpp b/python/main.cpp index 0936834..bb84f51 100644 --- a/python/main.cpp +++ b/python/main.cpp @@ -1,127 +1,127 @@ /* ================================================================================================= (c - GPLv3) T.W.J. de Geus (Tom) | tom@geus.me | www.geus.me | github.com/tdegeus/GooseFEM ================================================================================================= */ #include #include #include #include #define GOOSEFEM_ENABLE_ASSERT #include namespace py = pybind11; +#include "version.hpp" #include "Vector.hpp" #include "VectorPartitioned.hpp" #include "VectorPartitionedTyings.hpp" #include "Matrix.hpp" #include "MatrixPartitioned.hpp" #include "MatrixPartitionedTyings.hpp" #include "MatrixDiagonal.hpp" #include "MatrixDiagonalPartitioned.hpp" #include "Element.hpp" #include "ElementQuad4.hpp" #include "ElementQuad4Planar.hpp" #include "ElementQuad4Axisymmetric.hpp" #include "ElementHex8.hpp" #include "Mesh.hpp" #include "MeshTri3.hpp" #include "MeshQuad4.hpp" #include "MeshHex8.hpp" -#include "Version.hpp" PYBIND11_MODULE(GooseFEM, m) { // -------- // GooseFEM // -------- m.doc() = "Some simple finite element meshes and operations"; +init_version(m); init_Vector(m); init_VectorPartitioned(m); init_VectorPartitionedTyings(m); init_Matrix(m); init_MatrixPartitioned(m); init_MatrixPartitionedTyings(m); init_MatrixDiagonal(m); init_MatrixDiagonalPartitioned(m); -init_Version(m); // ---------------- // GooseFEM.Element // ---------------- py::module mElement = m.def_submodule("Element", "Generic element routines"); init_Element(mElement); // ---------------------- // GooseFEM.Element.Quad4 // ---------------------- py::module mElementQuad4 = mElement.def_submodule("Quad4", "Linear quadrilateral elements (2D)"); py::module mElementQuad4Gauss = mElementQuad4.def_submodule("Gauss", "Gauss quadrature"); py::module mElementQuad4Nodal = mElementQuad4.def_submodule("Nodal", "Nodal quadrature"); init_ElementQuad4(mElementQuad4); init_ElementQuad4Planar(mElementQuad4); init_ElementQuad4Axisymmetric(mElementQuad4); init_ElementQuad4Gauss(mElementQuad4Gauss); init_ElementQuad4Nodal(mElementQuad4Nodal); // --------------------- // GooseFEM.Element.Hex8 // --------------------- py::module mElementHex8 = mElement.def_submodule("Hex8", "Linear hexahedron (brick) elements (3D)"); py::module mElementHex8Gauss = mElementHex8.def_submodule("Gauss", "Gauss quadrature"); py::module mElementHex8Nodal = mElementHex8.def_submodule("Nodal", "Nodal quadrature"); init_ElementHex8(mElementHex8); init_ElementHex8Gauss(mElementHex8Gauss); init_ElementHex8Nodal(mElementHex8Nodal); // ------------- // GooseFEM.Mesh // ------------- py::module mMesh = m.def_submodule("Mesh", "Generic mesh routines"); init_Mesh(mMesh); // ------------------ // GooseFEM.Mesh.Tri3 // ------------------ py::module mMeshTri3 = mMesh.def_submodule("Tri3", "Linear triangular elements (2D)"); init_MeshTri3(mMeshTri3); // ------------------- // GooseFEM.Mesh.Quad4 // ------------------- py::module mMeshQuad4 = mMesh.def_submodule("Quad4", "Linear quadrilateral elements (2D)"); init_MeshQuad4(mMeshQuad4); py::module mMeshQuad4Map = mMeshQuad4.def_submodule("Map", "Map mesh objects"); init_MeshQuad4Map(mMeshQuad4Map); // ------------------ // GooseFEM.Mesh.Hex8 // ------------------ py::module mMeshHex8 = mMesh.def_submodule("Hex8", "Linear hexahedron (brick) elements (3D)"); init_MeshHex8(mMeshHex8); } diff --git a/setup.py b/setup.py index e4ace6d..c906452 100644 --- a/setup.py +++ b/setup.py @@ -1,64 +1,55 @@ from setuptools import setup, Extension import re import os import pybind11 import pyxtensor -import subprocess +from os import environ -header = open('include/GooseFEM/config.h','r').read() -major = re.split(r'(.*)(\#define GOOSEFEM_VERSION_MAJOR\ )([0-9]+)(.*)', header)[3] -minor = re.split(r'(.*)(\#define GOOSEFEM_VERSION_MINOR\ )([0-9]+)(.*)', header)[3] -patch = re.split(r'(.*)(\#define GOOSEFEM_VERSION_PATCH\ )([0-9]+)(.*)', header)[3] +version = environ.get('PKG_VERSION') -__version__ = '.'.join([major, minor, patch]) +if version is None: + from setuptools_scm import get_version + version = get_version() include_dirs = [ os.path.abspath('include/'), pyxtensor.find_pyxtensor(), pyxtensor.find_pybind11(), pyxtensor.find_xtensor(), pyxtensor.find_xtl(), pyxtensor.find_eigen()] build = pyxtensor.BuildExt xsimd = pyxtensor.find_xsimd() if xsimd: if len(xsimd) > 0: include_dirs += [xsimd] build.c_opts['unix'] += ['-march=native', '-DXTENSOR_USE_XSIMD'] build.c_opts['msvc'] += ['/DXTENSOR_USE_XSIMD'] -git_hash = subprocess.check_output(["git", "rev-parse", "HEAD"]).strip().decode('UTF-8') -git_branch = subprocess.check_output(["git", "rev-parse", "--abbrev-ref", "HEAD"]).strip().decode('UTF-8') - -build.c_opts['unix'] += [ - '-DGOOSEFEM_GIT_HASH="{0:s}"'.format(git_hash), - '-DGOOSEFEM_GIT_BRANCH="{0:s}"'.format(git_branch)] - -build.c_opts['msvc'] += [ - '/DGOOSEFEM_GIT_HASH="{0:s}"'.format(git_hash), - '/DGOOSEFEM_GIT_BRANCH="{0:s}"'.format(git_branch)] +build.c_opts['unix'] += ['-DGOOSEFEM_VERSION="{0:s}"'.format(version)] +build.c_opts['msvc'] += ['/DGOOSEFEM_VERSION="{0:s}"'.format(version)] ext_modules = [Extension( 'GooseFEM', ['python/main.cpp'], include_dirs = include_dirs, language = 'c++')] setup( name = 'GooseFEM', description = 'Finite element meshes, quadrature, and assembly tools', long_description = 'Finite element meshes, quadrature, and assembly tools', - version = __version__, + 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', 'pyxtensor'], cmdclass = {'build_ext': build}, zip_safe = False) diff --git a/test/basic/CMakeLists.txt b/test/basic/CMakeLists.txt index ac7935d..2695ad5 100644 --- a/test/basic/CMakeLists.txt +++ b/test/basic/CMakeLists.txt @@ -1,52 +1,52 @@ cmake_minimum_required(VERSION 3.0) if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) project(GooseFEM-test-basic) find_package(GooseFEM REQUIRED CONFIG) endif() set(ASSERT ON) set(DEBUG ON) option(XSIMD "Use xsimd optimisations" ON) set(test_name "test-basic") find_package(Catch2 REQUIRED) find_package(xtensor REQUIRED) add_executable(${test_name} main.cpp Allocate.cpp Element.cpp ElementHex8.cpp ElementQuad4.cpp Iterate.cpp Matrix.cpp MatrixDiagonal.cpp Mesh.cpp MeshQuad4.cpp Vector.cpp VectorPartitioned.cpp - Version.cpp) + version.cpp) target_link_libraries(${test_name} PRIVATE Catch2::Catch2 GooseFEM GooseFEM::compiler_warnings xtensor::optimize) if(ASSERT) target_link_libraries(${test_name} PRIVATE GooseFEM::assert) endif() if(DEBUG) target_link_libraries(${test_name} PRIVATE GooseFEM::debug) endif() if(SIMD) find_package(xsimd REQUIRED) target_link_libraries(${test_name} PRIVATE xtensor::use_xsimd) endif() add_test(NAME ${test_name} COMMAND ${test_name}) diff --git a/test/basic/Version.cpp b/test/basic/version.cpp similarity index 70% rename from test/basic/Version.cpp rename to test/basic/version.cpp index 4010295..4512b8c 100644 --- a/test/basic/Version.cpp +++ b/test/basic/version.cpp @@ -1,15 +1,14 @@ #include #include -TEST_CASE("GooseFEM::Version", "Version.h") +TEST_CASE("GooseFEM::version", "version.h") { SECTION("basic") { - auto g = GooseFEM::git(); auto v = GooseFEM::version(); auto d = GooseFEM::version_dependencies(); } }