Python finite-element library for wind turbine blade and tower modal analysis (OpenFAST/ElastoDyn)
Project description
pyBmodes
pybmodes is a pure-Python finite-element library for wind-turbine blade and tower modal analysis. It reads OpenFAST (ElastoDyn / SubDyn / HydroDyn / MoorDyn), BModes .bmi, and WISDEM / WindIO ontology YAML inputs; solves the coupled flap–lag–torsion–axial vibration modes with a 15-DOF Bernoulli-Euler beam element; and emits ElastoDyn-compatible mode-shape polynomials, MAC-tracked Campbell diagrams, and bundled Markdown / HTML / CSV reports.
Validated against the BModes Fortran reference solver on six benchmark cases (NREL 5MW land + OC3 monopile + OC3 Hywind floating spar, IEA-3.4-130-RWT, BModes CertTest 03 / 04) to better than 0.01 % on every comparison. As of 1.8.0 the dedicated Validation workflow (weekly cron + workflow_dispatch) enforces the strict tolerance in CI for the cases whose external data is clonable from a public GitHub repository at a manifest-pinned SHA. Cloning is manifest-driven (verify_external_data.py --clone), so CI fetches and --strict-checks every required entry: the NREL 5MW family in OpenFAST/r-test, all four IEA Task-37 reference turbines (IEA-3.4-130-RWT, IEA-10.0-198-RWT, IEA-15-240-RWT, IEA-22-280-RWT), and the WISDEM WindIO examples — a missing or off-pin required clone hard-fails the run. Only the optional = true entries (MoorPy / RAFT cross-reference clones) are left out of CI as maintainer-local checks. Publishing to PyPI is itself gated on a green run of this workflow for the tagged commit. The two BModes CertTest cases (Test03, Test04) depend on external/BModes, a NREL download not on GitHub; those tests skip cleanly when the data is absent and stay maintainer-local enforcement. The per-PR ci.yml continues to run the self-contained suite (synthetic + closed-form-referenced) and tolerates "no tests collected" on the integration step when the runner has no upstream data. See VALIDATION.md for the full per-case matrix and external/MANIFEST.toml for the manifest-pinned commit SHAs plus line-ending-normalized SHA-256 hashes for the text validation decks.
Documentation
📖 The rendered documentation lives at pybmodes.readthedocs.io. Sphinx-specific roles (
:math:,:doc:,:func:,:class:) inside the.rstsource files only render correctly through the deployed site; browsing the raw source on GitHub will show them as literal text. Always link readers to the RTD URL, not the source.(If the URL 404s, the Read the Docs project hasn't been imported yet — see
docs/deployment.rstfor the one-time maintainer setup.)
| Page | What's there |
|---|---|
| Installation | PyPI / source install, extras matrix, Windows + conda quickstart, troubleshooting |
| Quickstart | Nine worked recipes — synthetic tower, OpenFAST deck, monopile + SubDyn, floating coupled, Campbell sweep, WindIO one-click, MAC, batch, persistence |
| Theory | Eigenproblem maths, 15-DOF beam element, four boundary conditions, polynomial ansatz, solver dispatch, citable references |
| Data sources | Every input format — BModes .bmi, ElastoDyn / SubDyn / HydroDyn / MoorDyn .dat, WAMIT .1 / .hst, WindIO .yaml — with snippet examples |
| Units | SI conventions, conversion tables, mode-shape normalisation, OpenFAST DOF order, common pitfalls |
| Limitations | Polynomial-representation limits, four specific validation-matrix edge cases, "when to reach for a different tool" |
| Validation matrix | Per-case cross-checks against published references (cross-references VALIDATION.md) |
| API reference | Autodoc-generated module reference |
| API contract | Semver-frozen public surface + deprecation policy + stability tiers |
| Changelog | Versioning policy + full release history (cross-references CHANGELOG.md) |
| Contributing | Welcome scope, pre-commit, PR checklist, no-AI-attribution rule |
| Release checklist | 11-step pre-tag sequence (maintainer) |
| Deployment | One-time RTD setup + versioning policy (maintainer) |
To build locally:
pip install -e ".[docs]"
make -C docs html
# then open docs/_build/html/index.html through a real web server
# (file:// blocks MathJax CDN in some browsers):
python -m http.server -d docs/_build/html
Install
pip install pybmodes
That installs the runtime core (numpy + scipy). Add an extra for optional features — [plots], [windio], [notebook], [docs] (matrix below). For a source / editable checkout (contributors, or tracking master):
git clone https://github.com/SMI-Lab-Inha/pyBModes.git
cd pyBModes
pip install -e ".[dev,plots]"
Take care that pybmodes is a different project from pyModeS (an ADS-B / Mode-S decoder). The PyPI name is pybmodes (lowercase, no S); double-check the package name + the GitHub SMI-Lab-Inha/pyBModes repo URL before installing.
See https://pybmodes.readthedocs.io/en/latest/installation.html for the full Windows + conda quickstart and the optional-extras matrix ([plots], [windio], [notebook], [docs]).
Quick example
from pybmodes.models import Tower
from pybmodes.elastodyn import compute_tower_params, patch_dat
# Reads ElastoDyn main + tower from one path; lumps the rotor mass.
tower = Tower.from_elastodyn("NRELOffshrBsline5MW_Onshore_ElastoDyn.dat")
modal = tower.run(n_modes=4)
# Constrained 6th-order fit, FA/SS family selection with torsion-contamination filter.
params = compute_tower_params(modal)
# Rewrite the polynomial blocks (use --dry-run / --diff via the CLI for safety).
patch_dat("NRELOffshrBsline5MW_Onshore_ElastoDyn.dat", params)
More — Campbell sweeps, WindIO one-click, mode-by-mode MAC comparison, bundled reports — in https://pybmodes.readthedocs.io/en/latest/quickstart.html.
CLI
Seven subcommands surfaced as the pybmodes console script:
| Subcommand | Purpose |
|---|---|
pybmodes validate <main.dat> |
Coefficient-consistency report on one ElastoDyn deck. |
pybmodes patch <main.dat> |
Regenerate polynomial blocks. --dry-run / --diff / --backup / --output-dir for safety. |
pybmodes campbell <input> |
Rotor-speed sweep → Campbell diagram PNG + CSV. |
pybmodes batch ROOT |
Walk a directory of decks; per-deck validate + patch + summary CSV. |
pybmodes report <main.dat> |
Bundled Markdown / HTML / CSV analysis report. |
pybmodes windio <yaml | dir> |
One-click WISDEM / WindIO → composite blade + tubular tower + coupled platform + Campbell. |
pybmodes examples --copy DIR |
Vendor sample_inputs/ and / or reference_decks/ out of the installed wheel. |
Development
pytest # default — self-contained, no external data
pytest -m integration # integration — needs upstream decks under external/
ruff check src/ tests/ scripts/
mypy src/pybmodes
python scripts/audit_validation_claims.py # gates "claim ahead of test" drift
The default pytest run is self-contained and works on a fresh clone with no external data. Tests that need locally-checked-out OpenFAST r-test, BModes CertTest, or IEA-RWT decks are gated behind the integration marker; CI tolerates exit code 5 ("no tests collected") on a runner without the data. Full developer guide in CONTRIBUTING.md.
Citation
If you use pyBmodes in academic work, please cite it via the CITATION.cff file. GitHub's Cite this repository widget reads it automatically; Zenodo and most reference managers pick it up too.
License
Released under the Apache License 2.0.
Copyright 2024-2026 Jae Hoon Seo, Marine Structural Mechanics and Integrity Lab (SMI Lab), Inha University.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pybmodes-1.12.0.tar.gz.
File metadata
- Download URL: pybmodes-1.12.0.tar.gz
- Upload date:
- Size: 749.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
57c2c8c7380884e1ece632a7095c33104eb23456f8dd5967c3fb81ea6241d466
|
|
| MD5 |
03a5ba090e02d7c9fd856a121c856d97
|
|
| BLAKE2b-256 |
dd83d71b8dc96de67bc28a92d35016e82c556331eb7b687f942e568afdfea336
|
Provenance
The following attestation bundles were made for pybmodes-1.12.0.tar.gz:
Publisher:
publish.yml on SMI-Lab-Inha/pyBModes
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pybmodes-1.12.0.tar.gz -
Subject digest:
57c2c8c7380884e1ece632a7095c33104eb23456f8dd5967c3fb81ea6241d466 - Sigstore transparency entry: 1609604760
- Sigstore integration time:
-
Permalink:
SMI-Lab-Inha/pyBModes@358db082353d3722194b235a5f622fa96550cd22 -
Branch / Tag:
refs/tags/v1.12.0 - Owner: https://github.com/SMI-Lab-Inha
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@358db082353d3722194b235a5f622fa96550cd22 -
Trigger Event:
push
-
Statement type:
File details
Details for the file pybmodes-1.12.0-py3-none-any.whl.
File metadata
- Download URL: pybmodes-1.12.0-py3-none-any.whl
- Upload date:
- Size: 556.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5c0c0e1b80cccb45df5c4c3c907828ba628d36bfbc380d77ffd33d24f516b84f
|
|
| MD5 |
08272caa050ffe777ce21dc605d5b908
|
|
| BLAKE2b-256 |
dabaae15f0e709ed68337e3e3aef600a89bc2ab4f0f0fc765c4ea2038a74c436
|
Provenance
The following attestation bundles were made for pybmodes-1.12.0-py3-none-any.whl:
Publisher:
publish.yml on SMI-Lab-Inha/pyBModes
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pybmodes-1.12.0-py3-none-any.whl -
Subject digest:
5c0c0e1b80cccb45df5c4c3c907828ba628d36bfbc380d77ffd33d24f516b84f - Sigstore transparency entry: 1609604929
- Sigstore integration time:
-
Permalink:
SMI-Lab-Inha/pyBModes@358db082353d3722194b235a5f622fa96550cd22 -
Branch / Tag:
refs/tags/v1.12.0 - Owner: https://github.com/SMI-Lab-Inha
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@358db082353d3722194b235a5f622fa96550cd22 -
Trigger Event:
push
-
Statement type: