Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
4a65052
fix(capi): name the real scope of the aggregate refusals (#87)
SMI-Lab-Inha Nov 7, 2026
10d4df0
feat(openfast): range graphs in coupled runs and a SeaState depth-gri…
SMI-Lab-Inha Nov 7, 2026
b069946
fix(deck): run a static check without dtM (#91)
SMI-Lab-Inha Nov 7, 2026
ba90a42
perf(waves): vectorise the wave component sum (#92)
SMI-Lab-Inha Nov 7, 2026
b11904f
feat(capi): step decks in moving water in-process (#88)
SMI-Lab-Inha Nov 7, 2026
6545ed0
fix(output): report the section under a bend stiffener (#89)
SMI-Lab-Inha Nov 7, 2026
df5606c
ci: run the suite and the examples on the Prescott kernel (#94)
SMI-Lab-Inha Nov 7, 2026
22ce413
feat(python): read the modal output file (#93)
SMI-Lab-Inha Nov 7, 2026
fc16ce7
feat(python): bind the raw-line calls and the load Jacobians (#95)
SMI-Lab-Inha Nov 7, 2026
a15a95d
perf(capi): read a whole line at once, with section curvature and the…
SMI-Lab-Inha Nov 7, 2026
9381284
fix(openfast): retries at any dtM, CalcSteady, FAST.Farm range files …
SMI-Lab-Inha Nov 7, 2026
7d66c91
fix(output): the geometric curvature and section moment of a stretche…
SMI-Lab-Inha Nov 7, 2026
103967d
feat(waves): per-component direction and a reference point for wave r…
SMI-Lab-Inha Nov 7, 2026
8244887
feat: a seabed drift note and initialisation notes for in-process hos…
SMI-Lab-Inha Nov 7, 2026
cf5d48a
fix(openfast): restart from a checkpoint at any glue step (#101)
SMI-Lab-Inha Nov 7, 2026
63e3f26
docs(changelog): record the changes since 0.4.0 (#102)
SMI-Lab-Inha Nov 7, 2026
af95000
fix(waves): a MoorDyn-C mean level is added to the elevation alone (#…
SMI-Lab-Inha Nov 8, 2026
58e1290
release: CableDyn 0.4.1
SMI-Lab-Inha Nov 8, 2026
f8f1e1a
chore(release): rerun the experiment records with 0.4.1
SMI-Lab-Inha Nov 8, 2026
e8f88f5
chore(release): the 0.4.1 release record
SMI-Lab-Inha Nov 8, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions .github/workflows/fortran.yml
Original file line number Diff line number Diff line change
Expand Up @@ -89,3 +89,55 @@ jobs:
OMP_NUM_THREADS: "1"
OPENBLAS_NUM_THREADS: "1"
run: ctest --test-dir build --output-on-failure --parallel 4

# Round-off fragility: a result that depends on the BLAS kernel fails here although every
# job above, on the runner's own kernel, passes. Prescott, an SSE3 kernel of the conda-forge
# OpenBLAS, sums in another order than the AVX2 and AVX-512 kernels the runners select.
# This job is advisory: branch protection names the jobs above, not this one.
roundoff:
name: round-off kernel (conda gfortran, ubuntu-latest, Prescott)
runs-on: ubuntu-latest
env:
OPENBLAS_CORETYPE: Prescott
defaults:
run:
shell: bash -el {0} # login shell so the conda env is active
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false

- name: Set up the conda toolchain (gfortran, CMake, OpenBLAS, LAPACK)
uses: mamba-org/setup-micromamba@f457c30a868e4760d3a6fcea5f25dc655b8edf39 # v3.2.1
with:
environment-file: environment.yml
cache-environment: true

- name: Show toolchain
run: gfortran --version && cmake --version

- name: Configure
run: cmake -S . -B build -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release

- name: Build
run: cmake --build build --parallel

- name: Confirm the OpenBLAS kernel
# OPENBLAS_CORETYPE works only on a dynamic-architecture OpenBLAS and is otherwise
# ignored without a word: stop here rather than pass on the runner's own kernel.
run: >-
python tests/check_example_fallbacks.py --driver build/cabledyn --examples examples
--out build/kernel_check --coretype "$OPENBLAS_CORETYPE" --kernel-only

- name: Test (CTest)
# As in the job above: four tests at once, each single-threaded. The few tests that
# pin a kernel of their own set OPENBLAS_CORETYPE themselves.
env:
OMP_NUM_THREADS: "1"
OPENBLAS_NUM_THREADS: "1"
run: ctest --test-dir build --output-on-failure --parallel 4

- name: Example decks without a fallback note
run: >-
python tests/check_example_fallbacks.py --driver build/cabledyn --examples examples
--out build/example_scan --coretype "$OPENBLAS_CORETYPE" --jobs 4
2 changes: 1 addition & 1 deletion ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -446,7 +446,7 @@ src/
CableDyn_Hydro.f90 Morison loads, Airy and JONSWAP waves, currents
CableDyn_WaveSpectra.f90 spectra, spreading, and multi-train seas
CableDyn_StreamWave.f90 stream-function regular nonlinear waves
CableDyn_WaveMath.f90 block sine/cosine and exponential of the wave kinematics
CableDyn_WaveMath.f90 block sine/cosine, exponential and lane sums of the wave kinematics
CableDyn_Vessel.f90 vessel kinematics, 6-DOF motion, displacement RAOs
CableDyn_SeabedContact.f90 C1 normal contact and stick-slip friction laws
CableDyn_Bathymetry.f90 gridded bathymetry
Expand Down
132 changes: 131 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,135 @@ All notable changes to CableDyn are recorded in this file. The format follows

## [Unreleased]

## [0.4.1] - 2026-11-08

### Added

- In-process stepping in moving water (ABI 1.4). On decks with finite-EI lines, bodies or rods
the C API and Python march a steady deck current (`current`, WaterKin `CurrentMod 1`, MoorDyn-C
`Currents 1`), in the static start and in every step. A host can instead supply the fluid at
every line node: `CableDyn_SetHostFluid`, `CableDyn_NFluidNodes`,
`CableDyn_GetFluidNodePositions` and `CableDyn_UpdateFluidFields`, in Python `set_host_fluid`,
`n_fluid_nodes`, `fluid_node_positions` and `update_fluid_fields`. The field is sampled and held
as in the standalone march and in OpenFAST; in current and waves a stepped cable matches the
standalone driver to the digits of its output.
- `Line.section_curvature()` and the C API quantity `CD_C_LINE_SECTION_CURVATURE` return `CurvX`
and `CurvY` at every node of a finite-EI line in one evaluation.
- `CableDyn_GetInitNotes` in the C API and `CableDyn.init_notes` in Python: the notes of the last
deck initialisation on the point route and the aggregate, for a host that does not read the
standard streams.
- Python: `CableDyn.init_line`, `init_lines` and `calc_output_derivatives` bind the raw-array line
calls and the load Jacobians of the C API.
- Python: `read_output` reads both tables of `<root>.modes.out` into `NaturalModes` and
`ModeShapes`; `DriverResult` gains `modes_output` and `read_modes()`.
- Range graphs in coupled OpenFAST runs: the `LINES` `Outputs` flag `r` and `RangeStart` now write
`<RootName>.CD.Line<L>.range.out` in a single-turbine run, from the committed `dtM` steps of
`.CD.out`, once per step when OpenFAST retries a step, and across a checkpoint restart. A
turbine's own instance in FAST.Farm writes `<RootName>.T<n>.CD.Line<L>.range.out`. A FAST.Farm
shared mooring and the C API reject the flag by name.
- An OpenFAST initialisation note when the deepest interval of the SeaState depth grid exceeds 5 %
of the depth and a line lies in it: the field is linear there, unlike a deck depth table.
- An initialisation note names the lines that a current can move along a seabed without friction.
- `WaveKin 7`: each row of `wave_frequencies.txt` may carry its own `beta`, as MoorDyn-C reads it,
so that a component file can describe a short-crested sea; vessel RAOs take each row's heading.
- `WaveRefX` and `WaveRefY` options: the point that an elevation record or a component file
(`WaterKin WaveKinMod 1`, `WaveKin 3` and `7`) refers to. An extension of CableDyn; default 0, 0.
- CI: a Linux job runs the full test suite on the Prescott OpenBLAS kernel and fails on a fallback
note in any shipped example deck.

### Changed

- A standalone deck with `TMax 0` no longer needs `dtM`: the static check marches no step, so it
runs without one on every standalone route and writes the same `t = 0` row as with one. A
mixed deck that marches no step no longer prints the `dtM` advisory.
- Wave kinematics cost half to a fifth as much, depending on the compiler: on a 298-node line
in a 4,200 s elevation record of 2,400 components the sum falls from 6.0 to 3.0 ms per step
in the release build and from 18 to 3.6 ms in a GNU AVX2 build. Results change at round-off.
- `CableDyn_GetLineValues` evaluates the position, velocity, acceleration, tension, curvature,
bend moment, declination and azimuth of a line in one pass, without a text token per node. The
values are unchanged bit for bit. A read of `EI = 0` tension was O(n²) and is now linear.
- A coupled run restarts from a checkpoint at any glue step: `ChkptTime` need not be a multiple of
`dtM`, and the restarted run matches the uninterrupted one bit for bit.
- Range graphs are written when the host reports a completed run, so also at FAST.Farm's last
whole `DT_Low` and after `CalcSteady`. An earlier run's range graphs are removed as soon as the
deck is parsed, and a run that stops on an error writes none.
- The Python deck validator reads the files a deck names (WaterKin, the MoorDyn-C kinematics
files, motion and vessel records, the RAO table, bathymetry, Syrope) and refuses what the solver
refuses.
- A direction bin below the smallest normal weight holds no energy: its components are exactly
zero, and a vessel RAO table needs no heading for it.
- The C API refuses the flag `r` on `EI = 0` decks too, which it accepted without writing a file.

### Fixed

- Nodal curvature under a tapered bend stiffener: a node took the stiffness of the softer
neighbouring element, which steps at every node of a taper, and so overstated the curvature
by about `h |EI'| / (2 EI)`. It now takes the stiffness `EI(s)` at the node, and the softer
side only at a real step of the section (the bare tip, stiffener rows that do not match, two
line types).
- Element curvature under a tapered bend stiffener: the peaks of `.elements.out` and the node
values of `OutputRecovery element` read the element's interpolation, which bends under one
stiffness per element. Against the section its curvature is off by the same `h |EI'| / (2 EI)`,
high where the curvature falls toward the tip and low where it rises. On an element with a
sleeve they now report the section: the moment over `EI(s)`.
- Curvature and bend moment of a stretched finite-EI line: the node outputs read the conjugate of
the tangent as the moment, which put `Curv` 2 ε and `BendMom` ε below their definitions.
`Curv` is now the geometric curvature of the stretched line and `BendMom` the moment that
balances the forces, `EI κ / (1 + ε)`.
- An `EI = 0` line whose deck chord heads within 45 degrees of +X reported its azimuth in [0, 360)
instead of (-180, 180] outside the standalone `EI = 0` route: in the C API and Python, on the
standalone mixed and multibody routes, and in OpenFAST. Its `L<L>N<J>Azi` channels, the
`Azimuth` column of the static profile and the azimuth of the initialisation summary now follow
the documented range on every route.
- A solver step retry in OpenFAST works at any `dtM/DT` and matches an unretried step exactly,
including across a restart; it rebuilt the model at `dtM = DT` and stopped at `dtM > DT`.
- `CalcSteady` with several operating points no longer stops at the second, works at `dtM` larger
than `DT`, and `.CD.out` and the range graphs run to the end of its run. `-VTKLin` works at `dtM`
larger than `DT`. Linearisation after `CalcSteady` or after a restart keeps its line states.
- A restart before the first commit keeps a body or rod at its start, and a restart no longer
rewrites `.CD.static.out`.
- Every initialisation note of a coupled line reaches the console; long lists were cut or dropped.
- The OpenFAST module driver runs a rotating motion in a single-precision build.
- A range-graph file that cannot be written completely is removed instead of left behind.
- A mean level in a MoorDyn-C kinematics file, a non-zero `omega = 0` row of `WaveKin 7` or the
mean of a `WaveKin 3` record, is added to the elevation alone, as MoorDyn-C does: the wave
numbers stay those of `WtrDpth` and the stretching maps the water under the total elevation.
CableDyn took the wave numbers at `WtrDpth` plus the level. With a 0.8 m level in 50 m of water
and six components in six directions, `WaveKin 7` now matches MoorDyn-C v2.7.2 to 1e-8 instead
of 7.7e-3 m in elevation and 1 % in velocity. The mean of a WaterKin `WaveKinMod 1` record still
raises the still-water level; MoorDyn-F drops it.
- The C API messages of `CableDyn_UpdatePointFluidFields` and `CableDyn_CalcOutputDerivatives` on
the coupled aggregate name its real scope: decks with finite-EI lines, bodies or rods.

### Upgrading

- `Curv`, `CurvX`, `CurvY`, `BendMom` and `StfMom`, and the `Curvature` and `BendMoment` of the
static profile and the range graphs, change at nodes inside a bend stiffener. Curvature and
`BendMom` fall by that first-order error, on `lazy_wave_bend_stiffener.dat` by about 5 % on
0.2 m elements, 4 % on 0.15 m, 2 % on 0.1 m and 0.7 % on 0.05 m; `StfMom` rises by the same
moment, so the two still add up to the section moment. A line end on a conical root
changes likewise, and a step between rows on a taper now compares the two stiffnesses at the
node. Positions, forces, the section moment and every node outside a stiffener are unchanged.
- `PeakCurvature`, `BendMomentAtPeak` and `PeakXi` of `.elements.out`, so `bend_check` and
`element_range_graph` on that table, change on elements with a stiffener sleeve, and so do
`Curv`, `CurvX` and `CurvY` under `OutputRecovery element` at their nodes, where they now equal
the default recovery. The peaks fall by 1.6 / 3.1 / 5.8 % on 0.05 / 0.1 / 0.2 m elements of a
hang-off whose curvature falls toward the tip, and rise by up to 4.4 % on the 0.15 m elements of
`lazy_wave_bend_stiffener.dat`, whose curvature rises. Elements without a sleeve are unchanged,
and `CD_HermiteCable_Dyn_Curvature_Exact` stays the geometric trace.
- `Curv`, `CurvX`, `CurvY`, `BendMom` and `StfMom`, and the `Curvature` and `BendMoment` of the
static profile and the range graphs, rise on every finite-EI line: curvature by twice the axial
strain, the moments by the strain, at most 0.024 % and 0.012 % on the examples. `BendMom` equals
`EI × Curv` only to within the strain. Tension, positions and forces are unchanged, and so are
`OutputRecovery element` values on elements without a stiffener sleeve.
- Azimuth values of the `EI = 0` lines named above read 360 degrees lower on those routes.
- On a `WaveKin 3` or `WaveKin 7` deck whose mean level is not zero, the elevation away from the
origin, the fluid velocity and acceleration, and so the loads and every output, change by the
order of the level over the depth: up to 1 % in velocity at 0.8 m in 50 m. A deck with no mean
level is unchanged bit for bit.
- OpenFAST checkpoints change format: they carry the range graphs and the input of the last
commit, so a checkpoint written by an earlier CableDyn cannot be restarted with this one.

## [0.4.0] - 2026-11-04

### Added
Expand Down Expand Up @@ -689,7 +818,8 @@ Corrections made during the pre-release review.
values of the shipped example decks and states which tension (end element or
`FairTen` end force) each comparison uses.

[Unreleased]: https://github.com/SMI-Lab-Inha/CableDyn/compare/v0.4.0...HEAD
[Unreleased]: https://github.com/SMI-Lab-Inha/CableDyn/compare/v0.4.1...HEAD
[0.4.1]: https://github.com/SMI-Lab-Inha/CableDyn/releases/tag/v0.4.1
[0.4.0]: https://github.com/SMI-Lab-Inha/CableDyn/releases/tag/v0.4.0
[0.3.0]: https://github.com/SMI-Lab-Inha/CableDyn/releases/tag/v0.3.0
[0.2.0]: https://github.com/SMI-Lab-Inha/CableDyn/releases/tag/v0.2.0
Expand Down
4 changes: 2 additions & 2 deletions CITATION.cff
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ authors:
repository-code: "https://github.com/SMI-Lab-Inha/CableDyn"
url: "https://github.com/SMI-Lab-Inha/CableDyn"
license: Apache-2.0
version: 0.4.0
date-released: 2026-11-04
version: 0.4.1
date-released: 2026-11-08
keywords:
- mooring dynamics
- cable dynamics
Expand Down
Loading
Loading