Developing CableDyn
This guide is for developers who build and test CableDyn from source. It lists the commands for the environment, build, tests, Python package, documentation, and integration with OpenFAST, maintained by NLR (National Laboratory of the Rockies, formerly NREL). Contribution rules are in CONTRIBUTING.md; the release procedure is in RELEASE.md.
Environment
Requirements: conda (Miniconda, Miniforge, or Anaconda) on Linux, macOS, or
Windows, and git. environment.yml provides conda-forge gfortran, a C compiler,
CMake, Ninja, Make, OpenBLAS/LAPACK, Python, and the developer tools
(pre-commit, fprettify). Do not mix the conda gfortran with a system gfortran
or Intel IFX.
conda env create -f environment.yml
conda activate cabledyn
pre-commit install
Build and test
cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release
cmake --build build --parallel
ctest --test-dir build -L fortran -LE slow --output-on-failure # fast tier
ctest --test-dir build --output-on-failure # full suite
The standalone driver is build/cabledyn (build\bin\cabledyn.exe with the conda
toolchain on Windows, where CMake stages the runtime DLLs and every executable in
build\bin); a build with an MSVC-style linker (Intel IFX) and the static release
build name the same program CableDyn_driver.exe. On Windows, add
-DCMAKE_C_COMPILER=gcc if CMake would otherwise pick a Visual Studio C compiler, so the
C sources build with the conda MinGW gcc that matches gfortran (as CI does).
The Debug configuration (-DCMAKE_BUILD_TYPE=Debug) adds -fcheck=all -fbacktrace. CMake finds LAPACK with find_package(LAPACK) and falls back to the
conda OpenBLAS through CONDA_PREFIX. cmake --install build --prefix stage
installs the driver, the shared library, and CableDyn_CAPI.h.
A Windows build with gfortran links every executable with a 64 MiB stack reserve
(the MinGW default is 2 MiB). With OpenMP enabled, gfortran keeps fixed-size local
arrays on the stack, and the stack depth of the OpenBLAS kernels differs between
CPUs, so a small reserve can pass on one machine and overflow on another. The
shared library cannot rely on this reserve: the host program (for example
python.exe, which reserves about 2 MB) sets the stack of the threads that call
it. The -L stack tests check the library on a thread with a 1 MiB stack and, in
a Windows gfortran build, the driver and the modal test relinked with a 1 MiB
reserve and the reserve written into each executable.
Selection |
Tests |
|---|---|
|
All Fortran tests |
|
Fast tier |
|
Long validation cases |
|
The 10 analytical cases |
|
Static and dynamic solver tests |
|
End-to-end driver and aggregate tests |
|
OpenFAST shell and aggregate tests |
|
IEA-15MW VolturnUS-S mooring comparisons |
|
Secondary Cosserat path |
|
Python package, deck-style, and documentation checks |
|
Library, driver, and modal test on a 1 MiB stack |
A test program can also be run directly from the build tree (build/, or
build\bin\ with the conda toolchain on Windows); it prints PASS: or
stops at the first mismatch. The Fortran CI workflow builds Release and Debug on
Ubuntu and Windows and runs the full suite on every pull request and push to
main.
Python package
The cabledyn package (python/) loads the C-ABI shared library built by
cmake --build build --target cabledyn_shared. The python_package CTest runs its
tests when the configured Python has numpy and pytest. To work on the package
directly:
python -m pip install -e ".\python[dev]"
$env:CABLEDYN_LIBRARY = "<path to the built libcabledyn shared library>"
python -m pytest python/tests -q
cd python; python -m ruff check cabledyn tests; python -m ruff format --check cabledyn tests; python -m mypy; cd ..
The fatigue (test_fatigue.py) and spectral (test_spectra.py) tests do not load
the shared library. They compare against independent references (the ASTM E1049
cycle table and analytical sinusoids); do not replace these with snapshots of
CableDyn output.
On Windows, run Python from the activated cabledyn environment and point
CABLEDYN_LIBRARY at the DLL. Do not prepend compiler or OpenBLAS runtime
directories to PATH before importing NumPy: mixed runtime DLLs can terminate
Python during NumPy initialisation.
Documentation
python -m pip install -r doc/requirements.txt
python -m sphinx -W --keep-going -n -b html doc doc/_build/html
python tests/test_documentation.py
Markdown files outside doc/ that the manual includes (CHANGELOG.md,
CONTRIBUTING.md, DEVELOPMENT.md, VALIDATION.md) must link to repository
files with absolute https://github.com/SMI-Lab-Inha/CableDyn/blob/main/...
URLs.
Formatting and checks
pre-commit run --all-files
fprettify --indent 2 --line-length 120 src/<file>.f90
The hooks check whitespace, end-of-file, merge markers, YAML, large files, Fortran
formatting (fprettify; src/openfast/ is excluded), Python lint and formatting (ruff),
and release metadata.
Fortran lines longer than 120 columns must be split with & before formatting.
Coding standards
Fortran
Fortran 2018, free form,
IMPLICIT NONEin every program unit.Real kind
wpfromCableDyn_Precision; neverREAL*8orDOUBLE PRECISION.Modules are named
CableDyn_<Function>; subroutinesCD_<Action>_<Object>(for exampleCD_Assemble_Cable_Mass).Public subroutines take
ErrStat (INTEGER, INTENT(OUT))andErrMsg (CHARACTER(*), INTENT(OUT)).LAPACK: banded solvers (
DGBSV, andDPBTRF/DPBTRSfor symmetric positive definite bands); a dense assembly is packed into band storage before the solve.Warning-clean under
-std=f2018 -Wall -Wextra -fimplicit-nonewith gfortran 15 and 16. gfortran 16 can report-Wuninitializedfor a default-initialised local derived-type variable with allocatable components: the optimiser copies the unset bounds of its unallocated arrays, which the program never reads. Such a local isALLOCATABLEwhere this occurs.Keep large data off the stack: a local array or derived-type variable that can exceed about 64 KB is
ALLOCATABLE, except on the per-step path, which uses the preallocated workspaces and does not allocate.
SPDX headers
Every source file starts with:
! File: <path>
! SPDX-License-Identifier: Apache-2.0
! Copyright (c) 2026 Jae Hoon Seo, SMI Lab, Inha University
Use the comment syntax of the language (# for Python, PowerShell, and YAML).
OpenFAST integration
The OpenFAST host module in src/openfast/ compiles only inside an OpenFAST
source tree. To build and check it locally:
git clone https://github.com/OpenFAST/openfast.git <openfast>
git -C <openfast> checkout 2895884d2be01862173c88d70f86b358d2f1a50a
./integration/openfast/prepare_openfast_source.ps1 -OpenFASTRoot <openfast>
cmake -S <openfast> -B <openfast-build-dir> -DCABLEDYN_ROOT=<CableDyn checkout>
powershell -File integration/openfast/openfast_build_gate.ps1 -BuildDir <openfast-build-dir> -CaseFst <case.fst>
openfast_build_gate.ps1 builds openfast.exe, runs a CompMooring = 5 case,
checks that the CableDyn banner appears in the log, and checks that the output is
finite.
An openfast.exe built this way through CMake does not embed the UTF-8
active-code-page manifest (app/utf8_code_page.manifest), so on Windows it may not
open input files in folders whose names the system code page cannot spell. The
static release build (release/build_static_windows.ps1, which uses the OpenFAST
Visual Studio solution) embeds the manifest. See
integration/openfast/README.md
for details.
Troubleshooting
Symptom |
Cause |
Fix |
|---|---|---|
|
environment not activated |
|
|
no system LAPACK |
install |
Python exits while importing NumPy on Windows |
runtime DLL directories on |
remove them from |
Windows checkout differs from CI |
CRLF line endings |
|