diff --git a/CMakeLists.txt b/CMakeLists.txt index c0bb271..72ff2e7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -183,13 +183,18 @@ if(SEASTACK_ENABLE_CHRONO) " (or /usr/local/opt/libomp on Intel Homebrew).") endif() - # If Chrono set HDF5_DIR, retry the find + # If Chrono set HDF5_DIR to NOTFOUND (common when Chrono itself found HDF5 + # via module mode, not hdf5-config.cmake), clear it so later FindHDF5 + # module-mode discovery (e.g. Ubuntu libhdf5-dev) can succeed. if(NOT HDF5_FOUND AND DEFINED CACHE{HDF5_DIR}) if("${HDF5_DIR}" MATCHES "NOTFOUND") unset(HDF5_DIR CACHE) find_package(HDF5 CONFIG QUIET) endif() endif() + if(SEASTACK_ENABLE_HYDRO_IO AND NOT HDF5_FOUND) + find_package(HDF5 QUIET COMPONENTS CXX) + endif() # Use same C++ standard as Chrono for ABI compatibility if(DEFINED CHRONO_CXX_STANDARD) diff --git a/adapters/chrono/CMakeLists.txt b/adapters/chrono/CMakeLists.txt index 46f30a5..ae95378 100644 --- a/adapters/chrono/CMakeLists.txt +++ b/adapters/chrono/CMakeLists.txt @@ -24,19 +24,25 @@ target_include_directories(seastack_chrono_adapter # Chrono MBS YAML registers TSDA/RSDA force functors without copying damping onto the link; # simulation_export reads damping_coefficient from model YAML when GetDampingCoefficient()==0. -find_package(yaml-cpp CONFIG QUIET) -if(NOT yaml-cpp_FOUND) - find_package(yaml-cpp QUIET) -endif() -if(TARGET yaml-cpp::yaml-cpp) - set(_seastack_yaml_cpp_target yaml-cpp::yaml-cpp) -elseif(TARGET yaml-cpp) - set(_seastack_yaml_cpp_target yaml-cpp) -elseif(TARGET Chrono::yaml-cpp) - # Chrono's config often provides yaml-cpp as an imported target without a system package. +# +# Prefer Chrono's bundled yaml-cpp when available so that the yaml-cpp headers +# (which come from Chrono's chrono_thirdparty/yaml-cpp/include via Chrono::Chrono_core) +# match the linked library. Mixing a system libyaml-cpp.so with Chrono's headers can +# produce link errors against internal symbols (e.g. YAML::FpToString, YAML::Emitter::Write). +if(TARGET Chrono::yaml-cpp) set(_seastack_yaml_cpp_target Chrono::yaml-cpp) else() - message(FATAL_ERROR "yaml-cpp not found (required for Chrono adapter).") + find_package(yaml-cpp CONFIG QUIET) + if(NOT yaml-cpp_FOUND) + find_package(yaml-cpp QUIET) + endif() + if(TARGET yaml-cpp::yaml-cpp) + set(_seastack_yaml_cpp_target yaml-cpp::yaml-cpp) + elseif(TARGET yaml-cpp) + set(_seastack_yaml_cpp_target yaml-cpp) + else() + message(FATAL_ERROR "yaml-cpp not found (required for Chrono adapter).") + endif() endif() target_link_libraries(seastack_chrono_adapter diff --git a/adapters/chrono/src/simulation_export.cpp b/adapters/chrono/src/simulation_export.cpp index 5e7a60c..c9e55c2 100644 --- a/adapters/chrono/src/simulation_export.cpp +++ b/adapters/chrono/src/simulation_export.cpp @@ -1082,13 +1082,18 @@ void SimulationExporter::RecordStep(::chrono::ChSystem* system) { } // ── Generic joint reactions (level-gated) ─────────────────────────────── + // GetReaction1/2 and GetFrame1Abs/2Abs are virtual on ChLinkBase, so they + // work for every concrete joint type (ChLinkLock, ChLinkUniversal, + // ChLinkRevoluteSpherical, ...). Previously this code dynamic_cast<>'d to + // ChLinkLock* only, silently writing zeros for every other joint type -- + // including the ChLinkUniversal joints used by the 5SA articulated WEC demos. for (auto& j : impl_->joints) { auto* L = j.link; - if (auto* lock = dynamic_cast<::chrono::ChLinkLock*>(L)) { + if (L) { try { - auto w1 = lock->GetReaction1(); - auto F1 = lock->GetFrame1Abs().TransformDirectionLocalToParent(w1.force); - auto T1 = lock->GetFrame1Abs().TransformDirectionLocalToParent(w1.torque); + auto w1 = L->GetReaction1(); + auto F1 = L->GetFrame1Abs().TransformDirectionLocalToParent(w1.force); + auto T1 = L->GetFrame1Abs().TransformDirectionLocalToParent(w1.torque); j.react_force_b1.insert(j.react_force_b1.end(), {F1.x(), F1.y(), F1.z()}); j.react_torque_b1.insert(j.react_torque_b1.end(), {T1.x(), T1.y(), T1.z()}); } catch (const std::exception& ex) { @@ -1098,9 +1103,9 @@ void SimulationExporter::RecordStep(::chrono::ChSystem* system) { } if (!is_compact) { try { - auto w2 = lock->GetReaction2(); - auto F2 = lock->GetFrame2Abs().TransformDirectionLocalToParent(w2.force); - auto T2 = lock->GetFrame2Abs().TransformDirectionLocalToParent(w2.torque); + auto w2 = L->GetReaction2(); + auto F2 = L->GetFrame2Abs().TransformDirectionLocalToParent(w2.force); + auto T2 = L->GetFrame2Abs().TransformDirectionLocalToParent(w2.torque); j.react_force_b2.insert(j.react_force_b2.end(), {F2.x(), F2.y(), F2.z()}); j.react_torque_b2.insert(j.react_torque_b2.end(), {T2.x(), T2.y(), T2.z()}); } catch (const std::exception& ex) { diff --git a/data/demos/run_seastack/5sa/bimodal/5sa_bimodal.hydro.yaml b/data/demos/run_seastack/5sa/bimodal/5sa_bimodal.hydro.yaml index 32569c1..1159c59 100644 --- a/data/demos/run_seastack/5sa/bimodal/5sa_bimodal.hydro.yaml +++ b/data/demos/run_seastack/5sa/bimodal/5sa_bimodal.hydro.yaml @@ -1,20 +1,31 @@ hydrodynamics: bodies: + # Surge/sway/heave/roll/pitch/yaw damping mirrored from the spreading + # case. The bimodal swell + wind sea combination contains spectral + # energy near the chain's heave natural frequency, and with zero + # linear and quadratic damping in heave/pitch/yaw the rigid-body + # heave mode runs away after ~200 s of accumulation (body z-position + # exceeded 10 m above SWL by t=280 s in the previous configuration). - name: body1 h5_file: ../assets/hydroData/5sa_directional.h5 - linear_damping: [0, 100000, 0, 500000, 0, 0] + linear_damping: [20000, 80000, 80000, 500000, 200000, 200000] + quadratic_damping: [10000, 40000, 40000, 250000, 100000, 100000] - name: body2 h5_file: ../assets/hydroData/5sa_directional.h5 - linear_damping: [0, 100000, 0, 500000, 0, 0] + linear_damping: [20000, 80000, 80000, 500000, 200000, 200000] + quadratic_damping: [10000, 40000, 40000, 250000, 100000, 100000] - name: body3 h5_file: ../assets/hydroData/5sa_directional.h5 - linear_damping: [0, 100000, 0, 500000, 0, 0] + linear_damping: [20000, 80000, 80000, 500000, 200000, 200000] + quadratic_damping: [10000, 40000, 40000, 250000, 100000, 100000] - name: body4 h5_file: ../assets/hydroData/5sa_directional.h5 - linear_damping: [0, 100000, 0, 500000, 0, 0] + linear_damping: [20000, 80000, 80000, 500000, 200000, 200000] + quadratic_damping: [10000, 40000, 40000, 250000, 100000, 100000] - name: body5 h5_file: ../assets/hydroData/5sa_directional.h5 - linear_damping: [0, 100000, 0, 500000, 0, 0] + linear_damping: [20000, 80000, 80000, 500000, 200000, 200000] + quadratic_damping: [10000, 40000, 40000, 250000, 100000, 100000] # Bimodal sea state: swell along +X, wind sea from beam (90 deg). waves: @@ -42,6 +53,11 @@ hydrodynamics: type: cos2s s: 8 + # Bimodal sea: swell and wind-sea have different headings, so excitation + # must be evaluated in the frequency domain (matches spreading case). + excitation: + method: frequency_domain + radiation: method: rirf_convolution smoothing: diff --git a/scripts/unix/build.sh b/scripts/unix/build.sh old mode 100644 new mode 100755 index f0170f8..4cfbf31 --- a/scripts/unix/build.sh +++ b/scripts/unix/build.sh @@ -318,14 +318,15 @@ else USE_VSG=0 fi +# HydroIO / HDF5: +# Do not force HydroIO OFF merely because build-config.json leaves HDF5Dir empty. +# On Ubuntu/Debian, libhdf5-dev is discovered by CMake FindHDF5 (module mode) +# without a config-mode HDF5_DIR. Passing -DHDF5_DIR is optional; Chrono's +# ChronoConfig may even set HDF5_DIR to NOTFOUND when it used module-mode HDF5. +# Only --no-hydro-io disables HydroIO here. If CMake cannot find HDF5, configure +# fails with a clear FindHDF5 error instead of a later missing-header failure. if [[ -z "${SEASTACK_HDF5_DIR:-}" && "${NO_HYDRO_IO}" -eq 0 ]]; then - echo " [WARN] HDF5 not found; HydroIO will be disabled." >&2 - if [[ "${USE_CHRONO}" -eq 1 ]]; then - echo " If Chrono was built without HDF5, set HDF5Dir in build-config.json." >&2 - else - echo " For Chrono-free builds, set HDF5Dir or use --no-hydro-io." >&2 - fi - NO_HYDRO_IO=1 + echo " [INFO] HDF5Dir unset; HydroIO left ON for CMake HDF5 discovery (module/config)." >&2 fi if [[ "${MOORDYN}" -eq 1 && ! -f "${REPO_ROOT}/extern/MoorDyn/CMakeLists.txt" ]]; then diff --git a/scripts/unix/ctest_suite.sh b/scripts/unix/ctest_suite.sh old mode 100644 new mode 100755 diff --git a/scripts/unix/run_benchmarks.sh b/scripts/unix/run_benchmarks.sh old mode 100644 new mode 100755 diff --git a/scripts/unix/run_chrono_free_tests.sh b/scripts/unix/run_chrono_free_tests.sh old mode 100644 new mode 100755 diff --git a/scripts/unix/run_comparison_tests.sh b/scripts/unix/run_comparison_tests.sh old mode 100644 new mode 100755 diff --git a/scripts/unix/run_regression_tests.sh b/scripts/unix/run_regression_tests.sh old mode 100644 new mode 100755 diff --git a/scripts/unix/run_seastack_demo_smoke.sh b/scripts/unix/run_seastack_demo_smoke.sh old mode 100644 new mode 100755 diff --git a/scripts/unix/run_unit_tests.sh b/scripts/unix/run_unit_tests.sh old mode 100644 new mode 100755 diff --git a/scripts/unix/run_verification_tests.sh b/scripts/unix/run_verification_tests.sh old mode 100644 new mode 100755