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
Full documentation is published on Read the Docs (the status badge above shows whether that build is live); the table below links straight to the rendered pages. The source lives under docs/ if you'd rather read it on GitHub, and you can build it offline (below).
| 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 |
| Conventions | Coordinate system, origin (tower base), axis directions, DOF order, boundary conditions, and the floating MSL datum + draft / cm_pform / ref_* signs — per model type |
| Units | SI conventions, conversion tables, mode-shape normalisation, OpenFAST DOF order, common pitfalls |
| Limitations | Polynomial-representation limits, validation-matrix edge cases, "when to reach for a different tool" |
| Validation matrix | Per-case cross-checks against published references (mirrors VALIDATION.md) |
| API reference | Autodoc-generated module reference |
| API contract | Semver-frozen public surface + deprecation policy + stability tiers |
| Changelog | Versioning policy + full release history |
| Contributing | Welcome scope, pre-commit, PR checklist, no-AI-attribution rule |
| Release checklist | 11-step pre-tag sequence (maintainer) |
| Deployment | One-time Read the Docs 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]"
Updating to a new release
New versions are published to PyPI (see the releases and the changelog). To upgrade an existing install to the latest release:
pip install --upgrade pybmodes # add the same extras you use, e.g. -U "pybmodes[plots,windio]"
Check the installed version, and pin one if you need reproducibility:
python -c "import pybmodes; print(pybmodes.__version__)"
pip install "pybmodes==1.14.0" # install / pin a specific release
For a source checkout, pull and reinstall:
git pull
pip install -e ".[dev,plots]" # picks up new dependencies too
Using a conda environment? pyBmodes is installed with pip inside the
conda env (it's not on conda-forge), so activate the env first, then upgrade
with pip — don't use conda update:
conda activate pybmodes # the env you installed it into
pip install --upgrade pybmodes # or -U "pybmodes[plots,windio]"
python -c "import pybmodes; print(pybmodes.__version__)"
(If you're unsure which env has it, conda env list shows them and
pip show pybmodes confirms the version in the active env.)
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 the Installation guide 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 the Quickstart.
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.14.0.tar.gz.
File metadata
- Download URL: pybmodes-1.14.0.tar.gz
- Upload date:
- Size: 781.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a135c2299ba277a3a3973fd4ba72aed10cfcf2f9574a9bbf36bee0f4eb48ff98
|
|
| MD5 |
e1d5ed331828659d4a75f040b2011197
|
|
| BLAKE2b-256 |
9d5f0b9231b6671db6fe627bd5d023a71012db232c83eecd390ebdb93dc528f0
|
Provenance
The following attestation bundles were made for pybmodes-1.14.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.14.0.tar.gz -
Subject digest:
a135c2299ba277a3a3973fd4ba72aed10cfcf2f9574a9bbf36bee0f4eb48ff98 - Sigstore transparency entry: 1612345507
- Sigstore integration time:
-
Permalink:
SMI-Lab-Inha/pyBModes@50a5838e23b3c72be2bfe045423d4bfdfe214c6a -
Branch / Tag:
refs/tags/v1.14.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@50a5838e23b3c72be2bfe045423d4bfdfe214c6a -
Trigger Event:
push
-
Statement type:
File details
Details for the file pybmodes-1.14.0-py3-none-any.whl.
File metadata
- Download URL: pybmodes-1.14.0-py3-none-any.whl
- Upload date:
- Size: 569.6 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 |
a0841380b79e3b50f1a73345ee4dfaa56aefade609734074c80c0bdd09580b23
|
|
| MD5 |
67427b3749845128218e803e849e4bef
|
|
| BLAKE2b-256 |
04f576a510de3afe90dc5a7cbc7ee82e220d4a7acd31b3cb2eec7aaf4a5c73a4
|
Provenance
The following attestation bundles were made for pybmodes-1.14.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.14.0-py3-none-any.whl -
Subject digest:
a0841380b79e3b50f1a73345ee4dfaa56aefade609734074c80c0bdd09580b23 - Sigstore transparency entry: 1612345605
- Sigstore integration time:
-
Permalink:
SMI-Lab-Inha/pyBModes@50a5838e23b3c72be2bfe045423d4bfdfe214c6a -
Branch / Tag:
refs/tags/v1.14.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@50a5838e23b3c72be2bfe045423d4bfdfe214c6a -
Trigger Event:
push
-
Statement type: