Repository navigation
CableDyn 0.3.0 - #48
Merged
Merged
Conversation
RELEASE.md closes a release by adding an empty [Unreleased] section to the changelog; it compares against the v0.2.0 tag. Signed-off-by: Jae Hoon Seo <jaehoon.seo@inha.ac.kr>
The run-time profile (CABLEDYN_PROFILE=1) counted the steps and Newton iterations of EI = 0 lines but did not say where their time went, and it reported the factorisation and back-substitution of finite-EI cables as one "linear solve". Deciding whether a reused, scheduled factorisation is worth building needs both. The step of an EI = 0 line now times its residual-only evaluations, its residual and tangent evaluations, its LU factorisations and its back-substitutions (CableDyn_Profile kernel counters, updated atomically because lines step concurrently; their times are summed over the lines). The finite-EI cable profile times its factorisations apart from its back-substitutions, which now also include the force-blend correction that ends each step. The standalone driver and the OpenFAST module report both; the OpenFAST module arms and disarms the line counters with its own profiler. Unprofiled, every new entry point returns after one test: three decks run in the same time as with 0.2.0 (ratios 0.96-1.00) and write byte-identical outputs, and the driver tests check that every output file is identical with and without the profile. Signed-off-by: Jae Hoon Seo <jaehoon.seo@inha.ac.kr>
…#35) The first coupled profile showed that, on a mooring with a finite-EI power cable, CalcOutput and the SeaState sampling cost as much as the mooring step itself, and that the cable step is dominated by its residual and tangent assemblies. Choosing what to optimise first needs the inside of each. The residual and tangent assembly of a finite-EI cable now times its sections (band zeroing, tangent element kernels, tangent scatter, structural residual, weight, attachments, dry buoyancy, seabed contact, axial damping, drag, end connections, wave and held Froude-Krylov loads, torsion). The OpenFAST module splits CalcOutput into the overlay of the current kinematics, the output channels and the restore of the committed state, and the SeaState sampling into the node queries, the grid checks and the hand-over of the fields. The standalone driver and the OpenFAST module report them. Unprofiled, each new timer is skipped after one test; outputs are byte-identical with and without the profile. Signed-off-by: Jae Hoon Seo <jaehoon.seo@inha.ac.kr>
At the glue rate (nsuper = 1) CalcOutput saves the committed coupled kinematics, transfers the current ones, evaluates the loads and channels and restores the committed state. The save read the kinematics with CD_AGG_GetMovingPointMesh, which also evaluated the reaction of every finite-EI cable (a full residual and added-mass assembly) only for the caller to overwrite it with the loads evaluated after the transfer. The profile put this at 17 of the 41 s of CalcOutput in a 600 s run of the IEA-15 VolturnUS-S with a 248-element power cable. CD_AGG_GetMovingPointMesh takes an optional cable_loads = .FALSE. that skips the cable reactions and returns their load columns as zero; the save uses it. The reactions write only the cable's scratch, which the loads evaluation that follows overwrites, so the outputs are unchanged: the coupled chain-only and mixed runs write byte-identical OpenFAST and CableDyn outputs, and the mixed run takes 212 s instead of 227 s. Signed-off-by: Jae Hoon Seo <jaehoon.seo@inha.ac.kr>
The reaction of a finite-EI cable at a node (the fairlead load the OpenFAST module returns on every CalcOutput) assembled the residual and the added mass of the whole line and multiplied the whole mass by the acceleration, to read three rows. With a 248-element power cable this was 20 s of a 212 s coupled run. assemble_residual takes an optional node_only with a caller residual R_out: it assembles only the elements that reach the node and the node's own terms (attachments, contact, end connection), each in the order of the full assembly, so the node's rows are bit-identical and the model's scratch is not touched. The contact and attachment assemblies take node bounds, and contact writes through the residual it is given. The reaction builds the node's rows of the added mass from the same one or two element matrices and forms the inertia column by column as band_matvec does. A line with torsion, which couples every element, keeps the full assembly, as does full_assembly = .TRUE. test_hermite_node_reaction compares the two at every node, bit for bit, on hand-built cables with every load section (contact with friction on a controlled seabed, attachments, axial damping, drag, added mass, Airy waves or a held field, finite, rigid or no end connections) at scattered states, and along a coupled trajectory of the IEA-15 MW mixed mooring example, also after a fairlead transfer; it fails when the inertia sum is reordered. All 51 examples write byte-identical outputs, and the coupled chain-only and mixed OpenFAST runs write byte-identical outputs, the mixed one in 194 s instead of 212 s. Signed-off-by: Jae Hoon Seo <jaehoon.seo@inha.ac.kr>
A coarser mooring step is the main way to make coupled runs cheaper, but nothing told a user when dtM was too coarse for a line. With the IEA-15 MW mixed example in a turbulent 600 s OpenFAST run, the power cable (axial period 0.351 s) matches the dtM = DT fairlead tension within 0.3 % of its standard deviation at dtM = 0.05 s (7 steps per period), but at 0.1 s (3.5 steps) its axial dynamics are damped and its peak tension is about 35 % high; the chains (0.78 s) keep their tension statistics within 0.3 % at 0.1 s. At initialisation each line's axial period is estimated as that of a bar fixed at both ends, twice the sum over its sections of the length over sqrt(EA/m) (unstretched lengths, dry mass, the dynamic EA of a constant-stiffness viscoelastic type). A line that dtM resolves in fewer than six steps gets an initialisation note with the period, the number of steps and a dtM that resolves it, on the standalone, mixed and OpenFAST routes. Load-dependent types (ElasticMod 3, Syrope) are not assessed. Nothing else changes. The FAQ and the OpenFAST tutorial still gave 0.1 s as the OpenFAST default dtM; since 0.2.0 it is the glue DT. Signed-off-by: Jae Hoon Seo <jaehoon.seo@inha.ac.kr>
With dtM larger than the glue DT, CableDyn solves once per nsuper glue steps and held its loads between solves, so the platform received them on average dtM/2 late: a first-order lag that acts as negative damping of about the mooring stiffness times dtM/2. This is why 0.2.0 defaults to dtM = DT, at four times the mooring cost of dtM = 0.1 s. Between solves the loads are now extrapolated from the last two committed solves, F = F_c + tau (F_c - F_p) with tau the fraction of the mooring step elapsed, clamped to [0, 1]; the error is second order in dtM. The extrapolation is used only between consecutive commits, so the first step keeps the held loads. CD_UpdateStates shifts the served loads into the previous ones when a mooring step starts (not on a correction re-entry over the same step), keeping CalcOutput state-const, and mirrors them into the OtherState (pred_t, pred_loads), so a restart continues the extrapolation. The output channels and the .CD.out keep the committed samples. The deck OPTION predictLoads (default True) switches it; False keeps the hold. The arithmetic lives in CableDyn_LoadPredictor and is unit-tested. IEA-15 MW VolturnUS-S, turbulent 600 s DLC-1.6, dtM = 0.1 s against dtM = DT = 0.025 s: the platform surge, sway, roll and pitch differ by at most 0.12 % of their standard deviation (0.42 % held), on the chain and on the chain and power-cable mooring; the chain-only run takes a fifth less time (116 s against 141 s). Runs at dtM = DT are byte-identical, and with predictLoads False the outputs equal the held runs byte for byte. Signed-off-by: Jae Hoon Seo <jaehoon.seo@inha.ac.kr>
…art (#40) A committed mooring step holds the SeaState fields sampled at its interval end at the node positions of its start. On openfast -restart the module re-sampled them at the restored, end-of-step positions. At dtM = DT this was harmless, because the next solve re-samples before any load is served; with dtM larger than DT the loads served until the next solve came from the re-sampled fields, and the restarted run drifted from the uninterrupted one (up to 2e-3 of a tension's standard deviation in the CableDyn record, on held and extrapolated loads alike). A full-precision trace placed the first difference at the first load served after the restart, with identical host inputs. The OtherState carries the held fields (fluid_held: velocity, acceleration, free-surface elevation and dynamic pressure at the line nodes), saved at Init and at every committed step, and the restart hands them back to the aggregate instead of re-sampling. OpenFAST checkpoints are not versioned, so a checkpoint written by an earlier CableDyn (without these or the load predictor's fields) cannot be restarted with this one; the CHANGELOG says so. openfast -restart at 50 s now reproduces every later OpenFAST and .CD.out row of the IEA-15 VolturnUS-S chain mooring at dtM = 0.1 s (extrapolated and held loads) and at dtM = DT, and of the chain and power-cable mooring at dtM = 0.05 s. Uninterrupted runs do not change. Signed-off-by: Jae Hoon Seo <jaehoon.seo@inha.ac.kr>
The coupled time-step work (#38 to #40) lets CableDyn solve on a dtM larger than the OpenFAST DT. This records the verification of that change on the IEA-15 MW VolturnUS-S chain mooring in a DLC-1.6 environment (NTM 10.6 m/s turbulent wind, JONSWAP Hs 8 m / Tp 12 s, 3800 s), at dtM = 4 DT = 0.1 s against the same model at dtM = DT and against stock MoorDyn. With the coupled loads extrapolated between CableDyn solves, every platform DOF's time series differs from the dtM = DT run by at most 0.14 % of its standard deviation (0.41 % held), the tension statistics stay within 0.16 %, and the rainflow damage-equivalent loads change by at most 0.21 % at the fairleads and 1.5 % at the anchors, of the order of the reference's own sampling effect (0.94 %). Against stock MoorDyn the in-plane platform standard deviations agree within 0.03 %. validation/scripts/openfast_supercycle_ab.py computes these figures from the twin runs; its rainflow count (ASTM E1049, four-point method, half-cycle residue, a plateau of equal samples counted once) is tested against the standard's worked example. Every statistic of a run, its DEL change included, is taken over the samples it shares with the reference, and a run covering fewer of them is flagged. Signed-off-by: Jae Hoon Seo <jaehoon.seo@inha.ac.kr>
The cabledyn package was published only as a pure-Python wheel: it loads the CableDyn shared library and runs the standalone driver, but the user had to build or download both separately. This prepares publication on PyPI. A root pyproject.toml (scikit-build-core) builds an sdist of the sources and a platform wheel. CMake builds only the cabledyn_shared and cabledyn targets, serially, and under scikit-build installs them through the `python` component: the library beside the package modules, where cabledyn._discovery already looks first, and the driver in cabledyn/bin. The wheel is tagged py3-none-<platform>, since the package reaches the library through ctypes. The sdist leaves out the validation records, the manual, the OpenFAST integration and the release tooling, and builds a wheel on its own. The driver search takes the bundled driver after CABLEDYN_DRIVER and before PATH, under either toolchain name (CableDyn_driver, cabledyn). python/pyproject.toml stays the pure package for development against a build tree; tests/test_packaging_metadata.py keeps the two [project] tables identical except for the readme, licence files and platform classifiers, and the release checks cover the new file. Signed-off-by: Jae Hoon Seo <jaehoon.seo@inha.ac.kr>
The wave kinematics and the element kernels spend most of their time in vectorised cos/sin/exp, which the release build ran two doubles wide (SSE2). CABLEDYN_TARGET_AVX2 compiles the Fortran core for x86-64-v3 (/arch:CORE-AVX2 with IFX, -march=x86-64-v3 with gfortran 11+), and the static Windows release sets it: the IFX driver runs the benchmark decks 13-33% faster (lazy_wave_vessel_rao 11.9 s to 8.8 s, als_volturnus_line_break_time 35.5 s to 23.9 s). Contraction into fused multiply-adds stays off (/Qfma-, -ffp-contract=off): with it the compiler fuses the same expression differently where it is inlined, and a restored instance no longer continued a run bit for bit (test_line_attachments). src/cabledyn_cpu_guard.c, compiled for baseline x86-64, checks the processor before any Fortran code runs and stops a program on an older one with a message naming the missing instructions (exit 3). It writes with the operating system's calls only: in the Windows GNU build the C library names can resolve to openblas.dll's exports and import it at load time. CABLEDYN_CPU_GUARD_SIMULATE exercises the stop on any processor; the release script checks it for both executables, and the driver's --version and the OpenFAST module's start-up lines report the x86-64-v3 build. Signed-off-by: Jae Hoon Seo <jaehoon.seo@inha.ac.kr>
.github/workflows/wheels.yml builds the published distribution as workflow artifacts (manual runs, published releases, and pull requests that touch the packaging); publishing stays a separate step: - sdist, checked with twine; - Linux x86-64 (cibuildwheel, manylinux_2_28, image GCC toolset): OpenBLAS and the Fortran runtime bundled by auditwheel, built for x86-64-v3 (CABLEDYN_TARGET_AVX2), as the Windows release; - macOS arm64 (cibuildwheel, Homebrew gfortran and OpenBLAS, bundled by delocate, deployment target 14.0); - Windows x86-64 (release/build_windows_wheel.ps1): the static release configuration with IFX and MSVC and the release's pinned reference LAPACK; dumpbin checks that the library and the driver import only Windows system DLLs. release/smoke_test_wheel.py installs nothing itself: run in a clean environment with the wheel installed, it requires the package to load the library it carries and select the driver it carries, the driver to report the expected build (--expect-build), and a standalone deck to run. tests/test_packaging_metadata.py keeps the reference LAPACK version, checksum and flags of the wheel and release scripts equal. The Windows wheel is inspected with System.IO.Compression.ZipFile and an explicit extension filter (Windows PowerShell 5.1's Expand-Archive refuses .whl, and its Get-ChildItem -LiteralPath ignores -Include), and the static release's shared library links with /Qipo like the executables. Signed-off-by: Jae Hoon Seo <jaehoon.seo@inha.ac.kr>
wheels.yml gains two publish jobs that upload the sdist and the three release wheels its build jobs smoke-tested, with no stored token (id-token: write only; the publishers are registered on pypi.org and test.pypi.org for this repository, wheels.yml and the environments pypi and testpypi): - publish-testpypi: a manual run with upload = testpypi; a version already on TestPyPI is skipped; - publish-pypi: a published GitHub release, behind the pypi environment, after checking that the distribution set is one sdist and three wheels of the release tag's version. pypa/gh-action-pypi-publish is pinned to v1.14.2 by commit. RELEASE.md adds the TestPyPI preflight with a clean-environment install and smoke test, the approval step, and the publisher setup of a new repository. DEVELOPMENT.md links RELEASE.md by its repository URL (the Sphinx manual includes DEVELOPMENT.md but not RELEASE.md). Signed-off-by: Jae Hoon Seo <jaehoon.seo@inha.ac.kr>
…tore (#46) A restore followed by a step must be bit-identical to taking that step from the saved state (CableDyn_RestoreState, OpenFAST correction iterations). Restore discarded the committed force cached from the previous step and evaluated it afresh. On a finite-EI cable with seabed friction the two differ in the last bits: the commit's return mapping moves a sliding node's anchor to q - c*dxy, and the spring force from q minus that anchor reproduces the capped force only to rounding. Whether it showed depended on the trajectory (the controlled-cable snapshot test failed on the Linux Debug runner only). Snapshot now keeps the cache with the state, and Restore brings it back unless a setter invalidated the cache since the snapshot (fc_clears counts the invalidations, including the OpenFAST checkpoint reload). The control test asserts the restored cache again instead of clearing the reference's, and the cache comment states what holds. Runs without restores do not change. Signed-off-by: Jae Hoon Seo <jaehoon.seo@inha.ac.kr>
…47) The equilibrium recovery of finite-EI node values spread each node's floor reaction over the elements beside it by tributary length, including the touchdown element, which lies on the floor at one end only. That understated the tension of the last suspended node by the floor reaction of half an element: 5.3 % on a 10 m lazy-wave mesh against a mesh four times finer. A node's reaction is now shared by the grounded elements beside it (both nodes on the floor); a node with none keeps the tributary split. The coarse mesh follows the fine one within 3 % through touchdown (tests/check_touchdown_recovery.py fails on the old recovery). The node-value cache keys on the neighbouring nodes' positions as well, since their contact now decides an element's share. Line end forces and the solution do not change. The larger coarse-mesh wiggle comes from seabed friction, which acts at the nodes: as the line lands and lifts, a grounded element locks or releases up to mu w L, and the laid tension swings by that much (std 491, 136, 42, 33 N with 10, 5, 2.5, 1 m elements on the same cable). At initialisation a finite-EI line whose grounded elements lock more than 15 % of the touchdown tension now gets a note with the grounded element length that resolves it (flat seabed; standalone and OpenFAST). The manual explains this mesh resolution, the mesh dependence of the negative BA (damping ratio) form, whose ratio holds for each element's own axial mode while the line's modes get zeta n pi / (2N), and the measured trade-off of modified_newton, which stays off by default. A static solve in a current that fails because seabed friction holds the grounded run while the current pushes the suspended span into the touchdown ran the mesh-sequenced route to its iteration budget after the catenary-continuation route had diagnosed it; the frictionless grounded-run diagnosis already skipped that route. Both diagnoses now skip it (the symmetry-breaking pass still runs): the robustness study's 1000 m lazy wave in 440 m of water fails closed in 17.7 s instead of 22 s with the same message, and its 15 converging friction-and-current cases are unchanged. An anchor held exactly on the floor has no contact force of its own, so the grounded-element rule of the node recovery counted its laid end element as suspended and moved the next node's whole floor reaction to the following element; the held-end floor support restored only the anchor's side, leaving a weight moment at the anchor and its neighbour (521 N.m, 31 % of w l0^2/12, on a 100 m line laid on the penalty floor of CD_HermiteCable_Dyn_Init). A held end whose end element the floor supports (held_end_floor_support) now counts as on the floor; test_hermite_cable_static checks the laid line (4.6 N.m left, the bending of the line settling into the floor). Signed-off-by: Jae Hoon Seo <jaehoon.seo@inha.ac.kr>
Set the version to 0.3.0 (released 2026-10-23) in every file the release metadata check names (C API 0.3.0, ABI 1), and replace the unreleased notes with a short [0.3.0] section, one entry per user-visible change. The README, the Python package README (the PyPI project page) and the installation chapter install from PyPI with pip install cabledyn, name the platforms whose wheels carry the solver, and keep the pure wheel of the release page with its driver search. Signed-off-by: Jae Hoon Seo <jaehoon.seo@inha.ac.kr>
validation/RELEASE_0_3_0.md records the source, pins, toolchains, the GNU and CI gates, the Windows executable gates of the release workflow (run 39898803772), the 26-check clean-machine test of the assets and every shipped example with the release driver, the hashes of the release assets and of the preflight PyPI distributions (run 39898806566). The Holcombe and Bergdahl records were re-run with the 0.3.0 GNU build and reproduce byte for byte; their provenance names v0.3.0. Signed-off-by: Jae Hoon Seo <jaehoon.seo@inha.ac.kr>
Owner
Author
|
@codex review |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
Codex Review: Didn't find any major issues. You're on a roll. Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
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". |
This branch was successfully deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Release of CableDyn 0.3.0 from dev, following RELEASE.md. The changes since 0.2.0 are #33 to #47; CHANGELOG.md summarises them in its
[0.3.0]section.Highlights:
pip install cabledyn: the package is on PyPI, with wheels that carry the solver library and the driver:CalcOutputis lighter.dtM > DT:CableDyn_RestoreState, OpenFAST correction iterations) of a finite-EI cable with seabed friction continues bit for bit.The two release commits:
chore(release): prepare CableDyn 0.3.0:chore(release): record the builds and checks of 0.3.0:validation/RELEASE_0_3_0.md, and the provenance of the re-run Holcombe and Bergdahl records.Verification (details in
validation/RELEASE_0_3_0.md)-Wbuild pass.After merging: tag
v0.3.0and publish the GitHub release with the five assets. Publishing starts the PyPI upload, which waits for approval of thepypienvironment.Checklist
pre-commit run --all-filespassesctest --test-dir build --output-on-failurepassespython -m pytest tests python/testspasses (if Python or validation records changed)[Unreleased](heading added if missing) for user-visible changesdoc/updated for changed inputs, options, or outputsfeat:,fix:,docs:, ...) (release PR title per RELEASE.md)git commit -s) under theDeveloper Certificate of Origin