Installation
============
``pybmodes`` requires **Python ≥ 3.11**. The runtime depends only
on ``numpy`` and ``scipy``; everything optional — plotting,
notebook execution, WindIO ingestion, this documentation site —
is gated behind an extra so the default install footprint stays
small.
From PyPI
---------
.. code-block:: bash
pip install pybmodes
This pulls in the runtime dependencies (``numpy>=1.26``,
``scipy>=1.11``) and exposes:
- The Python package: ``import pybmodes``
- The CLI: ``pybmodes`` on ``PATH`` (seven subcommands — see
:doc:`quickstart`).
- The bundled example library (vendored as package-data,
reachable via ``pybmodes examples --copy
``).
To pin a specific release in a requirements file or a
``pyproject.toml``:
.. code-block:: text
pybmodes ==1.9.0 # exact pin
pybmodes ~=1.9 # latest 1.9.x, blocks 2.x
pybmodes >=1.9,<2 # 1.9+ but never a major bump
From source (editable)
----------------------
For contributors and anyone tracking ``master``:
.. code-block:: bash
git clone https://github.com/SMI-Lab-Inha/pyBModes.git
cd pyBModes
pip install -e ".[dev,plots]"
``-e`` installs in editable mode — changes to ``src/pybmodes/*.py``
take effect on the next import without re-installing. End users who
don't need the test/lint extras can install the runtime core alone
with ``pip install .``.
Optional extras
---------------
.. list-table::
:header-rows: 1
:widths: 15 30 55
* - Extra
- Pulls in
- When you need it
* - ``[dev]``
- ``pytest``, ``pytest-cov``, ``ruff``, ``mypy``, ``pyyaml``
- Run the test suite, lint, and type-check the package.
Pulled into editable installs by default; not needed for
end users.
* - ``[plots]``
- ``matplotlib>=3.7``
- Every plotting helper (``pybmodes.plots``): Campbell, MAC,
mode-shape, fit-quality, and environmental-loading
figures. ``pybmodes.plots.apply_style()`` applies the
project's standard engineering-paper palette.
* - ``[windio]``
- ``pyyaml>=6``
- ``Tower.from_windio(...)``, ``RotatingBlade.from_windio(...)``,
``Tower.from_windio_floating(...)``, and the
``pybmodes windio`` one-click CLI.
* - ``[notebook]``
- ``nbclient``, ``nbformat``, ``ipykernel``, ``matplotlib``
- Headless execution of bundled walkthrough notebooks under
:file:`tests/test_notebooks.py`. Test-only — not imported
by ``pybmodes`` itself.
* - ``[docs]``
- ``sphinx<9``, ``sphinx-rtd-theme``, ``myst-parser``,
``sphinx-copybutton``
- Build this documentation site locally.
Combine extras with commas:
.. code-block:: bash
pip install -e ".[dev,plots,windio]"
Windows + conda quickstart
--------------------------
The lowest-friction path on Windows. The user-facing maintainer
runs this exact sequence:
.. code-block:: bat
:: 1. install Miniconda or Anaconda first if you don't have it.
:: https://docs.conda.io/en/latest/miniconda.html
:: Open "Anaconda Prompt" from the Start menu (not regular
:: CMD or PowerShell -- the Anaconda Prompt has `conda`
:: already on PATH).
:: 2. create and activate a dedicated env
conda create -n pybmodes python=3.11 -y
conda activate pybmodes
:: 3. clone and install in editable mode with dev + plotting extras
git clone https://github.com/SMI-Lab-Inha/pyBModes.git
cd pyBModes
pip install -e ".[dev,plots]"
:: 4. verify the install
pytest
.. note::
Don't try to invoke the conda env's ``python.exe`` directly
from PowerShell — it errors with
``STATUS_DLL_INIT_FAILED`` because the env relies on conda's
``PATH`` manipulations. Use Anaconda Prompt, or wrap the call
in ``cmd /c "call activate.bat pybmodes && python ..."``.
Updating to a new release
-------------------------
New versions are published to PyPI (see the `releases
`_ and the
:doc:`changelog`). To upgrade an existing PyPI install to the latest
release, run
.. code-block:: bash
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.
.. code-block:: bash
python -c "import pybmodes; print(pybmodes.__version__)"
pip install "pybmodes==1.14.1" # install or pin a specific release
For a source checkout, pull and reinstall so new dependencies are
picked up too.
.. code-block:: bash
git pull
pip install -e ".[dev,plots]"
Inside a conda environment
^^^^^^^^^^^^^^^^^^^^^^^^^^^
pyBmodes is not on conda-forge, so it is installed with ``pip`` inside
the conda env. Upgrading is therefore a ``pip`` operation rather than a
``conda update``. Activate the env first, then upgrade with pip.
.. code-block:: bash
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__)"
.. note::
``conda update pybmodes`` will not work, because conda doesn't know
the package (pip installed it). If you're unsure which env has it,
``conda env list`` shows every env and ``pip show pybmodes`` confirms
the version installed in the currently active one. For a source
checkout living in a conda env, ``git pull`` then re-run the editable
``pip install -e ".[dev,plots]"`` with the env active.
Verifying the install
---------------------
After installing, run the **self-contained** test suite — every
test that doesn't need external data:
.. code-block:: bash
python -c "import pybmodes; print(pybmodes.__version__)"
pytest
A fresh clone or a fresh PyPI install both pass this with no
external data on the filesystem. Tests that need upstream
OpenFAST / BModes data are gated behind the ``integration``
marker; see :doc:`data_sources` for what to clone and where.
To run the full suite including the integration track once the
upstream data is staged under ``external/``:
.. code-block:: bash
pytest -m integration
CI runs both steps on every PR. The integration step tolerates
``pytest`` exit code 5 ("no tests collected") so the job stays
green on a runner without the data, but fails on any other
non-zero exit so a custom workflow run that *does* have the data
surfaces real failures immediately.
IDE setup
---------
VS Code
^^^^^^^
Recommended workspace settings (``./.vscode/settings.json``):
.. code-block:: json
{
"python.analysis.typeCheckingMode": "basic",
"python.testing.pytestEnabled": true,
"python.testing.pytestArgs": ["tests", "--no-cov"],
"[python]": {
"editor.formatOnSave": false,
"editor.codeActionsOnSave": {"source.organizeImports": "explicit"}
},
"ruff.lint.select": ["E", "F", "W", "I"]
}
The ``--no-cov`` flag in ``pytestArgs`` is a quality-of-life
choice — coverage reports clutter the Test Explorer output.
PyCharm
^^^^^^^
- **Interpreter**: point at the ``pybmodes`` conda env.
- **Test runner**: ``Settings → Tools → Python Integrated Tools →
Default test runner → pytest``.
- **Ruff plugin**: install ``Ruff`` from the marketplace; the
project's ``pyproject.toml`` carries the rules.
Common errors
-------------
``ModuleNotFoundError: No module named 'pybmodes'``
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
You ran ``python`` from outside the install's environment, **or**
you cloned the source but didn't ``pip install -e .``. From the
repo root either install editably or set ``PYTHONPATH``:
.. code-block:: bash
# one-time install
pip install -e .
# or one-off invocation
PYTHONPATH=src python -c "import pybmodes"
``UserWarning: matplotlib is required for plot_campbell``
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The ``[plots]`` extra wasn't pulled in. Add it:
.. code-block:: bash
pip install "pybmodes[plots]"
``KeyError: 'floating_platform'`` (WindIO yaml)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
You're calling ``Tower.from_windio_floating(...)`` on a yaml that
lacks a ``components.floating_platform`` block — a land-based or
monopile-only ontology. Use ``Tower.from_windio(...)`` instead,
or supply a ``floating_platform``-bearing yaml.
``FileNotFoundError: ... external/OpenFAST_files/...``
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
An integration test or a case script needs upstream data that
isn't present. See :doc:`data_sources` for the layout and clone
the required upstream repository under ``external/``.
``MemoryError`` or eigensolver hangs on large towers
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Use a smaller ``n_modes`` (only the lowest few are usually
interesting), or check ``hub_conn`` — a free-free root
(``hub_conn = 2``) without a ``PlatformSupport`` 6×6 matrix is
singular and will hang the solver. The pre-solve sanity checks
(:func:`pybmodes.checks.check_model`) catch this.
Uninstalling
------------
.. code-block:: bash
pip uninstall pybmodes
The editable install also clears with ``pip uninstall``; ``rm
-rf`` on the cloned repo handles the source.