diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..88ef189f --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,113 @@ +name: CI + +on: + push: + branches: [main] + pull_request: + branches: [main] + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: ci-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + test: + name: Python ${{ matrix.python-version }} + runs-on: ubuntu-latest + timeout-minutes: 15 + strategy: + fail-fast: false + matrix: + python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"] + steps: + - uses: actions/checkout@v7 + - 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 --extra dev + - run: uv run --no-sync coverage run -m pytest -q + - run: uv run --no-sync coverage report + - name: Smoke test CLI and example + run: | + uv run --no-sync pyfem --help + uv run --no-sync pyfem --version + mkdir -p "$RUNNER_TEMP/pyfem-smoke" + cp examples/ch02/PatchTest8.pro examples/ch02/PatchTest8.dat "$RUNNER_TEMP/pyfem-smoke/" + cd "$RUNNER_TEMP/pyfem-smoke" + "$GITHUB_WORKSPACE/.venv/bin/pyfem" PatchTest8.pro + + build: + name: Build package + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - uses: actions/checkout@v7 + - uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0 + with: + python-version: "3.14" + enable-cache: true + cache-suffix: build + - run: uv build + - name: Verify wheel installs + run: | + uv venv "$RUNNER_TEMP/pyfem-wheel-check" + uv pip install --python "$RUNNER_TEMP/pyfem-wheel-check" dist/*.whl + cd "$RUNNER_TEMP" + "$RUNNER_TEMP/pyfem-wheel-check/bin/python" -c "import pyfem; from importlib.metadata import version; assert pyfem.__version__ == version('pyfem')" + "$RUNNER_TEMP/pyfem-wheel-check/bin/pyfem" --help + - uses: actions/upload-artifact@v7 + with: + name: dist + path: dist/ + + docs: + name: Build documentation + runs-on: ubuntu-latest + timeout-minutes: 15 + steps: + - uses: actions/checkout@v7 + - uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0 + with: + python-version: "3.14" + 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 + - run: uv run --no-sync sphinx-build -b html doc doc/_build/html + - name: Upload Pages artifact + if: github.event_name == 'push' && github.ref == 'refs/heads/main' + uses: actions/upload-pages-artifact@v5 + 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@v5 + id: deployment diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml deleted file mode 100644 index 097ae02e..00000000 --- a/.github/workflows/documentation.yml +++ /dev/null @@ -1,28 +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: | - python -m pip install --upgrade pip - python -m pip install -e ".[docs]" - - 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 263e4b2e..00000000 --- a/.github/workflows/pytest.yml +++ /dev/null @@ -1,47 +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.10", "3.11", "3.12", "3.14" ] - - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Set up Python - uses: actions/setup-python@v5 - with: - python-version: ${{ matrix.python-version }} - - - name: Install package - run: | - python -m pip install --upgrade pip - python -m pip install -e ".[dev]" - - - name: Smoke test installed package - run: | - python -c "import pyfem; from importlib.metadata import version; assert pyfem.__version__ == version('pyfem')" - pyfem --help - mkdir -p /tmp/pyfem-smoke - cp examples/ch02/PatchTest8.pro examples/ch02/PatchTest8.dat /tmp/pyfem-smoke/ - cd /tmp/pyfem-smoke - pyfem PatchTest8.pro - - - name: Build package - run: | - python -m build --sdist --wheel --outdir /tmp/pyfem-dist - - - name: Run tests - run: | - coverage run -m pytest test - coverage report diff --git a/.gitignore b/.gitignore index a59bddb7..91008dec 100644 --- a/.gitignore +++ b/.gitignore @@ -124,6 +124,7 @@ celerybeat-schedule # Environments .env .venv +uv.lock env/ venv/ ENV/ diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 340edefc..b75eec5f 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -1,35 +1,26 @@ # 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.14" + 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: + - method: uv + command: sync + extras: - docs -# Formats to build (PDF, EPUB, etc.) formats: - pdf - epub diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c9776d10..865a02db 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -63,29 +63,37 @@ git clone https://github.com//PyFEM.git cd PyFEM ``` -Create and activate a virtual environment: +Use Python 3.10 or newer. + +For local development, use [uv](https://docs.astral.sh/uv/) to create a virtual +environment and install the test tools: ```bash -python -m venv pyfem-env +uv sync --extra dev +uv run --no-sync pytest -q ``` -On Linux or macOS: +To include the optional GUI, add `--extra gui` to `uv sync`. + +If you prefer pip, create and activate a virtual environment on Linux or macOS: ```bash +python -m venv pyfem-env source pyfem-env/bin/activate ``` On Windows PowerShell: ```powershell -pyfem-env\Scripts\Activate.ps1 +py -m venv pyfem-env +.\pyfem-env\Scripts\Activate.ps1 ``` -Install PyFEM in editable mode: +Then install PyFEM in editable mode with the development extra: ```bash python -m pip install --upgrade pip -pip install -e . +python -m pip install -e ".[dev]" ``` Create a branch for your contribution: @@ -159,10 +167,11 @@ added, explain in the pull request how the change was verified. The canonical local test command is: ```bash -python -m pytest test +uv run --no-sync pytest -q ``` -The test suite also supports the standard-library unittest runner: +If using the pip environment, run `python -m pytest test`. The test suite also +supports the standard-library unittest runner: ```bash python -m unittest discover -s test -p "*.py" diff --git a/README.md b/README.md index 18255d18..52cf9de2 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,9 @@ # PyFEM: A Python Finite Element Code -[![Python Version](https://img.shields.io/badge/python-3.9%2B-blue.svg)](https://www.python.org/downloads/) +[![Python Version](https://img.shields.io/badge/python-3.10%2B-blue.svg)](https://www.python.org/downloads/) +[![CI](https://github.com/jjcremmers/PyFEM/actions/workflows/ci.yml/badge.svg)](https://github.com/jjcremmers/PyFEM/actions/workflows/ci.yml) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE) -[![Documentation](https://img.shields.io/badge/docs-latest-brightgreen.svg)](https://github.com/jjcremmers/PyFEM/tree/main/doc) +[![Documentation](https://img.shields.io/badge/docs-readthedocs-brightgreen.svg)](https://pyfem.readthedocs.io/) [![GitHub Stars](https://img.shields.io/github/stars/jjcremmers/PyFEM?style=social)](https://github.com/jjcremmers/PyFEM/stargazers) [![GitHub Issues](https://img.shields.io/github/issues/jjcremmers/PyFEM)](https://github.com/jjcremmers/PyFEM/issues) [![Cite](https://img.shields.io/badge/Cite-How%20to%20cite-blue.svg)](CITATION.cff) @@ -35,61 +36,60 @@ The code is open source and intended for educational and scientific purposes. If ### Requirements -- Python 3.9 or higher -- pip package manager +- Python 3.10 or higher +- [uv](https://docs.astral.sh/uv/) for the commands below, or pip - Git (for cloning the repository) ### Quick Installation ```bash -# Clone the repository git clone https://github.com/jjcremmers/PyFEM.git cd PyFEM - -# Install with pip -pip install . +uv sync +uv run pyfem --help ``` -The base installation includes VTK output support for ParaView. The graphical -user interface dependency is optional. - -For the GUI, install: +`uv sync` creates `.venv` and installs the package in editable mode. The base +installation includes VTK output support for ParaView. The GUI is optional: ```bash -pip install ".[gui]" +uv sync --extra gui +uv run --no-sync pyfem-gui ``` -To install all optional dependencies: +### Development Installation + +For contributors, install the test tools and run the suite: ```bash -pip install ".[all]" +uv sync --extra dev +uv run --no-sync pytest -q ``` -### Development Installation +Add `--extra gui` to the sync command when developing the GUI. -For developers who want to make changes and test immediately: +### Building documentation ```bash -git clone https://github.com/jjcremmers/PyFEM.git -cd PyFEM -pip install -e ".[dev]" +uv sync --extra docs +uv run --no-sync sphinx-build -b html doc doc/_build/html ``` -For development with the GUI as well, use `pip install -e ".[dev,all]"`. +The output is `doc/_build/html/index.html`. See [doc/README.md](doc/README.md) +for hosting details. -### Virtual Environment (Recommended) +### Installation with pip ```bash -# Create and activate virtual environment -python3 -m venv pyfem-env -source pyfem-env/bin/activate # Linux/macOS -# or -pyfem-env\Scripts\activate # Windows - -# Install PyFEM +python3 -m venv .venv +source .venv/bin/activate # Linux/macOS pip install . ``` +On Windows Command Prompt, use `py -m venv .venv` and +`.venv\Scripts\activate.bat` before `pip install .`. For the optional GUI, +install `pip install ".[gui]"`. + For detailed installation instructions including platform-specific notes, see the [Installation Guide](doc/installation/overview.md). ## 🚀 Quick Start @@ -103,17 +103,17 @@ Run a PyFEM analysis from the command line: cd examples/ch02 # Run an example -pyfem PatchTest8.pro +uv run pyfem PatchTest8.pro ``` Useful command-line options: ```bash -pyfem --help # Show help -pyfem --version # Show installed PyFEM version -pyfem -i input.pro # Specify input file -pyfem -d state.dump # Restart from dump file -pyfem -p param=value # Override parameter +uv run pyfem --help # Show help +uv run pyfem --version # Show installed PyFEM version +uv run pyfem -i input.pro # Specify input file +uv run pyfem -d state.dump # Restart from dump file +uv run pyfem -p param=value # Override parameter ``` View results in [ParaView](https://www.paraview.org/download/): @@ -127,7 +127,7 @@ paraview PatchTest8.pvd ### User Guide - **[Installation Guide](doc/installation/overview.md)** - Complete installation instructions -- **[Quick Start Tutorial](doc/tutorials/quickstart.md)** - Get started with PyFEM +- **[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 @@ -147,7 +147,7 @@ For contributors and those extending PyFEM: ### API Reference -- **[API Documentation](doc/introduction/api.md)** - Python API reference +- **[API Documentation](https://pyfem.readthedocs.io/en/latest/api/pyfem/index.html)** - Generated Python API reference - **[Documentation Index](doc/index.md)** - Full documentation table of contents ## 🎯 Example Gallery 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..e6bafa9c --- /dev/null +++ b/doc/README.md @@ -0,0 +1,23 @@ +# PyFEM documentation + +Sphinx sources in this directory. Build after installing the package: + +```bash +uv sync --extra docs +uv run --no-sync sphinx-build -b html doc doc/_build/html +``` + +Output: `doc/_build/html/index.html` + +CI and Read the Docs use the same documentation extra. To install contributor tools as well, add `--extra dev` to `uv sync`. + +The API reference is generated by `sphinx-autoapi` during the Sphinx build. + +## Hosting + +- **Read the Docs (primary):** https://pyfem.readthedocs.io/ +- **GitHub Pages (mirror):** built in CI and published from `main` with GitHub's Pages deployment actions. Set repository **Settings → Pages → Build and deployment → Source** to **GitHub Actions** when merging this workflow. + +## Linux note + +Doc builds may require `libgl1` because Sphinx imports VTK-related modules. CI and RTD install it via apt. 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 cb5561c8..36af1a6c 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -1,87 +1,80 @@ -# 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", ] -templates_path = ['_templates'] -exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] - -autodoc_default_flags = ['members', 'undoc-members', 'private-members'] -add_module_names = False -autodoc_member_order = 'bysource' +exclude_patterns = [ + "_build", + "_api", + "README.md", + "img/README.md", + "Thumbs.db", + ".DS_Store", +] +autoapi_dirs = ["../pyfem"] +autoapi_root = "api" +autoapi_add_toctree_entry = True +autoapi_keep_files = False +autoapi_ignore = ["*/gui/*"] + +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.png" +html_theme = "furo" +html_static_path = ["_static"] html_favicon = "_static/pyfem.ico" -html_css_files = ["custom.css"] html_theme_options = { - 'collapse_navigation': False, - 'navigation_depth': 3, + "light_logo": "pyfem_logo.png", + "dark_logo": "pyfem_logo.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..cb8fab73 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 describes the Python 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) +- [General Index](genindex) +- [Module Index](py-modindex) +- [Search](search) diff --git a/doc/installation/overview.md b/doc/installation/overview.md index 5ee0a29c..e16a2964 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.10 or newer +- [uv](https://docs.astral.sh/uv/) for the recommended workflow, or pip - Git (for cloning the repository) **Python Dependencies** (installed automatically): @@ -21,56 +21,66 @@ Both the **Python API** and the **command-line interface (CLI)** are included. **Optional Dependencies:** - `PySide6`: graphical user interface support -**Recommended: Virtual Environment** -It's recommended to install PyFEM in a virtual environment to avoid conflicts with other Python packages: +## Installation with uv + +From the repository root, uv creates a virtual environment and installs PyFEM: ```bash -# Create virtual environment -python3 -m venv pyfem-env -# Activate on Linux / macOS -source pyfem-env/bin/activate +git clone https://github.com/jjcremmers/PyFEM.git +cd PyFEM +uv sync +uv run pyfem --help ``` -On Windows, use **Command Prompt** (`cmd.exe`) and activate the environment with: +The package is installed in editable mode. To add the optional GUI: -```cmd -py -m venv pyfem-env -pyfem-env\Scripts\activate.bat +```bash +uv sync --extra gui +uv run --no-sync pyfem-gui ``` -## Installation Steps +### Development setup -### Method 1: Standard Installation (Recommended) ```bash -git clone https://github.com/jjcremmers/PyFEM.git -cd PyFEM -pip install . +uv sync --extra dev +uv run --no-sync pytest -q +uv build ``` -This installs PyFEM with its core dependencies, including VTK output support for -ParaView, and creates the `pyfem` command-line executable. -To install the GUI dependencies: +Add `--extra gui` to `uv sync` when developing the GUI. + +## Installation with pip + +Create a virtual environment first. On Linux or macOS: ```bash -pip install ".[gui]" +python3 -m venv .venv +source .venv/bin/activate +pip install . ``` -To install all optional dependencies: +On Windows Command Prompt: + +```text +py -m venv .venv +.venv\Scripts\activate.bat +python -m pip install . +``` + +This installs the core package and the `pyfem` command. When using pip in an +activated environment, run `pyfem` directly. For the GUI, run: ```bash -pip install ".[all]" +pip install ".[gui]" ``` -### Method 2: Development Installation +For an editable development installation with test tools: + ```bash -git clone https://github.com/jjcremmers/PyFEM.git -cd PyFEM pip install -e ".[dev]" ``` -The `-e` flag installs in "editable" mode, so changes to the source code are immediately reflected without reinstalling. -For development with the GUI as well, use `pip install -e ".[dev,all]"`. -### Method 3: Direct from GitHub (Advanced) +### Direct from GitHub ```bash pip install git+https://github.com/jjcremmers/PyFEM.git ``` @@ -81,9 +91,9 @@ After installation, verify that both the CLI and API work correctly. ### Checking the CLI ```bash -pyfem --help +uv run pyfem --help cd examples/ch02 -pyfem PatchTest8.pro +uv run pyfem PatchTest8.pro ``` Expected output includes solver iterations, convergence information, and generated output files. @@ -100,21 +110,22 @@ If both tests complete without errors, the installation is successful. ### Command-Line Interface (CLI) **Basic Usage:** ```bash -pyfem input_file.pro +uv run pyfem input_file.pro ``` **Command-Line Options:** ```bash -pyfem --help # Show help -pyfem --version # Show installed PyFEM version -pyfem -i input.pro # Specify input file -pyfem -d state.dump # Restart from dump file -pyfem -p param=value # Override parameter +uv run pyfem --help # Show help +uv run pyfem --version # Show installed PyFEM version +uv run pyfem -i input.pro # Specify input file +uv run pyfem -d state.dump # Restart from dump file +uv run pyfem -p param=value # Override parameter ``` **Examples:** ```bash -pyfem examples/ch03/cantilever8.pro -pyfem -d results_cycle100.dump -pyfem -i model.pro -p E=210000 +cd examples/ch03 +uv run pyfem cantilever8.pro +uv run pyfem -d results_cycle100.dump +uv run pyfem -i model.pro -p E=210000 ``` ### Python API @@ -164,6 +175,8 @@ converged = globdat.solverStatus.converged ```bash cd PyFEM git pull origin main +uv sync +# Or, with pip in an activated environment: pip install --upgrade . # Or if installed directly from GitHub pip install --upgrade git+https://github.com/jjcremmers/PyFEM.git @@ -179,22 +192,23 @@ pip uninstall pyfem ```bash which pyfem # Linux/macOS where pyfem # Windows -~/.local/bin/pyfem input.pro +uv run pyfem input.pro ``` **2. Import errors** ```bash -pip install --force-reinstall pyfem +uv sync --reinstall +# Or, with pip from the repository root: +pip install --force-reinstall . ``` **3. VTK or GUI issues** ```bash -sudo apt-get install libgl1-mesa-glx libxkbcommon-x11-0 # Linux +sudo apt-get install libgl1 libxkbcommon-x11-0 # Linux # On macOS, install XQuartz brew install --cask xquartz ``` **4. Permission errors during installation** -```bash -pip install --user . -``` +Use `uv sync` or an activated virtual environment instead of installing into +the system Python. ## Platform-Specific Notes **Linux:** @@ -208,13 +222,13 @@ brew install python@3.11 brew install --cask xquartz ``` **Windows:** -1. Install Python 3.9+ from [python.org](https://www.python.org/downloads/) +1. Install Python 3.10+ from [python.org](https://www.python.org/downloads/) 2. Ensure "Add Python to PATH" is checked 3. Open **Command Prompt** (`cmd.exe`) 4. Install Git for Windows: [git-scm.com](https://git-scm.com/) 5. Run the installation commands from Command Prompt: - ```cmd + ```text git clone https://github.com/jjcremmers/PyFEM.git cd PyFEM py -m venv pyfem-env @@ -226,9 +240,9 @@ brew install --cask xquartz ```bash cd examples cd ch02 -pyfem PatchTest8.pro -cd ch03 -pyfem cantilever8.pro +uv run pyfem PatchTest8.pro +cd ../ch03 +uv run pyfem cantilever8.pro paraview cantilever8.pvd ``` Each example directory contains: @@ -236,16 +250,16 @@ Each example directory contains: - `.dat` files: Mesh files - Output files: VTK, text, plots -## Development Setup +## Building documentation + ```bash -git clone https://github.com/jjcremmers/PyFEM.git -cd PyFEM -pip install -e ".[dev]" -python -m pytest test/ -python -m black pyfem/ -python -m mypy pyfem/ +uv sync --extra docs +uv run --no-sync sphinx-build -b html doc doc/_build/html ``` +Open `doc/_build/html/index.html`. The API reference is generated from source +by Sphinx. On Linux, install `libgl1` if VTK cannot load during the build. + ## Getting Help - **Documentation**: https://pyfem.readthedocs.io/ - **GitHub Issues**: https://github.com/jjcremmers/PyFEM/issues @@ -255,5 +269,5 @@ python -m mypy pyfem/ ## 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 [generated 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 - -![The cover of Non-linear Finite Element Analysis of Solids and Structures](https://media.wiley.com/product_data/coverImage300/47/04706664/0470666447.jpg) - -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 1d27b024..a01b35d1 100644 --- a/doc/introduction/quickstart.md +++ b/doc/introduction/quickstart.md @@ -12,15 +12,15 @@ 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, VTK output support, and all - required core packages. To install the optional GUI dependency, use - `pip install ".[gui]"`. + This creates `.venv` and installs the `pyfem` command, VTK output support, + and the required core packages. To add the optional GUI, run + `uv sync --extra gui`. ## Verifying the Installation @@ -29,7 +29,7 @@ standalone example script: ```bash cd examples/ch02 -python PatchTest.py +uv run python PatchTest.py ``` You can then run a full PyFEM model from a `.pro` input file. @@ -40,7 +40,7 @@ After installation, run a basic example to verify everything works: ```bash cd examples/ch02 -pyfem PatchTest8.pro +uv run pyfem PatchTest8.pro ``` This runs a simple patch test. You should see solver output showing convergence @@ -54,11 +54,11 @@ cd examples # Run a nonlinear truss analysis cd ch04 -pyfem ShallowtrussRiks.pro +uv run pyfem ShallowtrussRiks.pro # Run a cantilever beam example cd ../ch03 -pyfem cantilever8.pro +uv run pyfem cantilever8.pro ``` Each example produces output files (VTK format for visualization, graphs, etc.) 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/requirements.txt b/doc/requirements.txt deleted file mode 100644 index d08a17b8..00000000 --- a/doc/requirements.txt +++ /dev/null @@ -1,21 +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 -myst-parser>=2.0.0 -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..e85e3682 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: - -![Delamination Buckling Result](img/delam_buckling200.png) +Run the example and inspect the output in 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/tutorials/index.md b/doc/tutorials/index.md index 90af8b64..bc19118a 100644 --- a/doc/tutorials/index.md +++ b/doc/tutorials/index.md @@ -44,6 +44,12 @@ Topics [Go to Tutorial 1](tutorial01.md) +```{toctree} +:hidden: + +tutorial01.md +``` + --- ## 2. Boundary Conditions and Loads @@ -57,7 +63,7 @@ Topics - Reaction forces - Singular stiffness matrices -[Go to Tutorial 2](tutorial02.md) +*Planned tutorial.* --- @@ -72,7 +78,7 @@ Topics - Element quality - Stress singularities -[Go to Tutorial 3](tutorial03.md) +*Planned tutorial.* --- @@ -88,7 +94,7 @@ Topics - Stress recovery - Averaging -[Go to Tutorial 4](tutorial04.md) +*Planned tutorial.* --- @@ -103,7 +109,7 @@ Topics - Load stepping - Convergence -[Go to Tutorial 5](tutorial05.md) +*Planned tutorial.* --- @@ -118,7 +124,7 @@ Topics - Return mapping - Internal variables -[Go to Tutorial 6](tutorial06.md) +*Planned tutorial.* --- @@ -133,7 +139,7 @@ Topics - Constraint equations - Tied interfaces -[Go to Tutorial 7](tutorial07.md) +*Planned tutorial.* --- @@ -148,7 +154,7 @@ Topics - Explicit solvers - Stability -[Go to Tutorial 8](tutorial08.md) +*Planned tutorial.* --- @@ -163,7 +169,7 @@ Topics - Hourglassing - Mixed formulations -[Go to Tutorial 9](tutorial09.md) +*Planned tutorial.* --- @@ -178,7 +184,7 @@ Topics - Energy balance - Error diagnosis -[Go to Tutorial 10](tutorial10.md) +*Planned tutorial.* --- @@ -190,4 +196,4 @@ Each tutorial builds upon concepts introduced previously and extends the finite Approximate time per tutorial: -**45–60 minutes** \ No newline at end of file +**45–60 minutes** diff --git a/doc/tutorials/overview.md b/doc/tutorials/overview.md index 5e2f6542..e67c8a1d 100644 --- a/doc/tutorials/overview.md +++ b/doc/tutorials/overview.md @@ -1,6 +1,6 @@ # Tutorials -A few tutorials. The list will be expanded soon. +Explore the available tutorials and the planned finite element tutorial series. ```{toctree} :maxdepth: 1 @@ -8,4 +8,5 @@ A few tutorials. The list will be expanded soon. dissnrg_tutorial.md gmsh_input_tutorial.md quickstart.md +index.md ``` 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/pyproject.toml b/pyproject.toml index e3eec154..d0de5cf2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [build-system] -requires = ["setuptools>=68", "wheel"] +requires = ["setuptools>=77", "wheel"] build-backend = "setuptools.build_meta" [project] @@ -7,14 +7,14 @@ name = "pyfem" dynamic = ["version"] description = "A Python finite element code (educational)" readme = "README.md" -requires-python = ">=3.9" -license = { text = "MIT" } +requires-python = ">=3.10" +license = "MIT" +license-files = ["LICENSE"] authors = [ { name = "J.J.C. Remmers" }, ] classifiers = [ "Programming Language :: Python :: 3", - "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Topic :: Scientific/Engineering", ] @@ -32,11 +32,11 @@ gui = [ "PySide6", ] docs = [ - "sphinx>=5.0.0,<8.0.0", - "sphinx-rtd-theme>=1.2.0", + "sphinx>=7", + "furo>=2024.8.6", "myst-parser>=2.0.0", "sphinx-autoapi>=2.0.0", - "docutils>=0.18", + "sphinx-copybutton>=0.5.0", ] dev = [ "pytest", @@ -57,6 +57,8 @@ pyfem-gui = "pyfem.gui.app:main" [project.urls] Homepage = "https://github.com/jjcremmers/PyFEM" Issues = "https://github.com/jjcremmers/PyFEM/issues" +Documentation = "https://pyfem.readthedocs.io/" +Repository = "https://github.com/jjcremmers/PyFEM" [tool.setuptools] include-package-data = true diff --git a/setup.py b/setup.py deleted file mode 100644 index f59ec967..00000000 --- a/setup.py +++ /dev/null @@ -1,9 +0,0 @@ -"""Compatibility shim for legacy setuptools commands. - -Project metadata is defined in pyproject.toml. -""" - -from setuptools import setup - - -setup() diff --git a/test/testApi.py b/test/testApi.py index 6e401683..3583bd71 100644 --- a/test/testApi.py +++ b/test/testApi.py @@ -86,7 +86,7 @@ def test_gui_dependency_is_optional_and_vtk_is_core(self) -> None: self.assertIn("vtk", dependencies) self.assertEqual(optional["gui"], ["PySide6"]) self.assertIn("myst-parser>=2.0.0", optional["docs"]) - self.assertIn("sphinx-rtd-theme>=1.2.0", optional["docs"]) + self.assertIn("furo>=2024.8.6", optional["docs"]) self.assertNotIn("vtk", optional["docs"]) self.assertIn("pytest", optional["dev"]) self.assertIn("coverage", optional["dev"])