Skip to content

Commit c7e3825

Browse files
committed
Add MoorDyn v2.6.1 submodule and build infrastructure
1 parent 7fa665a commit c7e3825

5 files changed

Lines changed: 227 additions & 8 deletions

File tree

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[submodule "extern/MoorDyn"]
2+
path = extern/MoorDyn
3+
url = https://github.com/FloatingArrayDesign/MoorDyn.git

CMakeLists.txt

Lines changed: 118 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,10 @@ configure_file(${CMAKE_SOURCE_DIR}/cmake/version.h.in
5252
# Add the cmake folder so the FindSphinx module is found
5353
set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH})
5454

55-
# Deterministic dependency discovery (avoid ambient PATH/registry drift)
55+
# Prefer config-mode package discovery (finds vcpkg *-config.cmake files
56+
# instead of CMake's built-in Find*.cmake modules which may not understand vcpkg).
5657
set(CMAKE_FIND_PACKAGE_PREFER_CONFIG ON)
5758
set(CMAKE_FIND_USE_PACKAGE_REGISTRY OFF)
58-
set(CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH OFF)
5959

6060
# Force Release by default so CI builds are optimized and users get good performance
6161
if(NOT DEFINED HYDROCHRONO_DEFAULT_BUILD_TYPE)
@@ -79,6 +79,7 @@ option(HYDROCHRONO_ENABLE_IRRLICHT "Enable Irrlicht visualization library" OFF)
7979
option(HYDROCHRONO_ENABLE_VSG "Enable VSG visualization library" OFF)
8080
option(HYDROCHRONO_ENABLE_DEMOS "Enable demo executables" OFF)
8181
option(HYDROCHRONO_ENABLE_YAML_RUNNER "Enable YAML-based CLI runner" OFF)
82+
option(HYDROCHRONO_ENABLE_MOORDYN "Enable MoorDyn mooring coupling" OFF)
8283

8384
# ===============================================================================
8485
# ------ Build setup ------------------------------------------------------------
@@ -167,6 +168,16 @@ if(NOT Chrono_DIR)
167168
return()
168169
endif()
169170

171+
# Chrono's export file may reference hdf5::hdf5_tools-{shared,static} which is
172+
# absent from some HDF5 installations (e.g., vcpkg). Provide empty shims so
173+
# ChronoTargets.cmake loads without errors. Must be created BEFORE find_package(Chrono).
174+
if(NOT TARGET hdf5::hdf5_tools-shared)
175+
add_library(hdf5::hdf5_tools-shared INTERFACE IMPORTED)
176+
endif()
177+
if(NOT TARGET hdf5::hdf5_tools-static)
178+
add_library(hdf5::hdf5_tools-static INTERFACE IMPORTED)
179+
endif()
180+
170181
find_package(Chrono
171182
CONFIG REQUIRED
172183
COMPONENTS Parsers)
@@ -239,7 +250,33 @@ endif()
239250
find_package(OpenMP REQUIRED COMPONENTS CXX)
240251

241252
# -- HDF5 Integration --
242-
find_package(HDF5 REQUIRED COMPONENTS CXX)
253+
# Prefer config-mode (vcpkg, official HDF5 installer). Fall back to CMake's
254+
# built-in FindHDF5 module for system-installed packages (apt, yum, brew, etc.).
255+
find_package(HDF5 CONFIG QUIET)
256+
if(NOT HDF5_FOUND)
257+
find_package(HDF5 REQUIRED COMPONENTS CXX)
258+
endif()
259+
260+
# -- MoorDyn mooring library (optional) --
261+
if(HYDROCHRONO_ENABLE_MOORDYN)
262+
message(STATUS "\n---- MoorDyn mooring library")
263+
set(EXTERNAL_EIGEN OFF CACHE BOOL "Use MoorDyn bundled Eigen" FORCE)
264+
set(PYTHON_WRAPPER OFF CACHE BOOL "Disable MoorDyn Python wrapper" FORCE)
265+
set(FORTRAN_WRAPPER OFF CACHE BOOL "Disable MoorDyn Fortran wrapper" FORCE)
266+
set(MATLAB_WRAPPER OFF CACHE BOOL "Disable MoorDyn MATLAB wrapper" FORCE)
267+
set(RUST_WRAPPER OFF CACHE BOOL "Disable MoorDyn Rust wrapper" FORCE)
268+
set(BUILD_TESTING_SAVED ${BUILD_TESTING})
269+
set(BUILD_TESTING OFF)
270+
add_subdirectory(extern/MoorDyn)
271+
set(BUILD_TESTING ${BUILD_TESTING_SAVED})
272+
# MoorDyn is a shared library (DLL) -- its internal Eigen usage must not
273+
# leak into HydroChrono's include paths (HydroChrono uses Chrono's Eigen).
274+
set_target_properties(moordyn PROPERTIES
275+
INTERFACE_INCLUDE_DIRECTORIES ""
276+
)
277+
message(STATUS "MoorDyn mooring coupling: ENABLED")
278+
message(STATUS "----\n")
279+
endif()
243280

244281
# ===============================================================================
245282
# ----- Create HydroChrono configuration header ---------------------------------
@@ -261,6 +298,12 @@ else()
261298
set(HC_HAS_VSG "#undef HYDROCHRONO_HAVE_VSG")
262299
endif()
263300

301+
if(HYDROCHRONO_ENABLE_MOORDYN)
302+
set(HC_HAS_MOORDYN "#define HYDROCHRONO_HAVE_MOORDYN")
303+
else()
304+
set(HC_HAS_MOORDYN "#undef HYDROCHRONO_HAVE_MOORDYN")
305+
endif()
306+
264307
# For BUILD tree
265308
set(HC_DATA_DIR "#define HC_DATA_DIR \"${HC_BUILD_DATA}\"")
266309
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/config.h.in
@@ -317,13 +360,41 @@ set(HC_SOURCES
317360
src/hydro/logging/logging.cpp
318361
)
319362

363+
# MoorDyn mooring sources (conditionally compiled).
364+
# The wrapper is built as a separate OBJECT library so that MoorDyn's
365+
# bundled Eigen headers stay isolated and don't conflict with the
366+
# system/Chrono Eigen used by HydroChrono.
367+
if(HYDROCHRONO_ENABLE_MOORDYN)
368+
add_library(moordyn_bridge OBJECT
369+
src/hydro/mooring/moordyn_wrapper.cpp
370+
)
371+
target_include_directories(moordyn_bridge PRIVATE
372+
"${CMAKE_CURRENT_SOURCE_DIR}/extern/MoorDyn/source"
373+
"${CMAKE_CURRENT_SOURCE_DIR}"
374+
"${CMAKE_CURRENT_SOURCE_DIR}/include"
375+
)
376+
target_link_libraries(moordyn_bridge PRIVATE moordyn)
377+
target_compile_features(moordyn_bridge PUBLIC cxx_std_17)
378+
# Pick up HydroChrono's public headers (system_state.h, hydro_types.h)
379+
target_include_directories(moordyn_bridge PUBLIC
380+
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>"
381+
)
382+
# Chrono headers needed for Eigen (used by hydro_types.h)
383+
target_link_libraries(moordyn_bridge PUBLIC Chrono::Chrono_core)
384+
385+
list(APPEND HC_SOURCES
386+
src/hydro/force_components/mooring_component.cpp
387+
)
388+
endif()
389+
320390
set(HC_HEADERS
321391
${PROJECT_BINARY_DIR}/hydroc/config.h
322392
${PROJECT_BINARY_DIR}/hydroc/version.h
323393
include/hydroc/hydro_system.h
324394
include/hydroc/helper.h
325395
include/hydroc/logging.h
326396
include/hydroc/config/hydro_config.h
397+
include/hydroc/config/moordyn_config.h
327398
include/hydroc/core/force_component.h
328399
include/hydroc/core/hydro_forces.h
329400
include/hydroc/core/hydro_types.h
@@ -361,19 +432,23 @@ if(TARGET hdf5::hdf5-static)
361432
target_link_libraries(HydroChrono PUBLIC hdf5::hdf5_cpp-static)
362433
target_link_libraries(HydroChrono PUBLIC hdf5::hdf5_hl-static)
363434
target_link_libraries(HydroChrono PUBLIC hdf5::hdf5_hl_cpp-static)
364-
target_link_libraries(HydroChrono PUBLIC hdf5::hdf5_tools-static)
435+
if(TARGET hdf5::hdf5_tools-static)
436+
target_link_libraries(HydroChrono PUBLIC hdf5::hdf5_tools-static)
437+
endif()
365438
elseif(TARGET hdf5::hdf5-shared)
366439
message(STATUS "Linking shared libraries hdf5::hdf5-shared")
367440
target_link_libraries(HydroChrono PUBLIC hdf5::hdf5-shared)
368441
target_link_libraries(HydroChrono PUBLIC hdf5::hdf5_cpp-shared)
369442
target_link_libraries(HydroChrono PUBLIC hdf5::hdf5_hl-shared)
370443
target_link_libraries(HydroChrono PUBLIC hdf5::hdf5_hl_cpp-shared)
371-
target_link_libraries(HydroChrono PUBLIC hdf5::hdf5_tools-shared)
372444
list(APPEND HDF5_TARGETS hdf5::hdf5-shared)
373445
list(APPEND HDF5_TARGETS hdf5::hdf5_cpp-shared)
374446
list(APPEND HDF5_TARGETS hdf5::hdf5_hl-shared)
375447
list(APPEND HDF5_TARGETS hdf5::hdf5_hl_cpp-shared)
376-
list(APPEND HDF5_TARGETS hdf5::hdf5_tools-shared)
448+
if(TARGET hdf5::hdf5_tools-shared)
449+
target_link_libraries(HydroChrono PUBLIC hdf5::hdf5_tools-shared)
450+
list(APPEND HDF5_TARGETS hdf5::hdf5_tools-shared)
451+
endif()
377452
elseif(TARGET HDF5::HDF5)
378453
message(STATUS "Linking HDF5::HDF5")
379454
target_link_libraries(HydroChrono PUBLIC HDF5::HDF5)
@@ -391,6 +466,15 @@ target_include_directories(HydroChrono
391466
${CMAKE_CURRENT_SOURCE_DIR}/include
392467
)
393468

469+
# Add MoorDyn (optional mooring coupling)
470+
if(HYDROCHRONO_ENABLE_MOORDYN AND TARGET moordyn)
471+
# Link moordyn import lib for DLL binding; moordyn_bridge provides
472+
# the compiled wrapper objects with MoorDyn headers isolated from HC.
473+
target_link_libraries(HydroChrono PRIVATE $<TARGET_LINKER_FILE:moordyn>)
474+
target_sources(HydroChrono PRIVATE $<TARGET_OBJECTS:moordyn_bridge>)
475+
target_compile_definitions(HydroChrono PUBLIC HYDROCHRONO_HAVE_MOORDYN)
476+
endif()
477+
394478
# Library-specific compile definitions
395479
target_compile_definitions(HydroChrono
396480
PUBLIC
@@ -515,6 +599,12 @@ function(configure_test_environment)
515599
list(APPEND DLL_DIRS ${VSG_DLL_DIR})
516600
endif()
517601

602+
# MoorDyn DLL path
603+
if(HYDROCHRONO_ENABLE_MOORDYN AND TARGET moordyn)
604+
list(APPEND DLL_DIRS "$<TARGET_FILE_DIR:moordyn>")
605+
message(STATUS " MoorDyn DLL directory: (via target)")
606+
endif()
607+
518608
set(TEST_ENVIRONMENT "PATH=${DLL_DIRS};$ENV{PATH}" PARENT_SCOPE)
519609
endfunction()
520610

@@ -715,6 +805,21 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
715805
endforeach()
716806
endif()
717807

808+
# MoorDyn DLL
809+
if(HYDROCHRONO_ENABLE_MOORDYN AND TARGET moordyn)
810+
install(TARGETS moordyn
811+
CONFIGURATIONS Release
812+
RUNTIME DESTINATION bin COMPONENT runtime)
813+
message(STATUS " MoorDyn DLL (via target)")
814+
endif()
815+
816+
endif()
817+
818+
# MoorDyn license bundling
819+
if(HYDROCHRONO_ENABLE_MOORDYN)
820+
install(FILES "${CMAKE_SOURCE_DIR}/extern/MoorDyn/LICENSE.txt"
821+
RENAME MoorDyn_LICENSE.txt
822+
DESTINATION licenses COMPONENT runtime)
718823
endif()
719824

720825
# Public, user-facing regression test suite only
@@ -750,6 +855,13 @@ if(MSVC AND OpenMP_CXX_FOUND)
750855
endif()
751856
endif()
752857
include(InstallRequiredSystemLibraries)
858+
859+
# Third-party license notices
860+
if(EXISTS "${CMAKE_SOURCE_DIR}/THIRD_PARTY_NOTICES.txt")
861+
install(FILES "${CMAKE_SOURCE_DIR}/THIRD_PARTY_NOTICES.txt"
862+
DESTINATION . COMPONENT runtime)
863+
endif()
864+
753865
set(CPACK_GENERATOR "ZIP")
754866
set(CPACK_PACKAGE_NAME "HydroChrono")
755867
set(CPACK_COMPONENTS_ALL runtime python-tests dev-demos)

THIRD_PARTY_NOTICES.txt

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
THIRD-PARTY SOFTWARE NOTICES AND INFORMATION
2+
3+
HydroChrono incorporates third-party components under the licenses listed below.
4+
The original license files are included in the licenses/ directory of this
5+
distribution.
6+
7+
================================================================================
8+
MoorDyn v2.6.1
9+
https://github.com/FloatingArrayDesign/MoorDyn
10+
License: BSD 3-Clause
11+
License file: licenses/MoorDyn_LICENSE.txt
12+
13+
Copyright (c) 2022, Matt Hall
14+
All rights reserved.
15+
16+
Redistribution and use in source and binary forms, with or without modification,
17+
are permitted provided that the following conditions are met:
18+
19+
1. Redistributions of source code must retain the above copyright notice, this
20+
list of conditions and the following disclaimer.
21+
22+
2. Redistributions in binary form must reproduce the above copyright notice,
23+
this list of conditions and the following disclaimer in the documentation
24+
and/or other materials provided with the distribution.
25+
26+
3. Neither the name of the copyright holder nor the names of its contributors
27+
may be used to endorse or promote products derived from this software without
28+
specific prior written permission.
29+
30+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
31+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
32+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
33+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
34+
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
35+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
36+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
37+
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
38+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
39+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40+
================================================================================

build.ps1

Lines changed: 63 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ param(
2222
[switch]$Package,
2323
[switch]$NoIrrlicht, # Disable Irrlicht (auto-enabled if Chrono has it)
2424
[switch]$NoVSG, # Disable VSG (auto-enabled if Chrono has it)
25+
[switch]$MoorDyn, # Enable MoorDyn mooring coupling
2526
[switch]$NoDemos,
2627
[switch]$NoTests,
2728
[switch]$Help,
@@ -62,6 +63,7 @@ if ($Help) {
6263
Write-Host " -Package Create distributable ZIP after building"
6364
Write-Host " -NoIrrlicht Disable Irrlicht (enabled by default if Chrono has it)"
6465
Write-Host " -NoVSG Disable VSG (enabled by default if Chrono has it)"
66+
Write-Host " -MoorDyn Enable MoorDyn mooring coupling (requires extern/MoorDyn)"
6567
Write-Host " -NoDemos Skip demo executables"
6668
Write-Host " -NoTests Skip test targets"
6769
Write-Host " -ConfigPath <path> Custom config file (default: build-config.json)`n"
@@ -149,6 +151,20 @@ if (-not $hasHDF5) {
149151
Write-Warn "Chrono built without HDF5 - build may fail"
150152
}
151153

154+
# Eigen3: extract include path from Chrono config so FindEigen3.cmake can
155+
# bypass Eigen3ConfigVersion.cmake (Eigen 5.x rejects the "3.3" request).
156+
$eigen3Include = $null
157+
if ($chronoContent -match 'Eigen3_DIR\s+"([^"]+)"') {
158+
$eigen3Root = Split-Path (Split-Path $Matches[1])
159+
$candidate = Join-Path $eigen3Root "include/eigen3"
160+
if (Test-Path (Join-Path $candidate "Eigen")) {
161+
$eigen3Include = $candidate
162+
Write-OK "Eigen3: $eigen3Include"
163+
} else {
164+
Write-Warn "Eigen3 headers not found at $candidate"
165+
}
166+
}
167+
152168
# =============================================================================
153169
# Check CMake
154170
# =============================================================================
@@ -194,9 +210,15 @@ $cmakeArgs = @(
194210
"-DHYDROCHRONO_ENABLE_DEMOS=$(if($NoDemos){'OFF'}else{'ON'})",
195211
"-DHYDROCHRONO_ENABLE_IRRLICHT=$(if($useIrrlicht){'ON'}else{'OFF'})",
196212
"-DHYDROCHRONO_ENABLE_VSG=$(if($useVSG){'ON'}else{'OFF'})",
197-
"-DCMAKE_BUILD_TYPE=$BuildType"
213+
"-DCMAKE_BUILD_TYPE=$BuildType",
214+
"-DHYDROCHRONO_ENABLE_MOORDYN=$(if($MoorDyn){'ON'}else{'OFF'})"
198215
)
199216

217+
# Add Eigen3 include path if extracted from Chrono config
218+
if ($eigen3Include) {
219+
$cmakeArgs += "-DEIGEN3_INCLUDE_DIR=`"$($eigen3Include -replace '\\','/')`""
220+
}
221+
200222
# Add Python if specified
201223
if ($PythonRoot -and (Test-Path $PythonRoot)) {
202224
$cmakeArgs += "-DPython3_ROOT_DIR=`"$($PythonRoot -replace '\\','/')`""
@@ -213,7 +235,7 @@ if ($useIrrlicht) {
213235
}
214236
}
215237

216-
Write-Detail "Build: $BuildType | Tests: $(if($NoTests){'OFF'}else{'ON'}) | Demos: $(if($NoDemos){'OFF'}else{'ON'})"
238+
Write-Detail "Build: $BuildType | Tests: $(if($NoTests){'OFF'}else{'ON'}) | Demos: $(if($NoDemos){'OFF'}else{'ON'}) | MoorDyn: $(if($MoorDyn){'ON'}else{'OFF'})"
217239

218240
if ($Verbose) {
219241
cmake @cmakeArgs
@@ -310,6 +332,45 @@ if ($useVSG) {
310332
}
311333
}
312334

335+
# Copy HDF5 and its dependencies (szip, zlib) from vcpkg
336+
if ($chronoContent -match 'HDF5_DIR\s+"([^"]+)"') {
337+
$hdf5Root = Split-Path (Split-Path $Matches[1])
338+
$hdf5BinDir = Join-Path $hdf5Root "bin"
339+
if (Test-Path $hdf5BinDir) {
340+
$hdf5Dlls = Get-ChildItem -Path $hdf5BinDir -Include "hdf5*.dll","szip*.dll","zlib*.dll" -Recurse -ErrorAction SilentlyContinue
341+
$copiedCount = 0
342+
foreach ($dll in $hdf5Dlls) {
343+
$destDll = Join-Path $binPath $dll.Name
344+
if (-not (Test-Path $destDll)) {
345+
Copy-Item $dll.FullName $destDll -Force
346+
$copiedCount++
347+
}
348+
}
349+
if ($copiedCount -gt 0) {
350+
Write-OK "Copied $copiedCount HDF5/compression DLLs from $hdf5BinDir"
351+
}
352+
}
353+
}
354+
355+
# Verify MoorDyn DLL is in the output directory
356+
if ($MoorDyn) {
357+
$moordynDll = Join-Path $binPath "moordyn.dll"
358+
if (Test-Path $moordynDll) {
359+
Write-OK "MoorDyn DLL: moordyn.dll"
360+
} else {
361+
# CMake places moordyn.dll in bin/<config> alongside other targets,
362+
# but fall back to searching the build tree if not found.
363+
$found = Get-ChildItem -Path ".\build" -Filter "moordyn.dll" -Recurse -ErrorAction SilentlyContinue |
364+
Select-Object -First 1
365+
if ($found) {
366+
Copy-Item $found.FullName $moordynDll -Force
367+
Write-OK "MoorDyn DLL: copied from $($found.Directory.Name)"
368+
} else {
369+
Write-Warn "MoorDyn enabled but moordyn.dll not found in build tree"
370+
}
371+
}
372+
}
373+
313374
# =============================================================================
314375
# Verify
315376
# =============================================================================

cmake/config.h.in

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@
1515
// If HydroChrono was built with VSG support, define HYDROCHRONO_HAVE_VSG
1616
@HC_HAS_VSG@
1717

18+
// If HydroChrono was built with MoorDyn mooring support, define HYDROCHRONO_HAVE_MOORDYN
19+
@HC_HAS_MOORDYN@
20+
1821
// Path to HydroChrono data directory
1922
@HC_DATA_DIR@
2023

0 commit comments

Comments
 (0)