Skip to content

fix: lump HydroDyn filled-member ballast into deck-built floating platforms - #143

Merged
SMI-Lab-Inha merged 4 commits into
masterfrom
fix/hydrodyn-filled-ballast
Sep 30, 2026
Merged

SMI-Lab-Inha merged 4 commits into
masterfrom
fix/hydrodyn-filled-ballast

Conversation

@SMI-Lab-Inha

Copy link
Copy Markdown
Owner

Follow-up to #142, which left one case open. The OC4 DeepCwind semi keeps its water ballast in HydroDyn filled-member groups rather than in ElastoDyn's PtfmMass, so its roll and pitch restoring stayed negative. This PR is stacked on #142 and should be retargeted to master once #142 merges.

What HydroDyn does with fill

Morison.f90 treats a closed fill group as body-fixed ballast. It precomputes each element's fill mass, centroid and inertia (FloodedBallastPartSegmentCyl), and puts the internal pressure datum at the ballast's instantaneous high point. The net load is therefore the weight of a rigid mass at the fill centroid, with no free-surface correction. Groups open to the sea only arise for members buried in the seabed, which a floater doesn't have.

Change

  • New pybmodes.io._hydrodyn_ballast.read_filled_ballast reads the joints, cylindrical property sets, members and fill groups of a HydroDyn deck.
    • It returns the fill's mass, centre of mass and full 3×3 inertia.
    • Members are linearly tapered frustums filled along the axis up to FillFSLoc, following HydroDyn's own full / partial / empty logic, including a surface exactly at a horizontal member counting as full.
    • Five-point Gauss integration, which is exact for these polynomial integrands.
    • Both member-table layouts and the old single NPropSets table are accepted.
    • FillDens = DEFAULT falls back to the water density.
    • A rectangular filled member raises NotImplementedError rather than being skipped.
  • Tower.from_elastodyn_with_mooring and the deck tier of Tower.from_windio_floating lump the ballast into mass_pform, cm_pform and i_matrix before the weight restoring is formed, using parallel-axis transfer to the combined CM.
  • Bundled samples regenerated. 08 (OC4) gets the ballasted platform. 09, 10 and 11 pick up fix: n_modes-independent dense solves, weight restoring on deck-built floaters, WindIO discovery path scope #142's weight term in hydro_K, which they didn't carry yet.

OC4 DeepCwind (r-test decks)

before after Robertson et al. (2014) NREL/TP-5000-60601
platform mass 3.852e6 kg 1.3476e7 kg 1.3473e7 kg
CM below MSL 8.66 m 13.460 m 13.46 m
C44 = C55 (hydro_K) −3.8e8 N·m/rad +9.85e8 N·m/rad
rigid-body modes returned 4 of 6, tower bending labelled roll / pitch all 6

After the fix, in Hz: surge/sway 0.0088, heave 0.0579, roll/pitch 0.0390, yaw 0.0125. The combined roll/pitch inertia comes out 4 % above the published 6.827e9 kg·m². That traces to the steel inertias in the r-test ElastoDyn deck, not to the fill geometry.

Validation

  • tests/test_hydrodyn_ballast.py
    • Self-contained: closed-form cylinders, frustum volume / centroid / axial moment, horizontal and inclined members, parallel-axis combination, both deck layouts, input hardening, and the platform merge.
    • Integration: the OC4 platform mass and CM against Robertson (2014), positive restoring, six labelled rigid-body modes, and heave against the single-DOF estimate.
  • tests/test_floating_samples_spectra.py::test_floating_sample_is_statically_stable (default run) keeps every bundled floater free of the negative-restoring warning.
  • VALIDATION.md rows and the Robertson (2014) citation added; scripts/audit_validation_claims.py is clean.
  • Local, Python 3.11, default + integration: 1450 passed, 3 skipped. ruff and mypy clean.

@SMI-Lab-Inha

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 30, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-09-30T10:44:59.224460Z ab0f561 Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4f6da2a23c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/pybmodes/models/tower.py Outdated
i_mat = _platform_inertia_matrix(ptfm)
# Filled-member ballast, as in from_elastodyn_with_mooring.
if hydrodyn_dat is not None:
ptfm, i_mat = _add_filled_ballast(ptfm, i_mat, hydrodyn_dat)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Honor rho when resolving default ballast density

When from_windio_floating falls back to WindIO hydro (for example, a supplied HydroDyn deck has PotMod=0) and the caller passes a non-default rho, the hydrostatic/added-mass calculations use that value, but this call resolves FillDens=DEFAULT to 1025 kg/m³ instead. A deck containing filled members therefore gets mutually inconsistent platform mass, inertia, and restoring terms; forward rho through _add_filled_ballast to read_filled_ballast(..., water_density=rho) on this path.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in a7b4ed5. from_windio_floating now passes its rho through _add_filled_ballast, so DEFAULT fill density matches the density the hydrostatics, added mass and mooring use on that path. from_elastodyn_with_mooring keeps the deck's own WtrDens. Covered by test_water_density_resolves_default_fill.

…last

The OC4 DeepCwind sample now carries its ballasted platform and positive
roll and pitch restoring; the IEA-15, IEA-22 and UPSCALE semis pick up
the weight term in hydro_K. A default-run test keeps every bundled
floater statically stable with all six rigid-body modes labelled.
@SMI-Lab-Inha
SMI-Lab-Inha force-pushed the fix/hydrodyn-filled-ballast branch from 4f6da2a to a7b4ed5 Compare September 30, 2026 10:27
@SMI-Lab-Inha

Copy link
Copy Markdown
Owner Author

@codex review

@SMI-Lab-Inha
SMI-Lab-Inha changed the base branch from fix/solver-conditioning-floating-weight to master September 30, 2026 10:34

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a7b4ed5d1f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/pybmodes/io/_hydrodyn_ballast.py Outdated

def _float(tok: str, what: str, path: pathlib.Path) -> float:
try:
return _parse_fortran_float(tok)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reject non-finite ballast deck scalars

When a HydroDyn numeric field contains NaN or Inf (for example, an explicit FillDens or a joint coordinate), _parse_fortran_float accepts it and the later range checks do not reliably reject it because comparisons with NaN are false. The quadrature then returns non-finite ballast properties, which _add_filled_ballast propagates into the platform mass and inertia matrices instead of reporting the malformed deck; validate finiteness here before returning the parsed value.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The shared _parse_fortran_float already raised on nan / inf, so these were rejected as malformed rather than propagated. The guarantee shouldn't rest on that helper, though, so ab0f561 checks finiteness directly in the ballast reader. New tests cover nan / inf in FillDens, FillFSLoc, a joint coordinate and PropD.

@SMI-Lab-Inha

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Already looking forward to the next diff.

Reviewed commit: ab0f561e44

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@SMI-Lab-Inha
SMI-Lab-Inha merged commit ba96c1a into master Sep 30, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant