API contract

pybmodes is on a stable 1.x baseline. The public surface enumerated below is semver-frozen across 1.x minor releases. Renaming or removing any name on this list requires a major- version bump (2.x). Adding new keyword arguments with defaults, new dataclass fields, and brand-new entry points is non- breaking.

Versioning policy

We follow Semantic Versioning 2.0 for the API surface. The version string is in [project] version of pyproject.toml and is mirrored at pybmodes.__version__.

Bump

Example

Triggers

Major (X.y.z)

1.7.0 → 2.0.0

Renaming or removing any name on this page; changing a function’s required parameter; tightening a return- type so callers must adapt; dropping a Python version.

Minor (x.Y.z)

1.6.0 → 1.7.0

New entry points; new keyword arguments with sane defaults; new dataclass fields with sane defaults; new optional dependency extra; new CLI subcommand.

Patch (x.y.Z)

1.7.0 → 1.7.1

Bug fixes; numerical-accuracy improvements that change output values (always called out in the changelog); documentation; internal refactors.

Numerical outputs may shift between minor and patch releases when validation tightens or a modelling correction lands. Every such shift is called out in Changelog under Fixed / Changed with magnitude and affected case. For reproducible numerics across runs, pin to an exact version (pybmodes==1.7.0) and only upgrade after reading the changelog.

Deprecation policy

When a public name is being renamed or removed for a future major version, we follow a two-minor-release deprecation window:

  1. First minor release introduces the new name; keeps the old name working but emits a DeprecationWarning with a pointer to the replacement.

  2. Second minor release keeps the old name working but prints the warning at module-import time, in addition to call-time.

  3. Next major release removes the old name entirely.

Deprecation warnings name the minimum version a fix is available in, so:

warnings.warn(
    "RotatingBlade.legacy_method is deprecated since 1.x; "
    "use RotatingBlade.method instead (available from 1.7.0). "
    "The legacy name will be removed in 2.0.",
    DeprecationWarning,
    stacklevel=2,
)

There are currently no deprecations in flight on the 1.x line.

Stable public names

The authoritative list is the docstring of pybmodes.__init__; the table below is a categorised summary.

Model constructors

Name

From

pybmodes.models.RotatingBlade

__init__(bmi_path), from_elastodyn(main_dat_path, *, validate_coeffs=False), from_windio(yaml_path, *, component='blade', n_span=30, rot_rpm=0.0, n_perim=300, elastic='auto').

pybmodes.models.Tower

__init__(bmi_path), from_bmi(bmi_path), from_elastodyn(main_dat_path, *, validate_coeffs=False), from_elastodyn_with_subdyn(main_dat_path, subdyn_dat_path), from_elastodyn_with_mooring(main_dat_path, moordyn_dat_path, hydrodyn_dat_path=None), from_geometry(...), from_windio(yaml_path, *, component='tower', thickness_interp='linear'), from_windio_floating(yaml_path, *, ...).

Results + serialisation

  • pybmodes.models.ModalResult — return value of .run(); carries frequencies + per-node mode shapes + optional participation + optional fit residuals; ships save(.npz) / load(.npz) and to_json(.json) / from_json(.json) with embedded pyBmodes version + UTC timestamp + source-file + git-hash metadata.

As of Phase 3 PR C1 of the 1.x refactor, pybmodes.campbell is a sub-package rather than a single 1301-line module. The public API (CampbellResult, campbell_sweep(), plot_campbell()) is unchanged and re-exported from pybmodes.campbell; internal helpers live in private sub-modules (_models / _classify / _mac / _sweep / _plot) so each file covers one concern.

  • pybmodes.campbell.CampbellResult — output of campbell_sweep; ships save(.npz) / load(.npz), to_csv(.csv); carries frequencies + omega_rpm + labels + participation + mac_to_previous per-step tracking confidence + integer mode counts.

Solvers + sweeps

Polynomial fitting + validation

  • pybmodes.elastodyn.compute_blade_params()

  • pybmodes.elastodyn.compute_tower_params()

  • pybmodes.elastodyn.compute_tower_params_report() — same plus a TowerSelectionReport exposing FA / SS family scoring + rejected-mode lists.

  • pybmodes.elastodyn.patch_dat()

  • pybmodes.elastodyn.validate_dat_coefficients()

Floating coupled-vs-cantilever diagnostic

  • pybmodes.elastodyn.report_floating_frequency_gap() runs a cantilever and a coupled solve on the same floating deck and returns the gap between the polynomial-basis 1st FA / SS and the coupled-system 1st FA / SS that an OpenFAST linearisation will report. Useful for reconciling pyBmodes-generated polynomial coefficients against linearisation output without re-deriving the cantilever-vs-coupled architecture.

  • pybmodes.elastodyn.FloatingFrequencyGap carries the four frequencies plus gap_fa_1_pct / gap_ss_1_pct properties and a format_report() rendering.

Soil-pile interaction

  • pybmodes.MudlineFoundation carries the three coupled mudline springs K_hh / K_hr / K_rr and the pile-behaviour / soil-profile / formula discriminators. Classmethod from_soil_properties(pile_diameter, pile_length_embedded, pile_EI, soil_E, soil_nu=0.3, soil_profile="homogeneous", pile_behaviour="auto", formula="shadlou") applies Randolph (1981) classification and dispatches to Shadlou and Bhattacharya (2016) per Yu and Amdahl (2023) Table 1 or to Psaroudakis et al. (2021) per Yu Eq 25. as_mooring_K() returns a 6 x 6 block in OpenFAST DOF order that drops straight into PlatformSupport.mooring_K of a hub_conn = 3 BMI.

Pre-solve sanity + comparison

Numerical options (1.x architecture refactor — Phase 1)

Frozen dataclasses that centralise numerical thresholds previously scattered as module-level constants. Adding fields with sensible defaults is non-breaking; removing or renaming a field is a semver-major change.

  • pybmodes.SolverOptions — FEM solver dispatch (sparse_ndof_threshold, symmetry_rtol).

  • pybmodes.FitOptions — polynomial-fit + family-selection thresholds (polynomial_rms_threshold, torsion_contamination_threshold, fit_cond_warn, fit_cond_fail).

  • pybmodes.CheckOptionscheck_model() thresholds (stiffness_jump_factor, ei_ratio_min / _max, support_asymmetry_rtol, fit_cond_warn / _fail).

Reports

  • pybmodes.report.generate_report() — Markdown / HTML / CSV bundled analysis report (eight sections: summary, assumptions, frequencies, classification, polynomial coefficients with fit residuals, validation, check_model warnings, Campbell sweep).

Workflows (Phase 2 of the 1.x architecture refactor)

The pybmodes.workflows sub-package exposes each CLI subcommand as a typed library function returning a WorkflowResult subclass. Lets notebooks and external scripts run the same flows the CLI uses without going through subprocess. The CLI in pybmodes.cli is now a thin argparse + delegate + format result + map exit code layer.

With this PR the full pybmodes CLI surface is library- callable; pybmodes.cli is purely argparse + delegation.

Mooring + hydro

As of Phase 3 PR C2 of the 1.x refactor, pybmodes.mooring is a sub-package rather than a single 1202-line module. The four public names (LineType, Point, Line, MooringSystem) are unchanged and re-exported from pybmodes.mooring; the implementation lives in types (data classes + Line.solve_static()) and system (MooringSystem with multi-line force assembly + 6×6 stiffness and the two from_* parsers), plus the private _catenary / _rotation math primitives and the _moordyn_parser MoorDyn .dat row tokenisers.

I/O

Plot helpers ([plots] extra)

CLI subcommands

The pybmodes console script declared in [project.scripts]. Subcommand names and their flag semantics are part of the semver contract.

Subcommand

Purpose

pybmodes validate <main.dat>

Coefficient-consistency report on one ElastoDyn deck.

pybmodes patch <main.dat>

Regenerate polynomial blocks; --backup / --dry-run / --diff / --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.

Stability tiers

Not every module is at the same stability level. The public names above (and only those) are the stable surface.

Public + stable

Listed above. Semver-frozen.

Public but experimental

Currently none. When a name is introduced experimentally (e.g. a new constructor for a niche WindIO dialect), it’s flagged in its docstring with:

.. note::
   Experimental — may change without notice until the next
   X.Y.0 release at the earliest.

Internal (underscore-prefixed)

Modules under src/pybmodes/ whose name starts with an underscore (_pipeline.py, _serialize.py, _elastodyn/, _precomp/) and module-level attributes starting with an underscore. These can change in any release including patch versions.

Don’t import from them; if you find yourself wanting to, open an issue — that’s a signal we have a real-use-case gap in the public surface, and we’d rather fix that than have you depend on something we’ll break.

Runtime dependency contract

The default install pulls in ``numpy`` and ``scipy`` only. Every other dependency is gated behind an extra (Installation). Adding a runtime dependency to the core requires alignment — the numpy + scipy-only stance is itself part of the contract.

Tier

Examples

Semver impact

Core

numpy, scipy

Tightening the version pin is a minor bump; adding a new core dep is a major bump.

Extras

matplotlib ([plots]), pyyaml ([windio]), sphinx ([docs])

Adding a new extra is a minor bump; renaming or removing an extra is a major bump.

How to track changes

  • Changelog — every release, called-out numerical shifts.

  • Validation matrix — the per-case validation matrix, mechanically audited by scripts/audit_validation_claims.py in CI.

  • CHANGELOG.md at the repo root — the source of truth (the docs page above is included from it).

  • GitHub Releases — release-notes copies of the [X.Y.Z] changelog block, with merge-PR backlinks.

  • Read the Docs version selector — version-pinned docs for every published tag.