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/apps/seastack/gui/vsg_config.h b/apps/seastack/gui/vsg_config.h index 99d237d..bfe5bad 100644 --- a/apps/seastack/gui/vsg_config.h +++ b/apps/seastack/gui/vsg_config.h @@ -25,7 +25,14 @@ inline constexpr int kColorVariationCycle = 8; inline constexpr float kWaterR = 0.01f; inline constexpr float kWaterG = 0.20f; inline constexpr float kWaterB = 0.35f; -inline constexpr float kWaterOpacity = 0.55f; +// NOTE: Material opacity must stay at 1.0 on Linux. +// With opacity < 1.0, Chrono's wrapIfTransparent() wraps the runtime-added +// water node in vsg::DepthSorted (bin 10), which crashes the VSG renderer +// at vsg::Bin::add during the first record traversal. The animated water +// surface is added to the scene after pVis->Initialize(), bypassing the +// BindAll() compile path that built-in Chrono demos rely on. +// TODO: enable proper translucency via a runtime compile traversal. +inline constexpr float kWaterOpacity = 1.0f; inline constexpr float kWaterSpecular = 0.6f; inline constexpr float kWaterRoughness = 0.05f; inline constexpr float kWaterMetallic = 0.0f; diff --git a/apps/seastack/gui/vsg_water_surface.cpp b/apps/seastack/gui/vsg_water_surface.cpp index ecc097a..6c86e50 100644 --- a/apps/seastack/gui/vsg_water_surface.cpp +++ b/apps/seastack/gui/vsg_water_surface.cpp @@ -501,7 +501,7 @@ void AnimatedWaterSurface::InitializeWireframe() { // Faint blue-gray material. auto wire_material = ::chrono_types::make_shared<::chrono::ChVisualMaterial>(); wire_material->SetDiffuseColor(::chrono::ChColor(0.1f, 0.2f, 0.3f)); - wire_material->SetOpacity(0.35f); + wire_material->SetOpacity(1.0f); wire_material->SetRoughness(0.9f); wire_material->SetMetallic(0.0f); diff --git a/apps/seastack/single_run.cpp b/apps/seastack/single_run.cpp index 3c3b36b..56d8918 100644 --- a/apps/seastack/single_run.cpp +++ b/apps/seastack/single_run.cpp @@ -123,7 +123,7 @@ namespace { class HCParser : public ::chrono::parsers::ChParserMbsYAML { public: HCParser() : ChParserMbsYAML() {} - void SetScriptDir(const std::string& dir) { m_script_directory = dir; } + void SetScriptDir(const std::string& dir) { m_file_handler.SetReferenceDirectory(dir); } }; static std::shared_ptr<::chrono::ChBody> FindBodyByName(::chrono::ChSystem& system, 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 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