From 7a18e6428b3ce36548526410f8414610fb791a79 Mon Sep 17 00:00:00 2001 From: "Jack S. Hale" Date: Mon, 27 Nov 2023 12:05:19 +0100 Subject: [PATCH] Update for DOLFINx 0.7.2 (#9) * Update to v0.6.0 * Update for 0.7.2, switch to scikit-build-core, remove sphinx makefile * flake8 and isort * Definetly doesn't work with nanobind based DOLFINx * Trigger test. * Install scikit-build-core --- .github/workflows/tests.yml | 7 +- CMakeLists.txt | 7 +- README.md | 2 +- demo/demo_kirchhoff-love-clamped.py | 18 ++-- demo/demo_reissner-mindlin-clamped-tdnns.py | 36 ++++---- demo/demo_reissner-mindlin-clamped.py | 14 ++-- .../demo_reissner-mindlin-simply-supported.py | 21 ++--- doc/Makefile | 20 ----- doc/source/conf.py | 3 +- doc/source/jupytext_process.py | 4 +- launch-container.sh | 2 +- pyproject.toml | 19 ++++- setup.py | 83 ------------------- 13 files changed, 61 insertions(+), 175 deletions(-) delete mode 100644 doc/Makefile delete mode 100644 setup.py diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index cf44cc4..27be958 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -14,7 +14,7 @@ on: jobs: build-and-test: runs-on: ubuntu-latest - container: ghcr.io/fenics/dolfinx/dolfinx:v0.6.0-r1 + container: ghcr.io/fenics/dolfinx/dolfinx:v0.7.2 steps: - name: Checkout uses: actions/checkout@v3 @@ -33,12 +33,13 @@ jobs: - name: Install FEniCSx-Shells run: | - python3 -m pip install . + pip install scikit-build-core[pyproject] # TO REMOVE ONCE 0.8.0 RELEASED + python3 -m pip install --no-build-isolation --check-build-dependencies . - name: Build documentation run: | cd doc - make html + python3 -m sphinx -W -b html source/ build/html/ - name: Run demos run: | diff --git a/CMakeLists.txt b/CMakeLists.txt index 895d509..53bb8f8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,9 +1,8 @@ -cmake_minimum_required(VERSION 3.16) +cmake_minimum_required(VERSION 3.18) -project(fenicsx_shells VERSION "0.1.0") +project(fenicsx_shells VERSION "0.1.0.0") -set(Python_FIND_IMPLEMENTATIONS CPython) -find_package(Python REQUIRED COMPONENTS Interpreter Development) +find_package(Python COMPONENTS Interpreter Development REQUIRED) find_package(DOLFINX REQUIRED) # Set C++ standard before finding pybind11 diff --git a/README.md b/README.md index 871e451..fa22a5f 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ numerical methods for solving a wide range of thin structural models (beams, plates and shells) expressed in the Unified Form Language (UFL) of the FEniCS Project. -*FEniCSx-Shells is an experimental version targeting version v0.5.0 of the new +*FEniCSx-Shells is an experimental version targeting version v0.7.2 of the new [DOLFINx solver](https://github.com/fenics/dolfinx).* The foundational aspects of the FEniCS-Shells project are described in the paper: diff --git a/demo/demo_kirchhoff-love-clamped.py b/demo/demo_kirchhoff-love-clamped.py index 104091e..76ddd53 100644 --- a/demo/demo_kirchhoff-love-clamped.py +++ b/demo/demo_kirchhoff-love-clamped.py @@ -41,18 +41,16 @@ import ufl from dolfinx.fem import FunctionSpace, dirichletbc from dolfinx.fem.petsc import LinearProblem -from dolfinx.mesh import create_unit_square, CellType +from dolfinx.mesh import CellType, create_unit_square from ufl import (FacetNormal, FiniteElement, Identity, Measure, MixedElement, grad, inner, sym, tr) from mpi4py import MPI # We then create a two-dimensional mesh of the mid-plane of the plate $\Omega = -# [0, 1] \times [0, 1]$. `GhostMode.shared_facet` is required as the Form will -# use Nédélec elements and DG-type restrictions. +# [0, 1] \times [0, 1]$. -mesh = create_unit_square(MPI.COMM_WORLD, 16, 16, CellType.triangle, - dolfinx.mesh.GhostMode.shared_facet) +mesh = create_unit_square(MPI.COMM_WORLD, 16, 16, CellType.triangle) # The Hellen-Herrmann-Johnson element for the Kirchhoff-Love plate problem # consists of: @@ -207,19 +205,19 @@ def all_boundary(x): # + problem = LinearProblem(a, L, bcs=bcs, petsc_options={ - "ksp_type": "preonly", "pc_type": "lu", "pc_factor_mat_solver_type": "mumps", "ksp_view": ""}) + "ksp_type": "preonly", "pc_type": "lu", "pc_factor_mat_solver_type": "mumps"}) u_h = problem.solve() -bb_tree = dolfinx.geometry.BoundingBoxTree(mesh, 2) -point = np.array([0.5, 0.5, 0.0], dtype=np.float64) -cell_candidates = dolfinx.geometry.compute_collisions(bb_tree, point) +bb_tree = dolfinx.geometry.bb_tree(mesh, 2) +point = np.array([[0.5, 0.5, 0.0]], dtype=np.float64) +cell_candidates = dolfinx.geometry.compute_collisions_points(bb_tree, point) cells = dolfinx.geometry.compute_colliding_cells( mesh, cell_candidates, point) w, M = u_h.split() if len(cells) > 0: - value = w.eval(point, cells[0]) + value = w.eval(point, cells.array[0]) print(value[0]) # TODO: IO? diff --git a/demo/demo_reissner-mindlin-clamped-tdnns.py b/demo/demo_reissner-mindlin-clamped-tdnns.py index aca8fd2..1962894 100644 --- a/demo/demo_reissner-mindlin-clamped-tdnns.py +++ b/demo/demo_reissner-mindlin-clamped-tdnns.py @@ -43,8 +43,7 @@ import ufl from dolfinx.fem import Function, FunctionSpace, dirichletbc from dolfinx.fem.petsc import LinearProblem -from dolfinx.io.utils import XDMFFile -from dolfinx.mesh import CellType, GhostMode, create_unit_square +from dolfinx.mesh import CellType, create_unit_square from ufl import (FacetNormal, FiniteElement, Identity, Measure, MixedElement, grad, inner, split, sym, tr) @@ -53,12 +52,10 @@ # - # We then create a two-dimensional mesh of the mid-plane of the plate $\Omega = -# [0, 1] \times [0, 1]$. `GhostMode.shared_facet` is required as the Form will -# use Nédélec elements and DG-type restrictions. +# [0, 1] \times [0, 1]$. # + -mesh = create_unit_square(MPI.COMM_WORLD, 16, 16, CellType.triangle, - GhostMode.shared_facet) +mesh = create_unit_square(MPI.COMM_WORLD, 16, 16, CellType.triangle) # - @@ -161,7 +158,8 @@ def inner_divdiv(M, theta): """Discrete div-div inner product""" n = FacetNormal(M.ufl_domain()) M_nn = nn(M) - result = -inner(M, k_theta(theta))*dx + inner(M_nn("+"), ufl.jump(theta, n))*dS + inner(M_nn, ufl.dot(theta, n))*ds + result = -inner(M, k_theta(theta))*dx + inner(M_nn("+"), + ufl.jump(theta, n))*dS + inner(M_nn, ufl.dot(theta, n))*ds return result @@ -179,11 +177,11 @@ def gamma(theta, w): # Imposition of boundary conditions requires some care. We reproduce the table # from Pechstein and Schöberl specifying the different types of boundary condition. # -# | Essential | Natural | Non-homogeneous term | -# | ------------------------------------ | ------------------------------------ | ------------------------------------------------------------------- | -# | $w = \bar{w}$ | $\mu(\partial_n w - \theta_n) = g_w$ | $\int_{\Gamma} g_w \tilde{w} \; \mathrm{d}s$ | -# | $\theta_\tau = \bar{\theta}_{\tau} $ | $m_{n\tau} = g_{\theta_\tau}$ | $\int_{\Gamma} g_{\theta_\tau} \cdot \tilde{\theta} \; \mathrm{d}s$ | -# | $m_{nn} = \bar{m}_{nn}$ | $\theta_n = g_{\theta_n}$ | $\int_{\Gamma} g_{\theta_n} \tilde{m}_{nn} \; \mathrm{d}s$ | +# | Essential | Natural | Non-homogeneous term | # noqa: E501 +# | ------------------------------------ | ------------------------------------ | ------------------------------------------------------------------- | # noqa: E501 +# | $w = \bar{w}$ | $\mu(\partial_n w - \theta_n) = g_w$ | $\int_{\Gamma} g_w \tilde{w} \; \mathrm{d}s$ | # noqa: E501 +# | $\theta_\tau = \bar{\theta}_{\tau} $ | $m_{n\tau} = g_{\theta_\tau}$ | $\int_{\Gamma} g_{\theta_\tau} \cdot \tilde{\theta} \; \mathrm{d}s$ | # noqa: E501 +# | $m_{nn} = \bar{m}_{nn}$ | $\theta_n = g_{\theta_n}$ | $\int_{\Gamma} g_{\theta_n} \tilde{m}_{nn} \; \mathrm{d}s$ | # noqa: E501 # # where $\theta_{n} = \theta_n$ is the normal component of the rotation, # $\theta_{\tau} = \theta \cdot \tau $ is the tangential component of the @@ -235,20 +233,14 @@ def all_boundary(x): "ksp_type": "preonly", "pc_type": "lu", "pc_factor_mat_solver_type": "mumps"}) u_h = problem.solve() -bb_tree = dolfinx.geometry.BoundingBoxTree(mesh, 2) -point = np.array([0.5, 0.5, 0.0], dtype=np.float64) -cell_candidates = dolfinx.geometry.compute_collisions(bb_tree, point) +bb_tree = dolfinx.geometry.bb_tree(mesh, 2) +point = np.array([[0.5, 0.5, 0.0]], dtype=np.float64) +cell_candidates = dolfinx.geometry.compute_collisions_points(bb_tree, point) cells = dolfinx.geometry.compute_colliding_cells( mesh, cell_candidates, point) theta, w, M = u_h.split() if len(cells) > 0: - value = w.eval(point, cells[0]) + value = w.eval(point, cells.array[0]) print(value[0]) - -with XDMFFile(MPI.COMM_WORLD, "w.xdmf", "w") as f: - f.write_mesh(mesh) - f.write_function(w) - -# TODO: Output of m and theta using new interpolation functions? diff --git a/demo/demo_reissner-mindlin-clamped.py b/demo/demo_reissner-mindlin-clamped.py index 4aa2625..0bd4d4a 100644 --- a/demo/demo_reissner-mindlin-clamped.py +++ b/demo/demo_reissner-mindlin-clamped.py @@ -44,8 +44,7 @@ # [0, 1] \times [0, 1]$. `GhostMode.shared_facet` is required as the Form will # use Nédélec elements and DG-type restrictions. -mesh = create_unit_square(MPI.COMM_WORLD, 32, 32, CellType.triangle, - dolfinx.cpp.mesh.GhostMode.shared_facet) +mesh = create_unit_square(MPI.COMM_WORLD, 32, 32, CellType.triangle) # The Durán-Liberman element [1] for the Reissner-Mindlin plate problem # consists of: @@ -217,16 +216,16 @@ def all_boundary(x): "ksp_type": "preonly", "pc_type": "lu", "pc_factor_mat_solver_type": "mumps"}) u_ = problem.solve() -bb_tree = dolfinx.geometry.BoundingBoxTree(mesh, 2) -point = np.array([0.5, 0.5, 0.0], dtype=np.float64) -cell_candidates = dolfinx.geometry.compute_collisions(bb_tree, point) +bb_tree = dolfinx.geometry.bb_tree(mesh, 2) +point = np.array([[0.5, 0.5, 0.0]], dtype=np.float64) +cell_candidates = dolfinx.geometry.compute_collisions_points(bb_tree, point) cells = dolfinx.geometry.compute_colliding_cells( mesh, cell_candidates, point) theta, w, R_gamma, p = u_.split() if len(cells) > 0: - value = w.eval(point, cells[0]) + value = w.eval(point, cells.array[0]) print(value[0]) # NOTE: FEniCS-Shells (old dolfin) `demo/documented/reissner-mindlin-clamped` # gives 1.28506469462e-06 on a 32 x 32 mesh and 1.2703580973e-06 on a 64 x 64 @@ -239,9 +238,6 @@ def test_center_displacement(): f.write_mesh(mesh) f.write_function(w) -with XDMFFile(MPI.COMM_WORLD, "theta.xdmf", "w") as f: - f.write_mesh(mesh) - f.write_function(theta) # - # ## Appendix diff --git a/demo/demo_reissner-mindlin-simply-supported.py b/demo/demo_reissner-mindlin-simply-supported.py index 43101e5..b671baf 100644 --- a/demo/demo_reissner-mindlin-simply-supported.py +++ b/demo/demo_reissner-mindlin-simply-supported.py @@ -33,7 +33,6 @@ import ufl from dolfinx.fem import Function, FunctionSpace, dirichletbc from dolfinx.fem.petsc import LinearProblem -from dolfinx.io.utils import XDMFFile from dolfinx.mesh import CellType, create_unit_square from ufl import (FiniteElement, MixedElement, VectorElement, dx, grad, inner, split, sym, tr) @@ -44,8 +43,7 @@ # [0, 1] \times [0, 1]$. `GhostMode.shared_facet` is required as the Form will # use Nédélec elements and DG-type restrictions. -mesh = create_unit_square(MPI.COMM_WORLD, 32, 32, CellType.quadrilateral, - dolfinx.cpp.mesh.GhostMode.shared_facet) +mesh = create_unit_square(MPI.COMM_WORLD, 32, 32, CellType.quadrilateral) # The MITC4 element [1] for the Reissner-Mindlin plate problem # consists of: @@ -233,24 +231,15 @@ def make_bc(value, V, on_boundary): "ksp_type": "preonly", "pc_type": "lu", "pc_factor_mat_solver_type": "mumps"}) u_ = problem.solve() -bb_tree = dolfinx.geometry.BoundingBoxTree(mesh, 2) -point = np.array([0.5, 0.5, 0.0], dtype=np.float64) -cell_candidates = dolfinx.geometry.compute_collisions(bb_tree, point) +bb_tree = dolfinx.geometry.bb_tree(mesh, 2) +point = np.array([[0.5, 0.5, 0.0]], dtype=np.float64) +cell_candidates = dolfinx.geometry.compute_collisions_points(bb_tree, point) cells = dolfinx.geometry.compute_colliding_cells( mesh, cell_candidates, point) theta, w, R_gamma, p = u_.split() if len(cells) > 0: - value = w.eval(point, cells[0]) + value = w.eval(point, cells.array[0]) print(value[0]) - - -with XDMFFile(MPI.COMM_WORLD, "w.xdmf", "w") as f: - f.write_mesh(mesh) - f.write_function(w) - -with XDMFFile(MPI.COMM_WORLD, "theta.xdmf", "w") as f: - f.write_mesh(mesh) - f.write_function(theta) # - diff --git a/doc/Makefile b/doc/Makefile deleted file mode 100644 index d0c3cbf..0000000 --- a/doc/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -# Minimal makefile for Sphinx documentation -# - -# You can set these variables from the command line, and also -# from the environment for the first two. -SPHINXOPTS ?= -SPHINXBUILD ?= sphinx-build -SOURCEDIR = source -BUILDDIR = build - -# Put it first so that "make" without argument is like "make help". -help: - @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) - -.PHONY: help Makefile - -# Catch-all target: route all unknown targets to Sphinx using the new -# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). -%: Makefile - @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/doc/source/conf.py b/doc/source/conf.py index 0f17523..5d8a040 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -6,13 +6,12 @@ # -- Project information ----------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information -import sys import os +import sys sys.path.insert(0, os.path.abspath('.')) import jupytext_process - jupytext_process.process() project = 'FEniCSx-Shells' diff --git a/doc/source/jupytext_process.py b/doc/source/jupytext_process.py index 3b16248..fad2b3c 100644 --- a/doc/source/jupytext_process.py +++ b/doc/source/jupytext_process.py @@ -4,9 +4,9 @@ # # SPDX-License-Identifier: LGPL-3.0-or-later -import shutil -import pathlib import os +import pathlib +import shutil import jupytext diff --git a/launch-container.sh b/launch-container.sh index 5d6223f..300616f 100755 --- a/launch-container.sh +++ b/launch-container.sh @@ -1,3 +1,3 @@ #!/bin/bash CONTAINER_ENGINE="docker" -${CONTAINER_ENGINE} run -ti -v $(pwd):/shared -w /shared dolfinx/dolfinx:v0.6.0-r1 +${CONTAINER_ENGINE} run -ti -v $(pwd):/shared -w /shared dolfinx/dolfinx:v0.7.2 diff --git a/pyproject.toml b/pyproject.toml index 5a52e3a..1f0556c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,3 +1,18 @@ [build-system] -requires = ["setuptools>=42", "wheel", "pybind11", "cmake"] -build-backend = "setuptools.build_meta" +requires = ["scikit-build-core[pyproject]", "wheel", "pybind11"] +build-backend = "scikit_build_core.build" + +[project] +name = "fenicsx-shells" +version = "0.1.0.dev0" +description = "FEniCSx-Shells" +readme = "README.md" +requires-python = ">=3.8.0" +license = { file = "COPYING.LESSER" } +authors = [ + { email = "jack.hale@uni.lu" }, + { name = "Jack S. Hale" }, +] +dependencies = [ + "fenics-dolfinx>=0.7.2,<0.8.0", +] diff --git a/setup.py b/setup.py deleted file mode 100644 index 99fa4ac..0000000 --- a/setup.py +++ /dev/null @@ -1,83 +0,0 @@ -import os -import subprocess -import sys - -from setuptools import Extension, setup -from setuptools.command.build_ext import build_ext - -if sys.version_info < (3, 7): - print("Python 3.7 or higher required, please upgrade.") - sys.exit(1) - -CLASSIFIERS = """\ -Development Status :: 5 - Production/Stable -Intended Audience :: Developers -Intended Audience :: Science/Research -License :: OSI Approved :: MIT License -Operating System :: POSIX -Operating System :: POSIX :: Linux -Operating System :: MacOS :: MacOS X -Programming Language :: Python -Programming Language :: Python :: 3 -Programming Language :: Python :: 3.7 -Programming Language :: Python :: 3.8 -Programming Language :: Python :: 3.9 -Topic :: Scientific/Engineering :: Mathematics -Topic :: Software Development :: Libraries :: Python Modules -""" - - -class CMakeExtension(Extension): - def __init__(self, name, sourcedir=''): - Extension.__init__(self, name, sources=[]) - self.sourcedir = os.path.abspath(sourcedir) - - -class CMakeBuild(build_ext): - def run(self): - try: - subprocess.check_output(['cmake', '--version']) - except OSError: - raise RuntimeError("CMake must be installed to build the following extensions: " - + ", ".join(e.name for e in self.extensions)) - - for ext in self.extensions: - self.build_extension(ext) - - def build_extension(self, ext): - extdir = os.path.abspath(os.path.dirname(self.get_ext_fullpath(ext.name))) - cmake_args = ['-DCMAKE_LIBRARY_OUTPUT_DIRECTORY=' + extdir, - '-DPYTHON_EXECUTABLE=' + sys.executable] - - cfg = 'Debug' if self.debug else 'Release' - build_args = ['--config', cfg] - - cmake_args += ['-DCMAKE_BUILD_TYPE=' + cfg] - build_args += ['--', '-j3'] - - env = os.environ.copy() - import pybind11 - env['pybind11_DIR'] = pybind11.get_cmake_dir() - env['CXXFLAGS'] = '{} -DVERSION_INFO=\\"{}\\"'.format(env.get('CXXFLAGS', ''), - self.distribution.get_version()) - - if not os.path.exists(self.build_temp): - os.makedirs(self.build_temp) - subprocess.check_call(['cmake', ext.sourcedir] + cmake_args, cwd=self.build_temp, env=env) - subprocess.check_call(['cmake', '--build', '.'] + build_args, cwd=self.build_temp, env=env) - - -setup(name='fenicsx-shells', - version='0.5.0.dev0', - description='Basix Python interface', - url="https://github.com/FEniCS-Shells/fenicsx-shells", - author='FEniCSx-Shells authors', - maintainer_email="jack.hale@uni.lu", - license="LGPL v3.0 or later", - classifiers=[_f for _f in CLASSIFIERS.split('\n') if _f], - platforms=["Linux", "Mac OS-X", "Unix"], - packages=["fenicsx_shells"], - setup_requires=["pybind11"], - ext_modules=[CMakeExtension('fenicsx_shells._fenicsx_shellscpp')], - cmdclass=dict(build_ext=CMakeBuild), - zip_safe=False)