diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f1d7553..298a15c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,119 +1,124 @@ name: CI on: workflow_dispatch: pull_request: push: branches: - master jobs: standard: strategy: fail-fast: false matrix: runs-on: [ubuntu-latest, macos-latest, windows-latest] include: - runs-on: ubuntu-latest config: -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTS=1 -DBUILD_EXAMPLES=1 conda: docs/examples/environment.yaml prop: tests & examples - runs-on: macos-latest config: -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTS=1 -DBUILD_DOCS=1 conda: environment.yaml prop: tests - runs-on: windows-latest config: -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTS=1 -G Ninja -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ conda: environment.yaml prop: tests defaults: run: shell: bash -l {0} name: ${{ matrix.runs-on }} • x64 ${{ matrix.args }} runs-on: ${{ matrix.runs-on }} steps: - name: Basic GitHub action setup uses: actions/checkout@v2 - name: Set conda environment uses: mamba-org/provision-with-micromamba@main with: environment-file: ${{ matrix.conda }} environment-name: myenv - name: Install clang if: runner.os == 'Windows' run: micromamba install -c conda-forge clang_win-64 ninja - name: Set dummy version run: echo "SETUPTOOLS_SCM_PRETEND_VERSION=0.0" >> $GITHUB_ENV - name: Configure using CMake run: cmake -Bbuild ${{ matrix.config }} - name: Build C++ ${{ matrix.prop }} working-directory: build run: cmake --build . - name: Run C++ ${{ matrix.prop }} working-directory: build run: ctest --output-on-failure - name: Build and install Python module run: python setup.py install --build-type Release -vv - name: Run Python tests working-directory: tests/basic-python run: | python version.py python MeshQuad4.py - name: Build doxygen-docs (error on warning) if: runner.os == 'macOS' working-directory: build - run: make docs + run: make html + + - name: Build sphinx-docs + if: runner.os == 'macOS' + working-directory: docs + run: make html py: strategy: fail-fast: false matrix: runs-on: [windows-latest] include: - runs-on: windows-latest conda: .ci_environment_py.yaml defaults: run: shell: bash -l {0} name: ${{ matrix.runs-on }} • x64 ${{ matrix.args }} • py runs-on: ${{ matrix.runs-on }} steps: - name: Basic GitHub action setup uses: actions/checkout@v2 - name: Set conda environment uses: mamba-org/provision-with-micromamba@main with: environment-file: ${{ matrix.conda }} environment-name: myenv - name: Build and install Python module run: python -m pip install . -vvv - name: Run Python tests working-directory: tests/basic-python run: | python version.py python MeshQuad4.py diff --git a/.github/workflows/gh-pages.yml b/.github/workflows/gh-pages.yml index 30bc5c1..a03befd 100644 --- a/.github/workflows/gh-pages.yml +++ b/.github/workflows/gh-pages.yml @@ -1,51 +1,51 @@ name: gh-pages on: push: branches: - master release: types: [released] jobs: publish: runs-on: ubuntu-latest defaults: run: shell: bash -l {0} steps: - name: Basic GitHub action setup uses: actions/checkout@v2 with: fetch-depth: 0 - name: Set conda environment (using micromamba for speed) uses: mamba-org/provision-with-micromamba@main with: environment-file: .ci_environment_docs.yaml environment-name: myenv - name: Configure using CMake run: cmake -Bbuild -DBUILD_DOCS=1 - name: Build the docs working-directory: build - run: make docs + run: make html - name: Deploy to GitHub Pages if: success() uses: crazy-max/ghaction-github-pages@v2 with: target_branch: gh-pages build_dir: build/html jekyll: false keep_history: false env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.readthedocsenv.yml b/.readthedocsenv.yml index 5d7e2b9..08d4c34 100644 --- a/.readthedocsenv.yml +++ b/.readthedocsenv.yml @@ -1,12 +1,11 @@ channels: - conda-forge dependencies: - breathe - cmake - doxygen - eigen - python-goosefem -- pyxtensor - setuptools_scm - sphinx - sphinx_rtd_theme diff --git a/CMakeLists.txt b/CMakeLists.txt index 4b8aa20..f2761fc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,227 +1,227 @@ cmake_minimum_required(VERSION 3.18..3.21) project(GooseFEM) string(TOUPPER "${PROJECT_NAME}" PROJECT_NAME_UPPER) # Command-line options # ==================== option(BUILD_ALL "${PROJECT_NAME}: Build tests, Python API & docs" OFF) option(BUILD_TESTS "${PROJECT_NAME}: Build tests" OFF) option(BUILD_EXAMPLES "${PROJECT_NAME}: Build examples" OFF) option(BUILD_PYTHON "${PROJECT_NAME}: Build Python API" OFF) option(BUILD_DOCS "${PROJECT_NAME}: Build docs" OFF) option(USE_WARNINGS "${PROJECT_NAME}: Build with runtime warnings" ON) option(USE_ASSERT "${PROJECT_NAME}: Build with assertions" ON) option(USE_DEBUG "${PROJECT_NAME}: Build in debug mode" OFF) option(USE_SIMD "${PROJECT_NAME}: Build with hardware optimization" OFF) if(SKBUILD) set(BUILD_ALL 0) set(BUILD_TESTS 0) set(BUILD_PYTHON 1) set(BUILD_DOCS 0) endif() # Read version # ============ if (DEFINED ENV{SETUPTOOLS_SCM_PRETEND_VERSION}) set(PROJECT_VERSION $ENV{SETUPTOOLS_SCM_PRETEND_VERSION}) message(STATUS "Building ${PROJECT_NAME} ${PROJECT_VERSION} (read from SETUPTOOLS_SCM_PRETEND_VERSION)") else() execute_process( COMMAND python -c "from setuptools_scm import get_version; print(get_version())" WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} OUTPUT_VARIABLE PROJECT_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE) message(STATUS "Building ${PROJECT_NAME} ${PROJECT_VERSION}") endif() # Set target # ========== find_package(xtensor REQUIRED) add_library(${PROJECT_NAME} INTERFACE) target_include_directories(${PROJECT_NAME} INTERFACE $ $) target_link_libraries(${PROJECT_NAME} INTERFACE xtensor) target_compile_definitions(${PROJECT_NAME} INTERFACE ${PROJECT_NAME_UPPER}_VERSION="${PROJECT_VERSION}") # Libraries # ========= include(CMakePackageConfigHelpers) include(GNUInstallDirs) include(CTest) include("${PROJECT_NAME}Config.cmake") # Installation headers / CMake / pkg-config # ========================================= if(NOT SKBUILD) 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 ${PROJECT_NAME} EXPORT ${PROJECT_NAME}-targets) install( EXPORT ${PROJECT_NAME}-targets FILE "${PROJECT_NAME}Targets.cmake" DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}") set(${PROJECT_NAME}_TMP ${CMAKE_SIZEOF_VOID_P}) unset(CMAKE_SIZEOF_VOID_P) write_basic_package_version_file( "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake" VERSION "${PROJECT_VERSION}" COMPATIBILITY AnyNewerVersion) set(CMAKE_SIZEOF_VOID_P ${${PROJECT_NAME}_TMP}) install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}Config.cmake" "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake" DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}") configure_file("${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}.pc.in" "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc" @ONLY) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc" DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig/") endif() # Build tests # =========== if(BUILD_TESTS OR BUILD_ALL) enable_testing() add_subdirectory(tests/basic) enable_testing() add_subdirectory(tests/gmat) endif() # Build examples # ============== if(BUILD_EXAMPLES OR BUILD_ALL) enable_testing() add_subdirectory(docs/examples) endif() # Build Python API # ================ if(BUILD_PYTHON OR BUILD_ALL) # The C++ functions are build to a library with name "_${PROJECT_NAME}" # The Python library simply loads all functions set(PYPROJECT_NAME "_${PROJECT_NAME}") if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE Release) endif() find_package(pybind11 REQUIRED CONFIG) find_package(xtensor-python REQUIRED) if (SKBUILD) find_package(NumPy REQUIRED) else() find_package(Python REQUIRED COMPONENTS Interpreter Development NumPy) endif() pybind11_add_module(${PYPROJECT_NAME} python/main.cpp) target_compile_definitions(${PYPROJECT_NAME} PUBLIC VERSION_INFO=${PROJECT_VERSION}) target_link_libraries(${PYPROJECT_NAME} PUBLIC ${PROJECT_NAME} xtensor-python) if (SKBUILD) target_include_directories(${PYPROJECT_NAME} PUBLIC ${NumPy_INCLUDE_DIRS}) else() target_link_libraries(${PYPROJECT_NAME} PUBLIC ${PROJECT_NAME} pybind11::module Python::NumPy) endif() if (USE_WARNINGS) target_link_libraries(${PYPROJECT_NAME} PUBLIC ${PROJECT_NAME}::warnings) message(STATUS "Compiling ${PROJECT_NAME}-Python with run-time warnings") endif() if (USE_ASSERT) target_link_libraries(${PYPROJECT_NAME} PUBLIC ${PROJECT_NAME}::assert) message(STATUS "Compiling ${PROJECT_NAME}-Python with assertions") endif() if (USE_DEBUG) target_link_libraries(${PYPROJECT_NAME} PUBLIC ${PROJECT_NAME}::debug) message(STATUS "Compiling ${PROJECT_NAME}-Python in debug mode") endif() if (USE_SIMD) find_package(xtensor REQUIRED) find_package(xsimd REQUIRED) target_link_libraries(${PYPROJECT_NAME} PUBLIC xtensor::optimize xtensor::use_xsimd) message(STATUS "Compiling ${PROJECT_NAME}-Python with hardware optimization") endif() if (SKBUILD) if(APPLE) set_target_properties(${PYPROJECT_NAME} PROPERTIES INSTALL_RPATH "@loader_path/${CMAKE_INSTALL_LIBDIR}") else() set_target_properties(${PYPROJECT_NAME} PROPERTIES INSTALL_RPATH "$ORIGIN/${CMAKE_INSTALL_LIBDIR}") endif() install(TARGETS ${PYPROJECT_NAME} DESTINATION .) endif() endif() # Build documentation # =================== if(BUILD_DOCS OR BUILD_ALL) find_package(Doxygen REQUIRED) set(DOXYGEN_EXCLUDE_SYMBOLS detail) set(DOXYGEN_CASE_SENSE_NAMES YES) set(DOXYGEN_USE_MATHJAX YES) set(DOXYGEN_GENERATE_TREEVIEW YES) set(DOXYGEN_JAVADOC_AUTOBRIEF YES) set(DOXYGEN_MACRO_EXPANSION YES) set(DOXYGEN_SOURCE_BROWSER YES) set(DOXYGEN_GENERATE_XML YES) set(DOXYGEN_QUIET YES) set(DOXYGEN_WARN_IF_UNDOCUMENTED YES) set(DOXYGEN_WARN_AS_ERROR YES) set(DOXYGEN_ALIASES "license=@par License:") set(DOXYGEN_USE_MDFILE_AS_MAINPAGE "README.md") set(DOXYGEN_HTML_EXTRA_STYLESHEET "${CMAKE_CURRENT_SOURCE_DIR}/docs/doxystyle/doxygen-awesome.css" "${CMAKE_CURRENT_SOURCE_DIR}/docs/doxystyle/custom.css") set(DOXYGEN_STRIP_FROM_INC_PATH "${CMAKE_CURRENT_SOURCE_DIR}/include") set(DOXYGEN_STRIP_FROM_PATH "${CMAKE_CURRENT_SOURCE_DIR}/include") - doxygen_add_docs(docs "${CMAKE_CURRENT_SOURCE_DIR}/include" "README.md") + doxygen_add_docs(html "${CMAKE_CURRENT_SOURCE_DIR}/include" "README.md") endif() diff --git a/docs/api/Mesh.rst b/docs/api/Mesh.rst index 013df73..08d08b3 100644 --- a/docs/api/Mesh.rst +++ b/docs/api/Mesh.rst @@ -1,116 +1,116 @@ **** Mesh **** Element-type ============ ElementType ----------- .. doxygenenum:: GooseFEM::Mesh::ElementType :project: GooseFEM defaultElementType ------------------ .. doxygenfunction:: GooseFEM::Mesh::defaultElementType :project: GooseFEM Stitch meshes ============= Stitch ------ .. doxygenclass:: GooseFEM::Mesh::Stitch :project: GooseFEM :members: ManualStitch ------------ .. doxygenclass:: GooseFEM::Mesh::ManualStitch :project: GooseFEM :members: overlapping ----------- .. doxygenfunction:: GooseFEM::Mesh::overlapping :project: GooseFEM Renumber lists ============== Renumber -------- .. doxygenclass:: GooseFEM::Mesh::Renumber :project: GooseFEM :members: renumber -------- .. doxygenfunction:: GooseFEM::Mesh::renumber :project: GooseFEM Reorder ------- .. doxygenclass:: GooseFEM::Mesh::Reorder :project: GooseFEM :members: Basic mesh properties ===================== dofs ---- .. doxygenfunction:: GooseFEM::Mesh::dofs :project: GooseFEM coordination ------------ .. doxygenfunction:: GooseFEM::Mesh::coordination :project: GooseFEM elem2node --------- .. doxygenfunction:: GooseFEM::Mesh::elem2node :project: GooseFEM edgesize -------- -.. doxygenfunction:: GooseFEM::Mesh::edgesize(const xt::xtensor&, const xt::xtensor&, ElementType) +.. doxygenfunction:: GooseFEM::Mesh::edgesize(const C&, const E&, ElementType) :project: GooseFEM edgesize -------- -.. doxygenfunction:: GooseFEM::Mesh::edgesize(const xt::xtensor&, const xt::xtensor&) +.. doxygenfunction:: GooseFEM::Mesh::edgesize(const C&, const E&) :project: GooseFEM centers ------- -.. doxygenfunction:: GooseFEM::Mesh::centers(const xt::xtensor&, const xt::xtensor&, ElementType) +.. doxygenfunction:: GooseFEM::Mesh::centers(const C&, const E&, ElementType) :project: GooseFEM -.. doxygenfunction:: GooseFEM::Mesh::centers(const xt::xtensor&, const xt::xtensor&) +.. doxygenfunction:: GooseFEM::Mesh::centers(const C&, const E&) :project: GooseFEM elemmap2nodemap --------------- -.. doxygenfunction:: GooseFEM::Mesh::elemmap2nodemap(const xt::xtensor&, const xt::xtensor&, const xt::xtensor&, ElementType) +.. doxygenfunction:: GooseFEM::Mesh::elemmap2nodemap(const T&, const C&, const E&, ElementType) :project: GooseFEM -.. doxygenfunction:: GooseFEM::Mesh::elemmap2nodemap(const xt::xtensor&, const xt::xtensor&, const xt::xtensor&) +.. doxygenfunction:: GooseFEM::Mesh::elemmap2nodemap(const T&, const C&, const E&) :project: GooseFEM diff --git a/docs/install.rst b/docs/install.rst index 36e6e95..8353c41 100644 --- a/docs/install.rst +++ b/docs/install.rst @@ -1,152 +1,171 @@ **************** Getting GooseFEM **************** Using conda =========== The easiest is to use *conda* to install *GooseFEM*:: conda install -c conda-forge goosefem This will install all the necessary runtime dependencies as well. .. tip:: The runtime dependencies (for both the C++ and the Python APIs) are also listed in ``environment.yaml``. - One could install those dependencies in an activated environment by: - - .. code-block:: cpp + One could install those dependencies in an activated environment by:: conda env update --file environment.yaml This will install the dependencies to run tests and examples. From source =========== .. tip:: It could be instructive to see how configuration / compilation is done in the continuous integration: :download:`.github/workflows/ci.yml <../.github/workflows/ci.yml>` Download the package:: git checkout https://github.com/tdegeus/GooseFEM.git cd GooseFEM Install headers, *CMake* and *pkg-config* support: .. code-block:: none cmake -Bbuild cd build cmake --install . .. note:: The version is determined from the latest git tag, and possible commits since that tag. Internally Python's ``setuptools_scm`` is used to this end. In case that you are not working from a clone of the repository you have to set the version manually, **before** configuring with CMake: .. code-block:: none export SETUPTOOLS_SCM_PRETEND_VERSION="1.2.3" cmake -Bbuild cd build cmake --install . In Windows replace the first line with .. code-block:: none set SETUPTOOLS_SCM_PRETEND_VERSION="1.2.3" .. tip:: To install in a loaded conda environment use .. code-block:: none cmake -Bbuild -DCMAKE_INSTALL_PREFIX:PATH="${CONDA_PREFIX}" cd build cmake --install . .. _install_python: Python interface ================ .. tip:: It could be instructive to see how configuration / compilation is done in the continuous integration: :download:`.github/workflows/ci.yml <../.github/workflows/ci.yml>` Using conda ^^^^^^^^^^^ The quickest (but not the most efficient!) is to use *conda* to install *GooseFEM*:: conda install -c conda-forge python-goosefem .. warning:: This package does not benefit from *xsimd* optimisation, as it is not compiled on your hardware. You'll have to compile by hand to benefit from *xsimd* optimisation. .. _install_python_source: From source ^^^^^^^^^^^ Start by installing the dependencies, for example using *conda*:: conda install -c conda-forge xtensor-python eigen xsimd Note that *xsimd* is optional, but recommended. Then, download the package:: git checkout https://github.com/tdegeus/GooseFEM.git cd GooseFEM -And, optionally, choose to use hardware optimisation (using *xsimd*):: +Install the package using:: - export CMAKE_ARGS="-DUSE_SIMD=1" + python setup.py install --build-type Release -vv -Install the package using:: +To use hardware optimisation (using *xsimd*) use instead:: - python -m pip install . -vv + python setup.py install --build-type Release -vv -DUSE_SIMD=1 .. _install_docs: Docs ==== +C++ (Doxygen) +^^^^^^^^^^^^^ + .. tip:: It could be instructive to see how configuration / compilation is done in the continuous integration: :download:`.github/workflows/gh-pages.yml <../.github/workflows/gh-pages.yml>` To build the docs there are two steps to be made: 1. Extract the code documentation using doxygen: .. code-block:: none cmake -Bbuild -DBUILD_DOCS=1 cd build make docs 2. Build the docs using sphinx: .. code-block:: none cd docs make html + +General / Python (Sphinx) +^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. tip:: + + The dependencies + are also listed in ``environment.yaml``. + One could install those dependencies in an activated environment by:: + + conda env update --file environment.yaml + +Build the docs as follows:: + + cd docs + make html + + diff --git a/environment.yaml b/environment.yaml index 2ba8ecf..3500cef 100644 --- a/environment.yaml +++ b/environment.yaml @@ -1,19 +1,22 @@ channels: - conda-forge dependencies: +- breathe - catch2 - cmake - doxygen - eigen - gmatelastic - gmatelastoplasticqpot - mathjax - ninja - numpy - pybind11 - python - scikit-build - setuptools_scm +- sphinx +- sphinx_rtd_theme - xsimd - xtensor - xtensor-python