From 9b2e65ee4d832276eefb81b7e0a6b26d82bbe4a1 Mon Sep 17 00:00:00 2001 From: sora <210at85@gmail.com> Date: Wed, 27 May 2026 23:52:59 +0800 Subject: [PATCH 1/2] Modernize packaging, CI, and documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace setup.py and the pytest/documentation workflows with pyproject.toml (hatchling) and one uv-based CI workflow. Packaging - Add pyproject.toml: runtime deps, docs extra, dev dependency group, console scripts - Remove setup.py; requires-python >=3.11; __version__ from importlib.metadata .github/workflows - Remove pytest.yml and documentation.yml; add ci.yml - test: uv sync, coverage and pytest on 3.11–3.13, apt libs for VTK/PySide6, pyfem --help - build: uv build, wheel smoke in .wheel-check venv, upload dist artifact - docs: uv sync --extra docs --no-dev, sphinx-build; upload-pages-artifact on push to main - deploy-docs: deploy-pages on push to main (replaces peaceiris/actions-gh-pages → gh-pages) doc/ - conf.py: Furo, MyST, sphinx-autoapi (api/ at build time, gitignored) - Remove Makefile, make.bat, requirements.txt, _static/custom.css, introduction/about.md, introduction/api.md, pyfem.html - Add doc/README.md; update installation guide, index, tutorials, README Other - .readthedocs.yaml: uv sync --extra docs --no-dev; apt libgl1 - .gitignore: doc/_build, doc/api, .wheel-check/, uv.lock, AGENTS.md, .python-version --- .github/workflows/ci.yml | 116 ++++++++++++++++++++++++ .github/workflows/documentation.yml | 27 ------ .github/workflows/pytest.yml | 39 -------- .gitignore | 22 +++-- .readthedocs.yaml | 31 +++---- README.md | 94 +++++++++++++------- doc/Makefile | 26 ------ doc/README.md | 29 ++++++ doc/_static/custom.css | 3 - doc/conf.py | 121 ++++++++++++------------- doc/develop/overview.md | 12 ++- doc/elements/smallstraincontinuum.md | 6 +- doc/index.md | 11 ++- doc/installation/overview.md | 128 +++++++++++++++++---------- doc/introduction/about.md | 24 ----- doc/introduction/api.md | 5 -- doc/introduction/introduction.md | 4 +- doc/introduction/quickstart.md | 6 +- doc/make.bat | 35 -------- doc/models/overview.md | 9 ++ doc/pyfem.html | 10 --- doc/requirements.txt | 20 ----- doc/tutorials/dissnrg_tutorial.md | 4 +- doc/tutorials/gmsh_input_tutorial.md | 8 +- doc/usermanual.md | 1 + pyfem/__init__.py | 6 +- pyproject.toml | 77 ++++++++++++++++ setup.py | 56 ------------ 28 files changed, 487 insertions(+), 443 deletions(-) create mode 100644 .github/workflows/ci.yml delete mode 100644 .github/workflows/documentation.yml delete mode 100644 .github/workflows/pytest.yml delete mode 100644 doc/Makefile create mode 100644 doc/README.md delete mode 100644 doc/_static/custom.css delete mode 100644 doc/introduction/about.md delete mode 100644 doc/introduction/api.md delete mode 100644 doc/make.bat delete mode 100644 doc/pyfem.html delete mode 100644 doc/requirements.txt create mode 100644 pyproject.toml delete mode 100644 setup.py diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..23f13878 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,116 @@ +name: CI + +# Triggers: +# push (any branch): test, build, docs on every branch push (fork or upstream) +# pull_request → main: same checks when a PR is opened/updated +# push → main only: upload Pages artifact + deploy-docs (see job if: filters) +# workflow_dispatch: manual run on the selected ref +on: + push: + pull_request: + branches: [main] + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: ci-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +env: + DEFAULT_PYTHON: "3.13" + +jobs: + test: + name: Python ${{ matrix.python-version }} + runs-on: ubuntu-latest + timeout-minutes: 15 + strategy: + fail-fast: false + matrix: + python-version: ["3.11", "3.12", "3.13"] + steps: + - uses: actions/checkout@v4 + - uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0 + with: + python-version: ${{ matrix.python-version }} + enable-cache: true + cache-suffix: test-${{ matrix.python-version }} + - name: Install system dependencies + run: | + sudo apt-get update + sudo apt-get install -y --no-install-recommends libgl1 libxkbcommon-x11-0 + - run: uv sync + - run: uv run coverage run -m pytest -q + - run: uv run coverage report + - run: uv run pyfem --help + + build: + name: Build package + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - uses: actions/checkout@v4 + - uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0 + with: + python-version: ${{ env.DEFAULT_PYTHON }} + enable-cache: true + cache-suffix: build + - run: uv build + - name: Verify wheel installs + run: | + uv venv .wheel-check + uv pip install --python .wheel-check dist/*.whl + .wheel-check/bin/python -c "import pyfem; print(pyfem.__version__)" + .wheel-check/bin/pyfem --help + - uses: actions/upload-artifact@v4 + with: + name: dist + path: dist/ + + docs: + name: Build documentation + runs-on: ubuntu-latest + timeout-minutes: 15 + permissions: + contents: read + pages: write + id-token: write + steps: + - uses: actions/checkout@v4 + - uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0 + with: + python-version: ${{ env.DEFAULT_PYTHON }} + enable-cache: true + cache-suffix: docs + - name: Install system dependencies + run: | + sudo apt-get update + sudo apt-get install -y --no-install-recommends libgl1 + - run: uv sync --extra docs --no-dev + - run: uv run sphinx-build -M html doc doc/_build + - name: Upload Pages artifact + if: github.event_name == 'push' && github.ref == 'refs/heads/main' + uses: actions/upload-pages-artifact@v3 + with: + path: doc/_build/html + + deploy-docs: + name: Deploy documentation + needs: docs + if: github.event_name == 'push' && github.ref == 'refs/heads/main' + runs-on: ubuntu-latest + timeout-minutes: 5 + concurrency: + group: pages-${{ github.ref }} + cancel-in-progress: false + permissions: + pages: write + id-token: write + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + steps: + - uses: actions/deploy-pages@v4 + id: deployment diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml deleted file mode 100644 index 6c24e8a2..00000000 --- a/.github/workflows/documentation.yml +++ /dev/null @@ -1,27 +0,0 @@ -name: documentation - -on: [push, pull_request, workflow_dispatch] - -permissions: - contents: write - -jobs: - docs: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-python@v5 - - name: Install dependencies - run: | - pip install sphinx sphinx_rtd_theme myst_parser sphinx-autoapi h5py vtk - - name: Sphinx build - run: | - sphinx-build doc _build - - name: Deploy to GitHub Pages - uses: peaceiris/actions-gh-pages@v3 - if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} - with: - publish_branch: gh-pages - github_token: ${{ secrets.GITHUB_TOKEN }} - publish_dir: _build/ - force_orphan: true diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml deleted file mode 100644 index f8acda20..00000000 --- a/.github/workflows/pytest.yml +++ /dev/null @@ -1,39 +0,0 @@ -name: PyFEM CI - -on: - push: - branches: [ main ] - pull_request: - branches: [ main ] - -jobs: - test: - name: Test on Python ${{ matrix.python-version }} - runs-on: ubuntu-latest - strategy: - matrix: - python-version: ["3.9", "3.10" , "3.11", "3.12"] - - steps: - - name: Checkout repository - uses: actions/checkout@v3 - - - name: Set up Python - uses: actions/setup-python@v4 - with: - python-version: ${{ matrix.python-version }} - - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install numpy scipy matplotlib meshio h5py vtk coverage - - - name: Run tests - run: | - python -m unittest discover -s test -p "*.py" - - - name: Run tests with coverage - run: | - pip install coverage - coverage run -m unittest discover -s test -p "*.py" - coverage report diff --git a/.gitignore b/.gitignore index 4853c431..9ab052e3 100644 --- a/.gitignore +++ b/.gitignore @@ -39,9 +39,9 @@ MANIFEST # Documentation doc/_build -doc/html doc/_api -doc/pyfem.*.rst +doc/api +doc/html # PyInstaller # Usually these files are written by a python script from a template @@ -97,15 +97,21 @@ target/ profile_default/ ipython_config.py -# pyenv +# Optional local pin for uv/pyenv (not required; CI uses DEFAULT_PYTHON in ci.yml) .python-version +# Local agent notes (not shared in repo for now) +AGENTS.md + +# CI wheel smoke venv (build job) +.wheel-check/ + # pipenv # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. # However, in case of collaboration, if having platform-specific dependencies or dependencies # having no cross-platform support, pipenv may install dependencies that don't work, or not # install all needed dependencies. -#Pipfile.lock +# Pipfile.lock # celery beat schedule file celerybeat-schedule @@ -121,6 +127,7 @@ venv/ ENV/ env.bak/ venv.bak/ +uv.lock # Spyder project settings .spyderproject @@ -143,9 +150,8 @@ dmypy.json pyfem.sh pyfem.exe -# +# Editor directories and files .agents -.github -.pytest_cache -.vscode .codex +.cursor +.vscode diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 340edefc..80e0ad72 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -1,35 +1,24 @@ # Read the Docs configuration file -# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details +# https://docs.readthedocs.com/platform/stable/config-file/v2.html version: 2 -# Build documentation in the doc/ directory with Sphinx +build: + os: ubuntu-24.04 + tools: + python: "3.13" + apt_packages: + - libgl1 + sphinx: configuration: doc/conf.py fail_on_warning: false -# Build environment -build: - os: ubuntu-22.04 - tools: - python: "3.11" - jobs: - post_checkout: - # Generate API documentation - - echo "Generating API documentation..." - -# Python dependencies python: install: - # Install documentation requirements - - requirements: doc/requirements.txt - # Install the package itself - - method: pip - path: . - extra_requirements: - - docs + - method: uv + command: sync --extra docs --no-dev -# Formats to build (PDF, EPUB, etc.) formats: - pdf - epub diff --git a/README.md b/README.md index e023cc18..57e1bbfe 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,12 @@ # PyFEM: A Python Finite Element Code -[](https://www.python.org/downloads/) +[](https://www.python.org/downloads/) +[](https://github.com/jjcremmers/PyFEM/actions/workflows/ci.yml) [](LICENSE) -[](https://github.com/jjcremmers/PyFEM/tree/main/doc) +[](https://pyfem.readthedocs.io/) [](https://github.com/jjcremmers/PyFEM/stargazers) [](https://github.com/jjcremmers/PyFEM/issues) -[](doc/index.rst#how-to-cite) +[](doc/introduction/introduction.md#how-to-cite) PyFEM is a Python-based finite element code designed for educational and research purposes in computational solid mechanics. The code emphasizes clarity and readability, making it ideal for learning, teaching, and prototyping finite element methods for nonlinear analysis. @@ -35,45 +36,73 @@ The code is open source and intended for educational and scientific purposes. If ### Requirements -- Python 3.9 or higher -- pip package manager +- Python 3.11 or newer +- [uv](https://docs.astral.sh/uv/) (recommended) or pip - Git (for cloning the repository) -### Quick Installation +### Quick Installation (recommended) + +[uv](https://docs.astral.sh/uv/) manages Python, the virtual environment, and dependencies in one step: ```bash # Clone the repository git clone https://github.com/jjcremmers/PyFEM.git cd PyFEM -# Install with pip -pip install . +# Install Python 3.13 (if needed), create .venv, and install PyFEM +uv sync +``` + +Run PyFEM without activating the environment: + +```bash +uv run pyfem --help +cd examples/ch02 +uv run pyfem PatchTest.pro ``` ### Development Installation -For developers who want to make changes and test immediately: +For contributors, `uv sync` installs PyFEM in editable mode together with dev tools (pytest, coverage, ruff): ```bash git clone https://github.com/jjcremmers/PyFEM.git cd PyFEM -pip install -e . +uv sync +uv run coverage run -m pytest -q +uv run coverage report +uv run ruff check pyfem test ``` -### Virtual Environment (Recommended) +Build and verify the wheel (same as CI): ```bash -# Create and activate virtual environment -python3 -m venv pyfem-env -source pyfem-env/bin/activate # Linux/macOS -# or -pyfem-env\Scripts\activate # Windows +uv build +``` + +### Building documentation -# Install PyFEM +CI and Read the Docs use `--no-dev` so only the `docs` extra is installed. Locally, omit `--no-dev` if you want dev tools in the same environment. + +```bash +uv sync --extra docs --no-dev +uv run sphinx-build -M html doc doc/_build +``` + +On Linux, if the doc build fails loading VTK/OpenGL, install `libgl1` (see the [Installation Guide](doc/installation/overview.md)). + +### Alternative: pip + +If you prefer pip, use a virtual environment and install from the repository root: + +```bash +python3 -m venv .venv +source .venv/bin/activate # Linux/macOS +# or: .venv\Scripts\activate # Windows pip install . ``` -For detailed installation instructions including platform-specific notes, see the [Installation Guide](doc/installation/overview.rst). +For detailed installation instructions including platform-specific notes, see the [Installation Guide](doc/installation/overview.md). ## 🚀 Quick Start @@ -99,29 +128,28 @@ paraview PatchTest.pvd ### User Guide -- **[Installation Guide](doc/installation/overview.rst)** - Complete installation instructions -- **[Quick Start Tutorial](doc/tutorials/quickstart.rst)** - Get started with PyFEM -- **[Elements](doc/elements/overview.rst)** - Available element formulations -- **[Materials](doc/materials/overview.rst)** - Material model documentation -- **[Solvers](doc/solvers/overview.rst)** - Solution algorithms -- **[I/O Modules](doc/io/overview.rst)** - Input/output capabilities -- **[Models](doc/models/overview.rst)** - Special models (RVE, contact) +- **[Installation Guide](doc/installation/overview.md)** - Complete installation instructions +- **[Quick Start Tutorial](doc/introduction/quickstart.md)** - Get started with PyFEM +- **[Elements](doc/elements/overview.md)** - Available element formulations +- **[Materials](doc/materials/overview.md)** - Material model documentation +- **[Solvers](doc/solvers/overview.md)** - Solution algorithms +- **[I/O Modules](doc/io/overview.md)** - Input/output capabilities +- **[Models](doc/models/overview.md)** - Special models (RVE, contact) - **[Examples](examples/)** - Collection of example analyses ### Developer Guide For contributors and those extending PyFEM: -- **[Developer's Overview](doc/develop/overview.rst)** - Getting started with development -- **[Implementing Elements](doc/develop/elements_dev.rst)** - Creating new element formulations -- **[Implementing Materials](doc/develop/materials_dev.rst)** - Developing material models -- **[Implementing Solvers](doc/develop/solvers_dev.rst)** - Creating solution algorithms -- **[Implementing I/O Modules](doc/develop/io_dev.rst)** - Adding input/output capabilities +- **[Developer's Overview](doc/develop/overview.md)** - Getting started with development +- **[Implementing Elements](doc/develop/elements_dev.md)** - Creating new element formulations +- **[Implementing Materials](doc/develop/materials_dev.md)** - Developing material models +- **[Implementing Solvers](doc/develop/solvers_dev.md)** - Creating solution algorithms +- **[Implementing I/O Modules](doc/develop/io_dev.md)** - Adding input/output capabilities ### API Reference -- **[API Documentation](doc/api.rst)** - Python API reference -- **[Module Documentation](doc/modules.rst)** - Complete module documentation +- **[API Documentation](https://pyfem.readthedocs.io/en/latest/api/pyfem/index.html)** - Python API reference (generated from source) ## 🎯 Example Gallery @@ -147,7 +175,7 @@ Each directory contains input files (`.pro`), mesh files (`.dat`), and generates ## 🤝 Contributing -Contributions are welcome! Please see the [Developer's Guide](doc/develop/overview.rst) for: +Contributions are welcome! Please see the [Developer's Guide](doc/develop/overview.md) for: - Code style and conventions - Testing guidelines diff --git a/doc/Makefile b/doc/Makefile deleted file mode 100644 index 355dc298..00000000 --- a/doc/Makefile +++ /dev/null @@ -1,26 +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 = . -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 apidoc - -# Auto-generate API documentation from source code -apidoc: - mkdir -p _api - sphinx-apidoc -f -e -M -o _api ../pyfem - @echo "API documentation generated. Run 'make html' to build." - -# 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/README.md b/doc/README.md new file mode 100644 index 00000000..5a77dce1 --- /dev/null +++ b/doc/README.md @@ -0,0 +1,29 @@ +# PyFEM documentation + +Sphinx sources in this directory. Build after installing the package: + +```bash +uv sync --extra docs --no-dev +uv run sphinx-build -M html doc doc/_build +``` + +Output: `doc/_build/html/index.html` + +`--no-dev` matches CI and Read the Docs. For a single environment with pytest/ruff as well, use `uv sync --extra docs` without `--no-dev`. + +API reference is generated at build time by `sphinx-autoapi` under `doc/api/` (gitignored; not committed). + +## Hosting + +- **Read the Docs (primary):** https://pyfem.readthedocs.io/ +- **GitHub Pages (mirror):** built on every PR and push; published only on **push to `main`** via `.github/workflows/ci.yml`. Requires repository **Settings → Pages → Build and deployment → Source: GitHub Actions**. + +## Linux note + +Doc builds may require `libgl1` because Sphinx viewcode imports VTK-related modules. CI and RTD install it via apt. + +Optional live reload (no extra project dependency): + +```bash +uv run --with sphinx-autobuild sphinx-autobuild doc doc/_build/html --watch pyfem --re-ignore "_build/*" +``` diff --git a/doc/_static/custom.css b/doc/_static/custom.css deleted file mode 100644 index 5c74d279..00000000 --- a/doc/_static/custom.css +++ /dev/null @@ -1,3 +0,0 @@ -.wy-side-nav-search .logo { - max-width: 200px; /* Adjust size as needed */ -} diff --git a/doc/conf.py b/doc/conf.py index 490e0fee..656698d9 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -1,87 +1,82 @@ -# Configuration file for the Sphinx documentation builder. -# -# For the full list of built-in configuration values, see the documentation: -# https://www.sphinx-doc.org/en/master/usage/configuration.html +"""Sphinx configuration for PyFEM.""" -# -- Project information ----------------------------------------------------- -# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information +from importlib.metadata import PackageNotFoundError, version as package_version -import os -import sys -sys.path.insert(0, os.path.abspath('../')) +project = "PyFEM" +copyright = "2026, Joris Remmers" -# Auto-generate API documentation -def run_apidoc(_): - from sphinx.ext.apidoc import main - import os - here = os.path.abspath(os.path.dirname(__file__)) - module = os.path.join(here, "..", "pyfem") - output = os.path.join(here, "_build") - if not os.path.exists(output): - os.makedirs(output) - main(['-f', '-e', '-M', '-o', output, module]) +try: + release = package_version("pyfem") +except PackageNotFoundError: + release = "dev" +version = release -def setup(app): - app.connect('builder-inited', run_apidoc) +root_doc = "index" -project = 'PyFEM' -copyright = '2026, Joris Remmers' -author = 'Joris Remmers' - -# Use index.md as master document (MyST) -master_doc = 'index' - -# -- General configuration --------------------------------------------------- -# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration +source_suffix = { + ".md": "markdown", + ".rst": "restructuredtext", +} extensions = [ - 'sphinx.ext.autodoc', # Automatically include docstrings - 'sphinx.ext.viewcode', # Add links to source code - 'sphinx.ext.napoleon', # Support for NumPy/Google-style docstrings - 'sphinx_rtd_theme', # Use the Read the Docs theme - 'sphinx.ext.mathjax', - 'myst_parser', # Support for Markdown files + "myst_parser", + "autoapi.extension", + "sphinx.ext.intersphinx", + "sphinx.ext.mathjax", + "sphinx.ext.napoleon", + "sphinx.ext.viewcode", + "sphinx_copybutton", +] + +exclude_patterns = [ + "_build", + "_api", + "README.md", + "img/README.md", + "Thumbs.db", + ".DS_Store", ] -templates_path = ['_templates'] -exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] +autoapi_dirs = ["../pyfem"] +autoapi_root = "api" +autoapi_add_toctree_entry = True +autoapi_keep_files = False +autoapi_ignore = ["*/gui/*"] -autodoc_default_flags = ['members', 'undoc-members', 'private-members'] -add_module_names = False -autodoc_member_order = 'bysource' +autodoc_mock_imports = ["PySide6", "vtk"] +intersphinx_mapping = { + "python": ("https://docs.python.org/3", None), + "numpy": ("https://numpy.org/doc/stable/", None), + "scipy": ("https://docs.scipy.org/doc/scipy/", None), + "matplotlib": ("https://matplotlib.org/stable/", None), +} -# -- Options for HTML output ------------------------------------------------- -# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output +myst_heading_anchors = 3 -html_theme = 'sphinx_rtd_theme' -html_static_path = ['_static'] -html_logo = "_static/pyfem_logo_official180.png" -html_favicon = "_static/pyfem.ico" -html_css_files = ["custom.css"] +html_theme = "furo" +html_static_path = ["_static"] +html_favicon = "pyfem.ico" html_theme_options = { - 'collapse_navigation': False, - 'navigation_depth': 3, + "light_logo": "pyfem_logo_official180.png", + "dark_logo": "pyfem_logo_official180.png", + "source_repository": "https://github.com/jjcremmers/PyFEM", + "source_branch": "main", + "source_directory": "doc/", } -# -- Options for LaTeX output ------------------------------------------------ -# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-latex-output - latex_elements = { - 'papersize': 'a4paper', - 'pointsize': '11pt', - 'preamble': r''' + "papersize": "a4paper", + "pointsize": "11pt", + "preamble": r""" \usepackage{bookmark} \setcounter{secnumdepth}{2} \setcounter{tocdepth}{3} - ''', - 'figure_align': 'htbp', + """, + "figure_align": "htbp", } +latex_toplevel_sectioning = "chapter" latex_documents = [ - ('index', 'PyFEM.tex', 'PyFEM Documentation', - 'Joris Remmers', 'manual'), + ("index", "PyFEM.tex", "PyFEM Documentation", "Joris Remmers", "manual"), ] - -# Ensure LaTeX handles chapters properly -latex_toplevel_sectioning = 'chapter' diff --git a/doc/develop/overview.md b/doc/develop/overview.md index 025faaa2..dea00f36 100644 --- a/doc/develop/overview.md +++ b/doc/develop/overview.md @@ -221,10 +221,14 @@ Leverage existing utilities: ### Developer Documentation -- [elements_dev.md](elements_dev.md) -- [materials_dev.md](materials_dev.md) -- [solvers_dev.md](solvers_dev.md) -- [io_dev.md](io_dev.md) +```{toctree} +:maxdepth: 1 + +elements_dev.md +materials_dev.md +solvers_dev.md +io_dev.md +``` ## References diff --git a/doc/elements/smallstraincontinuum.md b/doc/elements/smallstraincontinuum.md index 7a7be9b7..c24f5df0 100644 --- a/doc/elements/smallstraincontinuum.md +++ b/doc/elements/smallstraincontinuum.md @@ -143,6 +143,6 @@ examples directory: ## See Also -- [materials documentation](materials.md) - Available material models -- [tutorial1 documentation](tutorial1.md) - Introduction to PyFEM input files -- [elements documentation](elements.md) - Overview of all element types +- [Materials overview](../materials/overview.md) - Available material models +- [Quickstart](../introduction/quickstart.md) - Introduction to PyFEM input files +- [Elements overview](overview.md) - Overview of all element types diff --git a/doc/index.md b/doc/index.md index 4bdccdfb..fd8037a6 100644 --- a/doc/index.md +++ b/doc/index.md @@ -1,6 +1,6 @@ # PyFEM: A Python Finite Element Code -Welcome to the PyFEM documentation. This manual provides comprehensive documentation for PyFEM, a Python-based finite element code for nonlinear finite element analysis. T +Welcome to the PyFEM documentation. This manual provides comprehensive documentation for PyFEM, a Python-based finite element code for nonlinear finite element analysis. ## Documentation Contents @@ -12,11 +12,10 @@ installation/overview.md introduction/quickstart.md usermanual.md develop/overview.md -api.md ``` -## Indices and Tables +## Indices and search -- [General Index](genindex.md) -- [Module Index](modules.md) -- [Search](search.md) +* [Index](genindex) +* [Module Index](py-modindex) +* [Search Page](search) diff --git a/doc/installation/overview.md b/doc/installation/overview.md index e39d578c..0490d90c 100644 --- a/doc/installation/overview.md +++ b/doc/installation/overview.md @@ -6,8 +6,8 @@ Both the **Python API** and the **command-line interface (CLI)** are included. ## Requirements **System Requirements:** -- Python 3.9 or newer -- pip (Python package manager) +- Python 3.11 or newer +- [uv](https://docs.astral.sh/uv/) (recommended) or pip - Git (for cloning the repository) **Python Dependencies** (installed automatically): @@ -19,39 +19,66 @@ Both the **Python API** and the **command-line interface (CLI)** are included. - PySide6 - vtk -**Recommended: Virtual Environment** -It's recommended to install PyFEM in a virtual environment to avoid conflicts with other Python packages: +## Installation with uv (Recommended) + +[uv](https://docs.astral.sh/uv/) installs a compatible Python version, creates a virtual +environment, and installs PyFEM and its dependencies. ```bash -# Create virtual environment -python3 -m venv pyfem-env -# Activate on Linux / macOS -source pyfem-env/bin/activate -# Activate on Windows PowerShell -pyfem-env\Scripts\activate -# Activate on Windows Command Prompt -pyfem-env\Scripts\activate.bat +git clone https://github.com/jjcremmers/PyFEM.git +cd PyFEM +uv sync ``` -## Installation Steps +This creates a `.venv` directory and installs the `pyfem` and `pyfem-gui` commands. +Run them via `uv run`: -### Method 1: Standard Installation (Recommended) ```bash -git clone https://github.com/jjcremmers/PyFEM.git -cd PyFEM +uv run pyfem --help +uv run pyfem-gui +``` + +To activate the environment manually: + +```bash +source .venv/bin/activate # Linux / macOS +.venv\Scripts\activate # Windows +pyfem --help +``` + +### Development setup + +`uv sync` also installs dev tools (pytest, coverage, ruff): + +```bash +uv sync +uv run pytest test/ +uv run coverage run -m pytest -q && uv run coverage report +uv run ruff check pyfem test +uv run ruff format --check pyfem test +uv build +``` + +## Installation with pip + +If you prefer pip, create a virtual environment first: + +```bash +python3 -m venv .venv +source .venv/bin/activate # Linux / macOS +# .venv\Scripts\activate # Windows pip install . ``` -This installs PyFEM and all dependencies, and creates the `pyfem` and `pyfem-gui` command-line executables. -### Method 2: Development Installation +For editable development installs: + ```bash -git clone https://github.com/jjcremmers/PyFEM.git -cd PyFEM pip install -e . +pip install pytest ruff ``` -The `-e` flag installs in "editable" mode, so changes to the source code are immediately reflected without reinstalling. -### Method 3: Direct from GitHub (Advanced) +### Direct from GitHub + ```bash pip install git+https://github.com/jjcremmers/PyFEM.git ``` @@ -144,6 +171,8 @@ converged = globdat.solverStatus.converged ```bash cd PyFEM git pull origin main +uv sync +# Or with pip: pip install --upgrade . # Or if installed directly from GitHub pip install --upgrade git+https://github.com/jjcremmers/PyFEM.git @@ -152,6 +181,8 @@ pip install --upgrade git+https://github.com/jjcremmers/PyFEM.git ## Uninstalling ```bash pip uninstall pyfem +# Or remove the uv-managed environment: +rm -rf .venv ``` ## Troubleshooting @@ -160,38 +191,40 @@ pip uninstall pyfem which pyfem # Linux/macOS where pyfem # Windows ~/.local/bin/pyfem input.pro +# With uv, use: +uv run pyfem input.pro ``` **2. Import errors** ```bash +uv sync --reinstall +# Or with pip: pip install --force-reinstall pyfem ``` -**3. VTK or GUI issues** +**3. VTK, GUI, or documentation build issues** + ```bash -sudo apt-get install libgl1-mesa-glx libxkbcommon-x11-0 # Linux +sudo apt-get install -y libgl1 libxkbcommon-x11-0 # Linux (tests/GUI; libgl1 also needed for doc builds) # On macOS, install XQuartz brew install --cask xquartz ``` **4. Permission errors during installation** -```bash -pip install --user . -``` +Use a virtual environment (`uv sync` or `python -m venv .venv`) rather than installing system-wide. ## Platform-Specific Notes **Linux:** ```bash -sudo apt-get install python3-venv python3-pip # Debian/Ubuntu -sudo dnf install python3-virtualenv python3-pip # Fedora/RHEL +# uv installs its own Python; no system packages required for the venv +curl -LsSf https://astral.sh/uv/install.sh | sh ``` **macOS:** ```bash -brew install python@3.11 -brew install --cask xquartz +brew install uv +brew install --cask xquartz # for GUI / VTK ``` **Windows:** -1. Install Python 3.9+ from [python.org](https://www.python.org/downloads/) -2. Ensure "Add Python to PATH" is checked -3. Use PowerShell or Command Prompt -4. Install Git for Windows: [git-scm.com](https://git-scm.com/) +1. Install [uv](https://docs.astral.sh/uv/getting-started/installation/) +2. Use PowerShell or Command Prompt +3. Install Git for Windows: [git-scm.com](https://git-scm.com/) ## Running Examples ```bash @@ -207,24 +240,27 @@ Each example directory contains: - `.dat` files: Mesh files - Output files: VTK, text, plots -## Development Setup -```bash -git clone https://github.com/jjcremmers/PyFEM.git -cd PyFEM -pip install -e . -python -m pytest test/ -python -m black pyfem/ -python -m mypy pyfem/ -``` - ## Getting Help - **Documentation**: https://pyfem.readthedocs.io/ - **GitHub Issues**: https://github.com/jjcremmers/PyFEM/issues - **Examples**: See the `examples/` directory - **Book**: "Non-Linear Finite Element Analysis of Solids and Structures" by de Borst et al., John Wiley & Sons, 2012 +## Building documentation + +Same install path as CI and Read the Docs: + +```bash +uv sync --extra docs --no-dev +uv run sphinx-build -M html doc doc/_build +``` + +Open `doc/_build/html/index.html`. API reference is generated by `sphinx-autoapi` at build time (under `doc/api/`, gitignored). + +On Linux, install `libgl1` if the build fails when loading VTK modules for viewcode. + ## Next Steps 1. Read the [Quickstart guide](../introduction/quickstart.md) 2. Explore examples in the `examples/` directory -3. Review the [module documentation](../pyfem.md) +3. Review the [API reference](https://pyfem.readthedocs.io/en/latest/api/pyfem/index.html) 4. For development, see the [developer overview](../develop/overview.md) diff --git a/doc/introduction/about.md b/doc/introduction/about.md deleted file mode 100644 index b4c5de73..00000000 --- a/doc/introduction/about.md +++ /dev/null @@ -1,24 +0,0 @@ -# About the Code - -This is the user manual for PyFEM, a Python-based finite element code accompanying the book: - -**R. de Borst, M.A. Crisfield, J.J.C. Remmers and C.V. Verhoosel** -[Non-Linear Finite Element Analysis of Solids and Structures](https://www.wiley.com/en-us/Nonlinear+Finite+Element+Analysis+of+Solids+and+Structures%2C+2nd+Edition-p-9780470666449) -John Wiley and Sons, 2012, ISBN 978-0470666449 - - - -PyFEM is open source and intended for educational and scientific purposes only. If you use PyFEM in your research, the developers would be grateful if you could cite the book in your work. - -## Goals and Scope - -PyFEM aims to provide a clear, well-documented reference implementation for nonlinear finite element analysis, suited for teaching, prototyping, and reproducible research. The code emphasizes readability over micro-optimizations and includes a growing set of elements, material models, solvers, and I/O modules to cover common solid mechanics problems. - -## How to Cite - -If PyFEM contributes to a publication, please cite the textbook above and reference PyFEM (with the commit/tag or release) to ensure reproducibility. When applicable, include the specific modules (elements, materials, solvers) used in your study. - -J.J.C. Remmers (2025). PyFEM [https://github.com/jjcremmers/PyFEM](https://github.com/jjcremmers/PyFEM) - -R. de Borst, M.A. Crisfield, J.J.C. Remmers and C.V. Verhoosel (2012) -[Non-Linear Finite Element Analysis of Solids and Structures](https://www.wiley.com/en-us/Nonlinear+Finite+Element+Analysis+of+Solids+and+Structures%2C+2nd+Edition-p-9780470666449) diff --git a/doc/introduction/api.md b/doc/introduction/api.md deleted file mode 100644 index b0dd4a13..00000000 --- a/doc/introduction/api.md +++ /dev/null @@ -1,5 +0,0 @@ -# API Documentation - -This section provides the complete API reference for PyFEM, automatically generated from the source code documentation. - -See [pyfem](pyfem.md) for details. diff --git a/doc/introduction/introduction.md b/doc/introduction/introduction.md index 510ac67d..f7a1b0bc 100644 --- a/doc/introduction/introduction.md +++ b/doc/introduction/introduction.md @@ -114,7 +114,7 @@ If you need environment setup details or platform-specific notes, refer to the ## License PyFEM is released under the MIT License, enabling broad use for education and research. -For full license details, see the [LICENSE](../LICENSE) file. +For full license details, see the [LICENSE](../../LICENSE) file. Under the MIT License terms, you may use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the software, provided that you @@ -124,7 +124,7 @@ include the copyright notice and permission notice. The software is provided ### Important - The official PyFEM repository and its releases are licensed under the MIT - License as described above (see [LICENSE](../LICENSE)). + License as described above (see [LICENSE](../../LICENSE)). - If you obtain PyFEM as part of a third-party distribution, fork, or bundled project, the licensing of that distribution may differ; always consult that project's license in addition to the original MIT-licensed PyFEM sources. diff --git a/doc/introduction/quickstart.md b/doc/introduction/quickstart.md index 2ef70aae..a8c9b75a 100644 --- a/doc/introduction/quickstart.md +++ b/doc/introduction/quickstart.md @@ -12,13 +12,13 @@ and run your first simulation. cd PyFEM ``` -2. Install PyFEM and its dependencies: +2. Install PyFEM and its dependencies with [uv](https://docs.astral.sh/uv/): ```bash - pip install . + uv sync ``` - This installs the `pyfem` command-line tool and all required packages. + This installs the `pyfem` command-line tool and all required packages into `.venv`. ## Verifying the Installation diff --git a/doc/make.bat b/doc/make.bat deleted file mode 100644 index 954237b9..00000000 --- a/doc/make.bat +++ /dev/null @@ -1,35 +0,0 @@ -@ECHO OFF - -pushd %~dp0 - -REM Command file for Sphinx documentation - -if "%SPHINXBUILD%" == "" ( - set SPHINXBUILD=sphinx-build -) -set SOURCEDIR=. -set BUILDDIR=_build - -%SPHINXBUILD% >NUL 2>NUL -if errorlevel 9009 ( - echo. - echo.The 'sphinx-build' command was not found. Make sure you have Sphinx - echo.installed, then set the SPHINXBUILD environment variable to point - echo.to the full path of the 'sphinx-build' executable. Alternatively you - echo.may add the Sphinx directory to PATH. - echo. - echo.If you don't have Sphinx installed, grab it from - echo.https://www.sphinx-doc.org/ - exit /b 1 -) - -if "%1" == "" goto help - -%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% -goto end - -:help -%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% - -:end -popd diff --git a/doc/models/overview.md b/doc/models/overview.md index 5dc0178f..082c6921 100644 --- a/doc/models/overview.md +++ b/doc/models/overview.md @@ -20,3 +20,12 @@ model_name = { }; ``` Multiple models can be active simultaneously, each handling different aspects of the analysis. + +## Available model pages + +```{toctree} +:maxdepth: 1 + +rve.md +contact.md +``` diff --git a/doc/pyfem.html b/doc/pyfem.html deleted file mode 100644 index 6d89829d..00000000 --- a/doc/pyfem.html +++ /dev/null @@ -1,10 +0,0 @@ - - -
- - - -Redirecting to PyFEM…
- - - diff --git a/doc/requirements.txt b/doc/requirements.txt deleted file mode 100644 index a63928a0..00000000 --- a/doc/requirements.txt +++ /dev/null @@ -1,20 +0,0 @@ -# Sphinx documentation requirements for Read the Docs - -# Core Sphinx -sphinx>=5.0.0,<8.0.0 - -# Theme -sphinx-rtd-theme>=1.2.0 - -# Extensions -sphinx-autoapi>=2.0.0 - -# Math rendering -docutils>=0.18 - -# Python dependencies needed for autodoc -numpy>=1.20.0 -scipy>=1.7.0 -matplotlib>=3.3.0 -h5py>=3.0.0 -meshio>=5.0.0 diff --git a/doc/tutorials/dissnrg_tutorial.md b/doc/tutorials/dissnrg_tutorial.md index 7ce80c71..be3ea94a 100644 --- a/doc/tutorials/dissnrg_tutorial.md +++ b/doc/tutorials/dissnrg_tutorial.md @@ -16,6 +16,4 @@ These input files can be executed by typing: pyfem delam_buckling200.pro ``` -The result load displacement curve will look as follows: - - +The result load–displacement curve shows snap-back behavior typical of delamination buckling. Run the example and inspect the solver output or plot files written to the working directory. diff --git a/doc/tutorials/gmsh_input_tutorial.md b/doc/tutorials/gmsh_input_tutorial.md index 11bc365f..b1d5b3dd 100644 --- a/doc/tutorials/gmsh_input_tutorial.md +++ b/doc/tutorials/gmsh_input_tutorial.md @@ -1,6 +1,6 @@ # Tutorial: Using GMSH Input Files in PyFEM -This tutorial explains how to use GMSH-generated meshes as input for PyFEM, based on the examples in the [examples/gmsh](../../examples/gmsh) directory. We will walk through the structure of the input files and how to set up a simulation using GMSH meshes. +This tutorial explains how to use GMSH-generated meshes as input for PyFEM, based on the examples in the `examples/gmsh/` directory. We will walk through the structure of the input files and how to set up a simulation using GMSH meshes. ## 1. Overview of Files @@ -15,7 +15,7 @@ A typical GMSH-based example in PyFEM consists of: Write a geometry file (e.g., [two_fibres.geo](../../examples/gmsh/two_fibres.geo)): -```geo +```text lc = 0.25; Point(1) = { 0.0, 0.0, 0.0, lc }; Point(2) = { 10.0, 0.0, 0.0, lc }; @@ -80,8 +80,8 @@ paraview two_fibres.pvd - Always define physical groups in your `.geo` file for all regions where you want to apply boundary conditions or loads. - Use GMSH's GUI to inspect and assign physical groups interactively. -- For advanced setups, see the `.pro` files (e.g., [twist.pro](../../examples/gmsh/twist.pro) or [two_fibres.pro](../../examples/gmsh/two_fibres.pro)) or the [PyFEM documentation](../../README.md). +- For advanced setups, see the `.pro` files (e.g., [twist.pro](../../examples/gmsh/twist.pro) or [two_fibres.pro](../../examples/gmsh/two_fibres.pro)) or the [PyFEM documentation](../index.md). --- -For more details, see the [examples/gmsh](../../examples/gmsh) directory and the PyFEM documentation. +For more examples, see the `examples/gmsh/` directory in the repository. diff --git a/doc/usermanual.md b/doc/usermanual.md index e33a9769..15550fea 100644 --- a/doc/usermanual.md +++ b/doc/usermanual.md @@ -9,6 +9,7 @@ elements/overview.md materials/overview.md solvers/overview.md io/overview.md +models/overview.md tutorials/overview.md ``` diff --git a/pyfem/__init__.py b/pyfem/__init__.py index ec5dcacb..b4606437 100644 --- a/pyfem/__init__.py +++ b/pyfem/__init__.py @@ -1,7 +1,9 @@ +from importlib.metadata import version + from .core.api import run from .fem.NodeSet import NodeSet from .fem.ElementSet import ElementSet -__all__ = ["run","NodeSet","ElementSet"] -__version__ = "0.1.0" +__all__ = ["run", "NodeSet", "ElementSet"] +__version__ = version("pyfem") diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000..004e0acf --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,77 @@ +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[project] +name = "pyfem" +version = "3.0.0" +description = "A Python finite element code (educational)" +readme = "README.md" +requires-python = ">=3.11" +license = "MIT" +license-files = ["LICENSE"] +authors = [{ name = "J.J.C. Remmers" }] +keywords = ["finite-element", "computational-mechanics", "nonlinear-analysis"] +classifiers = [ + "Development Status :: 4 - Beta", + "Intended Audience :: Science/Research", + "Intended Audience :: Education", + "License :: OSI Approved :: MIT License", + "Operating System :: OS Independent", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3 :: Only", + "Topic :: Scientific/Engineering", + "Topic :: Scientific/Engineering :: Physics", +] +dependencies = [ + "h5py", + "matplotlib", + "meshio", + "numpy", + "PySide6", + "scipy", + "vtk", +] + +[project.urls] +Changelog = "https://github.com/jjcremmers/PyFEM/releases" +Documentation = "https://pyfem.readthedocs.io/" +Homepage = "https://github.com/jjcremmers/PyFEM" +Issues = "https://github.com/jjcremmers/PyFEM/issues" +Repository = "https://github.com/jjcremmers/PyFEM" + +[project.scripts] +pyfem = "pyfem.core.cli:main" +pyfem-gui = "pyfem.gui.app:main" + +[project.optional-dependencies] +docs = [ + "furo>=2024.8.6", + "myst-parser>=4.0.0", + "sphinx>=9.0.0", + "sphinx-autoapi>=3.0.0", + "sphinx-copybutton>=0.5.0", +] + +[dependency-groups] +dev = [ + "coverage>=7", + "pytest>=8", + "ruff>=0.9", +] + +[tool.hatch.build.targets.wheel] +packages = ["pyfem"] + +[tool.pytest.ini_options] +testpaths = ["test"] +python_files = ["test*.py", "*_test.py"] +python_classes = ["Test*"] +python_functions = ["test_*"] + +[tool.ruff] +line-length = 88 +target-version = "py311" + +[tool.uv] +default-groups = ["dev"] diff --git a/setup.py b/setup.py deleted file mode 100644 index 9e05b0a9..00000000 --- a/setup.py +++ /dev/null @@ -1,56 +0,0 @@ -# setup.py -from pathlib import Path -from setuptools import setup, find_packages - -README = Path(__file__).with_name("README.md") -long_description = README.read_text(encoding="utf-8") if README.exists() else "" - -setup( - name="pyfem", - version="3.00", - description="A Python finite element code (educational)", - long_description=long_description, - long_description_content_type="text/markdown", - url="https://github.com/jjcremmers/PyFEM", - author="J.J.C. Remmers", - license="GPL-3.0-only", - packages=find_packages(include=["pyfem", "pyfem.*"]), - include_package_data=True, # works with MANIFEST.in if you add one - python_requires=">=3.9", - install_requires=[ - "numpy", - "scipy", - "matplotlib", - "meshio", - "h5py", - "PySide6", - "vtk", - #"pyyaml", # if you load YAML props in api.py - # add other runtime deps used by pyfem/* - ], - #extras_require={ - # "dev": [ - # "pytest", - # "black", - # "mypy", - # ], - #}, - entry_points={ - "console_scripts": [ - "pyfem=pyfem.core.cli:main", - "pyfem-gui=pyfem.gui.app:main" - ], - }, - classifiers=[ - "Programming Language :: Python :: 3", - "License :: OSI Approved :: GNU General Public License v3 (GPLv3)", - "Operating System :: OS Independent", - "Topic :: Scientific/Engineering", - ], - project_urls={ - "Homepage": "https://github.com/jjcremmers/PyFEM", - "Issues": "https://github.com/jjcremmers/PyFEM/issues", - }, - zip_safe=False, -) - From dc73196c2a3e8ce29d7b33506689a4a192074002 Mon Sep 17 00:00:00 2001 From: sora <210at85@gmail.com> Date: Wed, 27 May 2026 23:52:59 +0800 Subject: [PATCH 2/2] Align README and quickstart with uv run workflow Use uv run pyfem and uv run pytest in user-facing docs so they match the installation guide and PR contributor commands. Co-authored-by: Cursor