@@ -52,10 +52,10 @@ configure_file(${CMAKE_SOURCE_DIR}/cmake/version.h.in
5252# Add the cmake folder so the FindSphinx module is found
5353set (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).
5657set (CMAKE_FIND_PACKAGE_PREFER_CONFIG ON )
5758set (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
6161if (NOT DEFINED HYDROCHRONO_DEFAULT_BUILD_TYPE)
@@ -79,6 +79,7 @@ option(HYDROCHRONO_ENABLE_IRRLICHT "Enable Irrlicht visualization library" OFF)
7979option (HYDROCHRONO_ENABLE_VSG "Enable VSG visualization library" OFF )
8080option (HYDROCHRONO_ENABLE_DEMOS "Enable demo executables" OFF )
8181option (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,10 +168,36 @@ if(NOT Chrono_DIR)
167168 return ()
168169endif ()
169170
171+ # Pre-load HDF5 targets so the shims below are only created when genuinely
172+ # needed (i.e., when HDF5 config-mode doesn't provide hdf5_tools).
173+ # Without this, installers that define all HDF5 targets as a batch
174+ # (e.g., HDF Group installer) error out on the partial pre-definition.
175+ find_package (HDF5 CONFIG QUIET )
176+
177+ # Chrono's export file may reference hdf5::hdf5_tools-{shared,static} which is
178+ # absent from some HDF5 installations (e.g., vcpkg). Provide empty shims so
179+ # ChronoTargets.cmake loads without errors. Must be created BEFORE find_package(Chrono).
180+ if (NOT TARGET hdf5::hdf5_tools-shared)
181+ add_library (hdf5::hdf5_tools-shared INTERFACE IMPORTED )
182+ endif ()
183+ if (NOT TARGET hdf5::hdf5_tools-static)
184+ add_library (hdf5::hdf5_tools-static INTERFACE IMPORTED )
185+ endif ()
186+
170187find_package (Chrono
171188 CONFIG REQUIRED
172189 COMPONENTS Parsers )
173190
191+ # If the early HDF5 find failed but Chrono has now set HDF5_DIR, retry.
192+ # The early find may have cached HDF5_DIR-NOTFOUND, blocking Chrono's
193+ # non-FORCE cache set. Clear it and retry with the Chrono-provided path.
194+ if (NOT HDF5_FOUND AND DEFINED CACHE{HDF5_DIR})
195+ if ("${HDF5_DIR} " MATCHES "NOTFOUND" )
196+ unset (HDF5_DIR CACHE )
197+ find_package (HDF5 CONFIG QUIET )
198+ endif ()
199+ endif ()
200+
174201message (STATUS "----\n " )
175202
176203message (STATUS "Chrono targets: ${CHRONO_TARGETS} " )
@@ -203,6 +230,20 @@ else()
203230 message (STATUS "Set C++ standard to: ${HC_CXX_STANDARD} " )
204231endif ()
205232
233+ # Detect whether Chrono has the newer ChLoadHydrodynamics API.
234+ # If not, fall back to HydroChrono's legacy added-mass implementation.
235+ set (CHRONO_HAS_LOAD_HYDRODYNAMICS FALSE )
236+ get_target_property (_chrono_inc_dirs Chrono::Chrono_core INTERFACE_INCLUDE_DIRECTORIES )
237+ foreach (_dir ${_chrono_inc_dirs} )
238+ if (EXISTS "${_dir} /chrono/physics/ChLoadHydrodynamics.h" )
239+ set (CHRONO_HAS_LOAD_HYDRODYNAMICS TRUE )
240+ break ()
241+ endif ()
242+ endforeach ()
243+ if (NOT CHRONO_HAS_LOAD_HYDRODYNAMICS)
244+ message (STATUS "ChLoadHydrodynamics not found in Chrono -- using legacy added-mass implementation" )
245+ endif ()
246+
206247# Enable Irrlicht support if requested and available
207248if (HYDROCHRONO_ENABLE_IRRLICHT AND NOT TARGET Chrono::Chrono_irrlicht)
208249 message (FATAL_ERROR "HYDROCHRONO_ENABLE_IRRLICHT is ON but Chrono::Chrono_irrlicht target not found. Ensure Chrono was built with Irrlicht support." )
@@ -239,7 +280,49 @@ endif()
239280find_package (OpenMP REQUIRED COMPONENTS CXX )
240281
241282# -- HDF5 Integration --
242- find_package (HDF5 REQUIRED COMPONENTS CXX )
283+ # Config-mode discovery runs early (before Chrono) to avoid target conflicts
284+ # with the hdf5_tools shims. Fall back to module-mode here if it wasn't found.
285+ if (NOT HDF5_FOUND)
286+ find_package (HDF5 REQUIRED COMPONENTS CXX )
287+ endif ()
288+
289+ # -- MoorDyn mooring library (optional) --
290+ if (HYDROCHRONO_ENABLE_MOORDYN)
291+ message (STATUS "\n ---- MoorDyn mooring library" )
292+ if (NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR} /extern/MoorDyn/CMakeLists.txt" )
293+ message (FATAL_ERROR
294+ "MoorDyn submodule not found at extern/MoorDyn.\n "
295+ "Run: git submodule update --init extern/MoorDyn" )
296+ endif ()
297+ # MoorDyn's CMakeLists.txt uses CMAKE_SOURCE_DIR (which resolves to
298+ # HydroChrono's root) for its config template and CPack license.
299+ # Copy the files it expects so the configure step succeeds.
300+ if (NOT EXISTS "${CMAKE_SOURCE_DIR} /cmake/MoorDynConfig.cmake" )
301+ file (COPY "${CMAKE_CURRENT_SOURCE_DIR} /extern/MoorDyn/cmake/MoorDynConfig.cmake"
302+ DESTINATION "${CMAKE_SOURCE_DIR} /cmake/" )
303+ endif ()
304+ if (NOT EXISTS "${CMAKE_SOURCE_DIR} /LICENSE.txt" )
305+ file (COPY "${CMAKE_CURRENT_SOURCE_DIR} /extern/MoorDyn/LICENSE.txt"
306+ DESTINATION "${CMAKE_SOURCE_DIR} /" )
307+ endif ()
308+
309+ set (EXTERNAL_EIGEN OFF CACHE BOOL "Use MoorDyn bundled Eigen" FORCE )
310+ set (PYTHON_WRAPPER OFF CACHE BOOL "Disable MoorDyn Python wrapper" FORCE )
311+ set (FORTRAN_WRAPPER OFF CACHE BOOL "Disable MoorDyn Fortran wrapper" FORCE )
312+ set (MATLAB_WRAPPER OFF CACHE BOOL "Disable MoorDyn MATLAB wrapper" FORCE )
313+ set (RUST_WRAPPER OFF CACHE BOOL "Disable MoorDyn Rust wrapper" FORCE )
314+ set (BUILD_TESTING_SAVED ${BUILD_TESTING} )
315+ set (BUILD_TESTING OFF )
316+ add_subdirectory (extern/MoorDyn )
317+ set (BUILD_TESTING ${BUILD_TESTING_SAVED} )
318+ # MoorDyn is a shared library (DLL) -- its internal Eigen usage must not
319+ # leak into HydroChrono's include paths (HydroChrono uses Chrono's Eigen).
320+ set_target_properties (moordyn PROPERTIES
321+ INTERFACE_INCLUDE_DIRECTORIES ""
322+ )
323+ message (STATUS "MoorDyn mooring coupling: ENABLED" )
324+ message (STATUS "----\n " )
325+ endif ()
243326
244327# ===============================================================================
245328# ----- Create HydroChrono configuration header ---------------------------------
@@ -261,6 +344,12 @@ else()
261344 set (HC_HAS_VSG "#undef HYDROCHRONO_HAVE_VSG" )
262345endif ()
263346
347+ if (HYDROCHRONO_ENABLE_MOORDYN)
348+ set (HC_HAS_MOORDYN "#define HYDROCHRONO_HAVE_MOORDYN" )
349+ else ()
350+ set (HC_HAS_MOORDYN "#undef HYDROCHRONO_HAVE_MOORDYN" )
351+ endif ()
352+
264353# For BUILD tree
265354set (HC_DATA_DIR "#define HC_DATA_DIR \" ${HC_BUILD_DATA} \" " )
266355configure_file (${CMAKE_CURRENT_SOURCE_DIR} /cmake/config.h.in
@@ -317,13 +406,41 @@ set(HC_SOURCES
317406 src/hydro/logging/logging.cpp
318407)
319408
409+ # MoorDyn mooring sources (conditionally compiled).
410+ # The wrapper is built as a separate OBJECT library so that MoorDyn's
411+ # bundled Eigen headers stay isolated and don't conflict with the
412+ # system/Chrono Eigen used by HydroChrono.
413+ if (HYDROCHRONO_ENABLE_MOORDYN)
414+ add_library (moordyn_bridge OBJECT
415+ src/hydro/mooring/moordyn_wrapper.cpp
416+ )
417+ target_include_directories (moordyn_bridge PRIVATE
418+ "${CMAKE_CURRENT_SOURCE_DIR} /extern/MoorDyn/source"
419+ "${CMAKE_CURRENT_SOURCE_DIR} "
420+ "${CMAKE_CURRENT_SOURCE_DIR} /include"
421+ )
422+ target_link_libraries (moordyn_bridge PRIVATE moordyn )
423+ target_compile_features (moordyn_bridge PUBLIC cxx_std_17 )
424+ # Pick up HydroChrono's public headers (system_state.h, hydro_types.h)
425+ target_include_directories (moordyn_bridge PUBLIC
426+ "$<BUILD_INTERFACE :${CMAKE_CURRENT_SOURCE_DIR} /include >"
427+ )
428+ # Chrono headers needed for Eigen (used by hydro_types.h)
429+ target_link_libraries (moordyn_bridge PUBLIC Chrono::Chrono_core )
430+
431+ list (APPEND HC_SOURCES
432+ src/hydro/force_components/mooring_component.cpp
433+ )
434+ endif ()
435+
320436set (HC_HEADERS
321437 ${PROJECT_BINARY_DIR} /hydroc/config.h
322438 ${PROJECT_BINARY_DIR} /hydroc/version.h
323439 include/hydroc/hydro_system.h
324440 include/hydroc/helper.h
325441 include/hydroc/logging.h
326442 include/hydroc/config/hydro_config.h
443+ include/hydroc/config/moordyn_config.h
327444 include/hydroc/core/force_component.h
328445 include/hydroc/core/hydro_forces.h
329446 include/hydroc/core/hydro_types.h
@@ -361,19 +478,23 @@ if(TARGET hdf5::hdf5-static)
361478 target_link_libraries (HydroChrono PUBLIC hdf5::hdf5_cpp-static )
362479 target_link_libraries (HydroChrono PUBLIC hdf5::hdf5_hl-static )
363480 target_link_libraries (HydroChrono PUBLIC hdf5::hdf5_hl_cpp-static )
364- target_link_libraries (HydroChrono PUBLIC hdf5::hdf5_tools-static )
481+ if (TARGET hdf5::hdf5_tools-static)
482+ target_link_libraries (HydroChrono PUBLIC hdf5::hdf5_tools-static )
483+ endif ()
365484elseif (TARGET hdf5::hdf5-shared)
366485 message (STATUS "Linking shared libraries hdf5::hdf5-shared" )
367486 target_link_libraries (HydroChrono PUBLIC hdf5::hdf5-shared )
368487 target_link_libraries (HydroChrono PUBLIC hdf5::hdf5_cpp-shared )
369488 target_link_libraries (HydroChrono PUBLIC hdf5::hdf5_hl-shared )
370489 target_link_libraries (HydroChrono PUBLIC hdf5::hdf5_hl_cpp-shared )
371- target_link_libraries (HydroChrono PUBLIC hdf5::hdf5_tools-shared )
372490 list (APPEND HDF5_TARGETS hdf5::hdf5-shared)
373491 list (APPEND HDF5_TARGETS hdf5::hdf5_cpp-shared)
374492 list (APPEND HDF5_TARGETS hdf5::hdf5_hl-shared)
375493 list (APPEND HDF5_TARGETS hdf5::hdf5_hl_cpp-shared)
376- list (APPEND HDF5_TARGETS hdf5::hdf5_tools-shared)
494+ if (TARGET hdf5::hdf5_tools-shared)
495+ target_link_libraries (HydroChrono PUBLIC hdf5::hdf5_tools-shared )
496+ list (APPEND HDF5_TARGETS hdf5::hdf5_tools-shared)
497+ endif ()
377498elseif (TARGET HDF5::HDF5)
378499 message (STATUS "Linking HDF5::HDF5" )
379500 target_link_libraries (HydroChrono PUBLIC HDF5::HDF5 )
@@ -391,11 +512,21 @@ target_include_directories(HydroChrono
391512 ${CMAKE_CURRENT_SOURCE_DIR} /include
392513)
393514
515+ # Add MoorDyn (optional mooring coupling)
516+ if (HYDROCHRONO_ENABLE_MOORDYN AND TARGET moordyn)
517+ # Link moordyn import lib for DLL binding; moordyn_bridge provides
518+ # the compiled wrapper objects with MoorDyn headers isolated from HC.
519+ target_link_libraries (HydroChrono PRIVATE $<TARGET_LINKER_FILE :moordyn >)
520+ target_sources (HydroChrono PRIVATE $<TARGET_OBJECTS :moordyn_bridge >)
521+ target_compile_definitions (HydroChrono PUBLIC HYDROCHRONO_HAVE_MOORDYN )
522+ endif ()
523+
394524# Library-specific compile definitions
395525target_compile_definitions (HydroChrono
396526 PUBLIC
397527 "HYDROCHRONO_VERSION=\" ${PROJECT_VERSION} \" "
398528 "HYDROCHRONO_BUILD_TYPE=\" $<IF :$<CONFIG :Debug >,Debug ,$<IF :$<CONFIG :Release >,Release ,$<IF :$<CONFIG :RelWithDebInfo >,RelWithDebInfo ,$<IF :$<CONFIG :MinSizeRel >,MinSizeRel ,Unknown >>>>\" "
529+ $<$<NOT :$<BOOL :${CHRONO_HAS_LOAD_HYDRODYNAMICS} >>:HYDROCHRONO_USE_LEGACY_ADDED_MASS >
399530 PRIVATE
400531 $<$<BOOL :${HYDROCHRONO_ENABLE_LOGGING} >:HYDROCHRONO_ENABLE_LOGGING ="1">
401532)
@@ -425,6 +556,7 @@ if(HYDROCHRONO_ENABLE_VSG)
425556 src/gui/vsg_gui_component.cpp
426557 src/gui/vsg_lighting.cpp
427558 src/gui/vsg_materials.cpp
559+ src/gui/vsg_mooring_lines.cpp
428560 src/gui/vsg_water_surface.cpp
429561 src/gui/vsg_radiation_surface.cpp
430562 )
@@ -433,6 +565,7 @@ if(HYDROCHRONO_ENABLE_VSG)
433565 src/gui/vsg_gui_component.h
434566 src/gui/vsg_lighting.h
435567 src/gui/vsg_materials.h
568+ src/gui/vsg_mooring_lines.h
436569 src/gui/vsg_water_surface.h
437570 src/gui/vsg_radiation_surface.h
438571 )
@@ -515,6 +648,12 @@ function(configure_test_environment)
515648 list (APPEND DLL_DIRS ${VSG_DLL_DIR} )
516649 endif ()
517650
651+ # MoorDyn DLL path
652+ if (HYDROCHRONO_ENABLE_MOORDYN AND TARGET moordyn)
653+ list (APPEND DLL_DIRS "$<TARGET_FILE_DIR :moordyn >" )
654+ message (STATUS " MoorDyn DLL directory: (via target)" )
655+ endif ()
656+
518657 set (TEST_ENVIRONMENT "PATH=${DLL_DIRS} ;$ENV{PATH} " PARENT_SCOPE )
519658endfunction ()
520659
@@ -547,6 +686,7 @@ if(HYDROCHRONO_ENABLE_TESTS)
547686 endif ()
548687
549688 add_subdirectory (tests/regression )
689+ add_subdirectory (tests/verification )
550690 add_subdirectory (tests/unit )
551691endif ()
552692
@@ -715,6 +855,21 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
715855 endforeach ()
716856 endif ()
717857
858+ # MoorDyn DLL
859+ if (HYDROCHRONO_ENABLE_MOORDYN AND TARGET moordyn)
860+ install (TARGETS moordyn
861+ CONFIGURATIONS Release
862+ RUNTIME DESTINATION bin COMPONENT runtime )
863+ message (STATUS " MoorDyn DLL (via target)" )
864+ endif ()
865+
866+ endif ()
867+
868+ # MoorDyn license bundling
869+ if (HYDROCHRONO_ENABLE_MOORDYN)
870+ install (FILES "${CMAKE_SOURCE_DIR} /extern/MoorDyn/LICENSE.txt"
871+ RENAME MoorDyn_LICENSE.txt
872+ DESTINATION licenses COMPONENT runtime )
718873endif ()
719874
720875# Public, user-facing regression test suite only
@@ -750,6 +905,13 @@ if(MSVC AND OpenMP_CXX_FOUND)
750905 endif ()
751906endif ()
752907include (InstallRequiredSystemLibraries )
908+
909+ # Third-party license notices
910+ if (EXISTS "${CMAKE_SOURCE_DIR} /THIRD_PARTY_NOTICES.txt" )
911+ install (FILES "${CMAKE_SOURCE_DIR} /THIRD_PARTY_NOTICES.txt"
912+ DESTINATION . COMPONENT runtime )
913+ endif ()
914+
753915set (CPACK_GENERATOR "ZIP" )
754916set (CPACK_PACKAGE_NAME "HydroChrono" )
755917set (CPACK_COMPONENTS_ALL runtime python-tests dev-demos)
0 commit comments