Skip to content

Improved HydroDyn strip-theory hydrodynamic load model for circular members floating on or just beneath the free surface - #3489

Draft
luwang00 wants to merge 20 commits into
OpenFAST:devfrom
luwang00:f/HD_HMember
Draft

luwang00 wants to merge 20 commits into
OpenFAST:devfrom
luwang00:f/HD_HMember

Conversation

@luwang00

@luwang00 luwang00 commented Oct 12, 2026 •

Copy link
Copy Markdown
Contributor

This PR is NOT ready to be merged. The core new functionality has been implemented and tested, but it is still a work in progress. Also depends on merging PR #3487 first.

Feature or improvement description
This PR provides an important upgrade to HydroDyn's strip-theory formulation by introducing a more accurate hydrodynamic load model for circular members on or near the free surface. It corrects the distributed hydrodynamic loads along the member both when the member is surface piercing (in a ship-like configuration) or at shallow submergence when the member is at a shallow inclination angle relative to the free surface. It also includes corrections to the joint/endplate loads to account for partial wetting.

HydroDyn already computes nonlinear hydrostatic loads on strip-theory (Morison) members by directly integrating the hydrostatic pressure on the instantaneous wetted surface (MHstLMod=2). This method is general and correctly evaluates the hydrostatic loads for any member/free-surface intersection. It also correctly handles partially wetted end plates.

However, the strip-theory hydrodynamic load model was still greatly simplified. More specifically, if the center of a section is below the wave free surface when wave stretching is enabled (WaveStMod>0 in SeaState) or below the still water level without wave stretching (WaveStMod=0 in SeaState), the hydrodynamic loads on this section were computed as if the entire section is submerged. Alternatively, if the section center is above the free surface or still water level, the section was treated as completely dry with zero hydrodynamic load. As a result, HydroDyn strip-theory members could not provide realistic hydrodynamic loads if the member is on and nearly parallel to the free surface with the section centers going in and out of water. The joints/endplates were handled in a similar fashion, being treated as either fully submerged or fully dry with no in-between states.

To address the fidelity gap between hydrodynamic and hydrostatic loads for near-surface/surface-piercing members with shallow inclination relative to the free surface, this PR adds improved strip-theory hydrodynamic load models for circular members specifically for these situations. The key changes relative to the baseline strip-theory load models, which are retained for members at a steeper angle relative to the free surface, are:

  • Time-varying section added mass based on instantaneous section submergence, including partial submergence, for section added-mass and wave-scattering forces.
  • The submergence-dependent transverse added-mass coefficients are based on the infinite-frequency added mass of Taylor (1930) and Greenhow and Ahn (1988) with newly developed piecewise polynomial representations and asymptotic approximations to facilitate fast and reliable evaluation at runtime. Note that fully submerged sections will also have corrected/time-dependent added mass if the submergence is shallow (center depth less than 5x section radii in this particular implementation).
  • The submergence-dependent axial added mass is simply obtained by scaling the fully submerged axial added mass by the fraction of the circumference that is submerged.
  • In addition to the standard Morison equation terms, also added a water entry/exit force following the Generalized von Kármán Model. This term is derived from momentum conservation and is related to the time derivative of section added mass. In the present implementation, the von Kármán water entry/exit force is generalized for oblique entry in the transverse direction and also generalized to the axial direction.
  • With this enhancement, we do not intend to model the slamming impact force exactly due to the excessive constraints it puts on the time step and the structural solver. Instead, we simply include the water entry/exit force to ensure the hydrodynamic load is momentum conserving as the waterline rises and falls across the section. Therefore, the discontinuous slamming load at the point of water impact and exit is smoothed out over 10% of the section diameter to minimize the high-frequency excitation that can cause numerical difficulties with the structural solver. Nevertheless, dropping the member from the air into water at great height will still lead to a smooth but very high quasi "slamming" load on the structure. Note that the load smoothing slightly breaks momentum conservation during initial impact.
  • The Froude-Krylov force is generalized to handle partial wetting of the section circumference. The section load in the transverse direction is integrated analytically based on local pressure gradient over the wetted arc for performance. In the axial direction, we equivalently scale the fully submerged axial force by the fraction of the circumference that is submerged.
  • The axial and transverse drag forces are also corrected for partial wetting. In the transverse direction, the reference width of the member is the instantaneous waterline width if less than half of the section is submerged or fixed to the section diameter if more than half of the section is submerged. In the axial direction, the drag is simply scaled by the fraction of the circumference that is submerged. Right now, the distributed transverse and axial drag coefficients are still constant with only corrections to the reference width/wetted circumference. Submergence-dependent drag coefficients can be implemented in the future.
  • Smooth blending between the new shallow-inclination section load model and the existing baseline model appropriate for members at a steeper angle relative to the free surface. The blending is performed on a nodal basis (without assuming straight undeflected member) based on the instantaneous angle between the section axial direction and the local free-surface normal over the range of 55 deg to 65 deg. The existing baseline model is used exclusively for 0 to 55 deg, while the new model is used exclusively for 65 to 90 deg. This is equivalent to using the new model when the section axial direction is inclined from the free surface by 0 to 25 degrees and using the existing baseline model when the inclination is between 35 to 90 degrees, with smooth blending between 25 and 35 degrees.
  • For the joint/endplate hydrodynamic loads, a unified formulation is adopted that always accounts for partial wetting, except when the endplate is nearly parallel to the free surface (within 5°), where it is treated as either fully wet or fully dry (the previous behavior). The forces are scaled by the wetted area fraction r. More specifically, the added-mass and wave-scattering force are scaled by r^(3/2) while the Froude-Krylov force and drag are scaled by r. If velocity filtering is used, the normal relative velocity filtered is also scaled by r. The von Kármán water entry/exit force is also generalized for the joints and is included in the model.
  • With the smooth blending of the new and existing distributed load models and the unified joint load model, the new capability currently does not require any new user inputs. It will automatically take effect with circular members when appropriate. (Rectangular members still have the old behavior.) However, new inputs might be added in the future if there is a strong need for the user to fine-tune model behavior, such as the smoothing length as a fraction of section radius for the slamming force or the inclination angle range for model blending.

Currently, the above new capabilities are only implemented for circular members. There is no plan to generalize it to rectangular members due to the greatly increased complexity and a lack of reference data.

The core feature has been implemented and preliminarily tested and verified, including a stress test where a light horizontal rigid cylinder (the fully submerged added mass is 4.6x the structural mass) is dropped from 10 m above water. After the initial impact, the member subsequently bounced back out of water before settling over time. This is a numerically highly challenging case because the initial Jacobian encodes zero added mass (member is in the air), and as the member hits the water, the added mass rapidly increases from 0 to 4x structural mass. Nevertheless, the glue code remains stable with the help of automatic Jacobian update and underrelaxation.

Related issue, if one exists
N/A

Impacted areas of the software
HydroDyn (Morison)

Additional supporting information
Formulation and implementation details to come.

Generative AI usage
Formulated by human. This PR page is also written by human for readability and focus.
Code implementation assisted by LLM:
Co-authored-by: Anthropic Claude claude@anthropic.com
Assisted by: GitHub Copilot support@github.com

Test results, if applicable
Existing r-tests are not affected because the scenario addressed by this improvement was purposely avoided in the past. New r-tests will be prepared and require merging.

  • r-test branch merging required

luwang00 and others added 19 commits October 5, 2026 15:59
…-vector helper

Morison_CalcOutput only consumed the axial unit vector k_hat from GetOrientationAngles; its tilt/heading trig outputs were unused. Replace that routine with a slim GetElementAxialVec(p1,p2,k_hat,...) that returns only k_hat and keeps the zero-length-element fatal guard (do not assume rigid structure). Convert the marine-growth weight moments F_WMG(4)/F_WMG(5) from sinPhi*sinBeta / sinPhi*cosBeta to the exact identities k_hat(2)/k_hat(1), update all four call sites, and drop the now-dead trig locals.

Co-authored-by: GitHub Copilot <copilot@github.com>

Co-authored-by: Claude <noreply@anthropic.com>
…helper

Collapse the three duplicated external end-plate buoyancy blocks into a single contained AddEndBuoyancy subroutine, replace the brittle EqualRealNos partial-wetting arc test with the secStat classification returned by GetSectionFreeSurfaceIntersects_Cyl, drop the dead SetErrStat after that call, and convert the section-geometry branch to SELECT CASE.

Co-authored-by: GitHub Copilot <copilot@github.com>

Co-authored-by: Claude <noreply@anthropic.com>
Convert bare SetErrStat propagation sites to 'if (Failed()) return' so fatal errors from sub-calls abort instead of continuing with bad data. Fixes two lost-error cases: paired GetTotalWaveElev calls that shared one SetErrStat (first status overwritten), and the VisMesh Transfer_Point_to_Line2 call that passed ErrStat/ErrMsg directly and clobbered accumulated errors.

Co-authored-by: GitHub Copilot <copilot@github.com>

Co-authored-by: Claude <noreply@anthropic.com>
…tput

Co-authored-by: GitHub Copilot <copilot@github.com>

Co-authored-by: Claude <noreply@anthropic.com>
Store each member's undisplaced section direction-cosine matrix as member%CMatrix at initialization instead of recomputing it every step via Morison_DirCosMtrx inside Morison_CalcOutput and getMemBallastHiPt.

The reference DCM is constant per (straight) member, so the per-step calls built from the static u%Mesh%Position were redundant. CMatrix is computed once in SetMemberProperties_Cyl (spin 0, axisymmetric) and SetMemberProperties_Rec (spin = MSpinOrient), then combined with the instantaneous u%Mesh%Orientation at each use site, preserving results bit-for-bit.

- Add CMatrix(3,3) to Morison_MemberType (registry + regenerated types).
- YawMember now yaw-rotates x_hat/y_hat for all section geometries, and deliberately leaves CMatrix in the undisplaced frame since it is composed with the full nodal orientation downstream.
- Remove dead Morison_DirCosMtrx calls, unused CMatrix/CMatrix0 locals, and the redundant MSecGeom checks in SetMemberProperties_Rec and YawMember.

Co-authored-by: GitHub Copilot <copilot@github.com>

Co-authored-by: Claude <noreply@anthropic.com>
Delete dead code with no callers: Morison_DirCosMtrx_noSpin (generic interface collapsed to Morison_DirCosMtrx), ElementCentroid, ElementVolume, FindInterpFactor, InterpWrappedStpInt, InterpWrappedStpLogical, DistributeElementLoads, and AddEndLoad, plus stale commented references.

Co-authored-by: GitHub Copilot <copilot@github.com>

Co-authored-by: Claude <noreply@anthropic.com>
Replace the trig-based incline angle (phi/sinPhi/cosPhi via acos/sin/cos) in member initialization with direct axial-unit-vector expressions, remove the now-redundant cosPhi_ref member field (consumers use k(3)), and guard the inclination-threshold checks with ABS(cosPhi) so a reversed member is still treated as vertical.

Co-authored-by: GitHub Copilot <copilot@github.com>

Co-authored-by: Claude <noreply@anthropic.com>
Replace the yaw-only YawMember/YawJoint helpers with RotateMemberNode and RotateJoint, which rotate reference-configuration member and joint properties to either the reference-yaw orientation (WaveDisp=0) or the full instantaneous node orientation (WaveDisp=1). Rotate per node in all three hydrodynamic loops (smoothing, no-smoothing, UpdateDiscState) and at the free-surface-crossing element, reading from the pristine parameter copy to avoid compounding. Keep hydrostatic loads on exact orientation. Remove the input constraint forbidding PtfmYMod=1 with WaveDisp=0 and clean up error handling in Morison_UpdateDiscState.

Co-authored-by: GitHub Copilot <copilot@github.com>

Co-authored-by: Claude <noreply@anthropic.com>
Add a PtfmRefXY pipeline so strip-theory (Morison) members translate with the low-frequency / instantaneous horizontal drift of the HydroDyn origin when WaveDisp=0, mirroring the existing PtfmRefY reference-yaw treatment and the WAMIT ExctnDisp filter.

The drift follows the user-specified ExctnDisp/ExctnCutOff regardless of whether potential-flow bodies are present: the raw ExctnDisp is captured into p%PtfmXYMod before HydroDynInput_ProcessInitData may force it to 0 for the WAMIT grid, and the ExctnCutOff>0 validation is checked beforehand and broadened to ExctnDisp=2.

Co-authored-by: GitHub Copilot <copilot@github.com>

Co-authored-by: Claude <noreply@anthropic.com>
Update the WaveDisp input comment and documentation to reflect the clearer
interpretation: WaveDisp=0 places strip-theory members/joints at a
potential-flow-consistent reference configuration (reference yaw plus
horizontal x-y drift governed by ExctnDisp/ExctnCutOff), and WaveDisp=1 uses
the exact instantaneous displaced position and orientation. Updates
input_files.rst, appendix.rst, api_change.rst, and the FAST_writer.py comment
string.

Co-authored-by: GitHub Copilot <copilot@github.com>
Co-authored-by: Claude <noreply@anthropic.com>
…heory

Remove the hidden logic that dropped the vertical (Z) displacement of
strip-theory member nodes when wave stretching was disabled. The member
submergence status now checks every node (members are no longer assumed
rigid/straight), and load smoothing is applied for right-side-up members
crossing the free surface once whenever wave stretching is enabled or
WaveDisp=1, since both can drive nodes in and out of the water. Smoothing is
skipped only when WaveStMod=0 and WaveDisp=0. Update input_files.rst to drop
the obsolete Z-displacement explanation.

Co-authored-by: GitHub Copilot <copilot@github.com>
Co-authored-by: Claude <noreply@anthropic.com>
…d loads

The AMMod switch selected whether the distributed strip-theory added-mass
force was evaluated only up to the SWL (0) or followed the instantaneous
wetted section (1). With the improved solver stability in 5.1.0 the SWL-only
option is no longer needed, so AMMod is removed and the added-mass force is
now computed the same way as the other distributed loads: up to the
instantaneous free surface when wave stretching is enabled (WaveStMod > 0)
and up to the SWL otherwise.

Removes AMMod from the Morison registry/types, HydroDyn input parsing and
validation, the Python reader/writer, and the documentation (with an
api_change.rst entry). Bumps the r-test pointer to the input files with the
AMMod line removed (required because HydroDyn uses fixed-form line-position
input parsing).

Co-authored-by: GitHub Copilot <copilot@github.com>
Co-authored-by: Claude <noreply@anthropic.com>
…thing

Use the SWL (z=0) as the free surface when wave stretching is disabled in the smoothing loop, matching how nodeInWater/MemSubStat are determined. Previously the instantaneous wave elevation was used to locate the crossing element while in-water status used the SWL, so the WaveStMod=0 + WaveDisp=1 combination could leave FSElem unset (-1) and segfault when indexing arrays. Also add a fatal-error guard if no free-surface-crossing element is found.

Co-authored-by: GitHub Copilot <copilot@github.com>

Co-authored-by: Claude <noreply@anthropic.com>
Drag, added-mass, and inertia side loads are now written only to memberLoads and added to the output mesh in a single pass after the side-load block. The load-redistribution moment correction is split by component and stored in the moment rows of F_D, F_A, and F_I instead of being added directly to the mesh, so member load totals now include it. This prepares for nodal blending with the upcoming shallow-angle member model.

Co-authored-by: GitHub Copilot <copilot@github.com>

Co-authored-by: Claude <noreply@anthropic.com>
Add memberLoads%F_WE and F_WE_End for the upcoming water entry/exit force, included in the mesh loads and member/joint totals. Add HM_w and HM_nw misc arrays for per-node blending of the baseline and shallow-angle strip-theory models. No change in results.

Co-authored-by: GitHub Copilot <copilot@github.com>

Co-authored-by: Claude <noreply@anthropic.com>
Add module constants (blend angles, Table 1 polynomial coefficients) and PURE helpers for the horizontal-member model: smooth step and blend weight, submerged area and wetted circumference fraction, normalized heave/sway added mass with analytic derivatives (heave via half-angle form to avoid cancellation near Hbar=+1), section submergence depth, and partially-submerged Froude-Krylov section force.

Co-authored-by: GitHub Copilot <copilot@github.com>

Co-authored-by: Claude <noreply@anthropic.com>
…members

Compute per-node blend weights from the local free-surface normal and member axis, skip the baseline model when all weights are zero, and blend in a shallow-angle model for circular members: submergence-dependent drag, Froude-Krylov force on the wetted arc, Greenhow/Taylor added mass and scattering, and smoothed water entry/exit loads. Extract the nodal taper into GetNodeTaper.

Co-authored-by: GitHub Copilot <copilot@github.com>

Co-authored-by: Claude <noreply@anthropic.com>
Add GetJointWetting for the wetted area fraction of joint end plates. Scale joint added mass, inertia, and drag by the wetted fraction, add the water entry/exit load, and use free-surface kinematics for joints above water. Apply the same scaling in the joint drag filter update.

Co-authored-by: GitHub Copilot <copilot@github.com>

Co-authored-by: Claude <noreply@anthropic.com>
Weight the joint relative normal velocity by sqrt(r) instead of r in CalcOutput and in the drag filter update, so the quadratic endplate drag scales with r in both the filtered and unfiltered branches. Fully wetted joints are unchanged.

Co-authored-by: GitHub Copilot <copilot@github.com>

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant