Conversation
… API Two small build fixes that together get SEA-Stack compiling cleanly on Linux against Chrono 10.0.0. * adapters/chrono/CMakeLists.txt — prefer Chrono::yaml-cpp over a system yaml-cpp when both are visible. Mixing Chrono's bundled yaml-cpp headers (from chrono_thirdparty/yaml-cpp/include) with a system libyaml-cpp.so triggers link errors against internal symbols such as YAML::FpToString and YAML::Emitter::Write. * apps/seastack/single_run.cpp — Chrono 10 moved the protected m_script_directory member of ChParserMbsYAML into an internal file handler; the script directory must now be set via m_file_handler.SetReferenceDirectory(dir).
The generic joint reaction extraction in SimulationExporter::RecordStep
was guarded by `dynamic_cast<ChLinkLock*>`, which silently fell through
to an "all zeros" fallback for every other ChLink subclass -- including
ChLinkUniversal (used by the 5SA articulated WEC demos), ChLinkRevolute,
ChLinkRevoluteSpherical, and others.
GetReaction1, GetReaction2, GetFrame1Abs, and GetFrame2Abs are virtual
on ChLinkBase, so they resolve uniformly for any concrete joint type.
Calling them on the base ChLink pointer fixes the export for all
current and future joint types.
Validation (5SA bimodal, 600s):
Before: joint_12..45 max |F| = 0.000 N for entire run
After: joint_12 max |F| = 192,471 N max |T| = 158,075 N*m
joint_23 max |F| = 211,687 N max |T| = 220,279 N*m
joint_34 max |F| = 201,941 N max |T| = 311,303 N*m
joint_45 max |F| = 169,830 N max |T| = 401,657 N*m
Internal consistency: reaction1_force == -reaction2_force to machine
precision (Newton's third law).
…citation
The bimodal case had linear_damping = [0, 100000, 0, 500000, 0, 0]
(zero linear damping in surge, heave, pitch, and yaw) and no quadratic
damping at all. The bimodal swell + wind-sea spectrum contains energy
near the chain's rigid-body heave natural frequency, and with no
restoring damping in heave the mode integrated unboundedly: at
t=198.86s body3 crossed 5 m/s, and by t=280s body z-positions exceeded
+10 m above SWL with the entire 144-m chain out of the water.
The fix mirrors the damping already present in the spreading case (a
near-identical multi-body configuration that runs to completion):
linear_damping: [20000, 80000, 80000, 500000, 200000, 200000]
quadratic_damping: [10000, 40000, 40000, 250000, 100000, 100000]
It also adds an explicit `excitation: frequency_domain` block, again
mirroring spreading. The bimodal swell and wind-sea have different
headings, so excitation must be evaluated in the frequency domain --
this is auto-selected by the loader when wave components span multiple
headings, but stating it explicitly matches the parity with spreading
and makes intent clear.
Validation (run_seastack 600s, no MoorDyn):
Before: body3 max |v| = diverged past 5.0 m/s at t=198.86s
body3 max z = +10.98 m at t=280s (chain in the air)
run terminated at 280.7s
After: body3 max |v| = 3.92 m/s at t=592.99s (bounded)
body3 max z = within +/- 2 m throughout
run completed full 600s, clean exit, 2m wallclock
…rash When the animated water surface is added to the VSG scene graph after ChVisualSystemVSG::Initialize() -- which happens because the wave model is set up at runtime, not pre-bind -- Chrono's wrapIfTransparent helper wraps the new node in a vsg::DepthSorted set to bin 10 if the material opacity is less than 1.0. The first record traversal that encounters this node then segfaults inside vsg::Bin::add() because the bin and its pipeline state were not present when Initialize() finalized the view's render path. Stack at the crash: #0 vsg::Bin::add(State*, double, Node const*) #1 vsg::RecordTraversal::apply(MatrixTransform const&) #2 vsg::Group::traverse(RecordTraversal&) ... #N chrono::vsg3d::ChVisualSystemVSG::Render() Water surface (kWaterOpacity=0.55) and wireframe overlay (SetOpacity(0.35)) both hit this. Setting both to 1.0 keeps the nodes out of the bin-10 DepthSorted path, so neither demos nor run_seastack crash on first render, including with the in-GUI wireframe toggle. Tradeoff: the water is opaque so submerged geometry is no longer visible through it. The proper fix is to compile any runtime-added transparent subtree against the live viewer (Chrono's ChShapeBuilderVSG owns an m_compileTraversal for this purpose but it is not exposed via SEA-Stack's public API surface). Tracking as a follow-up.
Each script under scripts/unix/ was checked in with mode 100644 (no executable bit), so `./scripts/unix/build.sh` fails on a fresh Linux clone. Setting +x on all of them makes the standard invocation pattern work as documented.
e17d2b9 to
5c2b908
Compare
|
@dav-og — when you have a moment, this brings SEA-Stack up on Linux + adds joint reactions for ChLinkUniversal. Validation data in the description; happy to walk through any of the four bugs. |
There was a problem hiding this comment.
Pull request overview
Improves Linux build, test, runtime, rendering, and simulation correctness.
Changes:
- Adds Unix build, test-suite, and smoke-test tooling.
- Fixes Chrono YAML compatibility and generic joint-reaction export.
- Stabilizes the 5SA demo and avoids VSG transparency crashes.
Reviewed changes
Copilot reviewed 6 out of 15 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
scripts/unix/build.sh |
Adds Unix build driver. |
scripts/unix/ctest_suite.sh |
Adds unified CTest runner. |
scripts/unix/run_benchmarks.sh |
Adds benchmark wrapper. |
scripts/unix/run_chrono_free_tests.sh |
Adds Chrono-free test wrapper. |
scripts/unix/run_comparison_tests.sh |
Adds comparison-test wrapper. |
scripts/unix/run_regression_tests.sh |
Adds regression-test wrapper. |
scripts/unix/run_seastack_demo_smoke.sh |
Adds headless demo smoke test. |
scripts/unix/run_unit_tests.sh |
Adds unit-test wrapper. |
scripts/unix/run_verification_tests.sh |
Adds verification-test wrapper. |
data/demos/run_seastack/5sa/bimodal/5sa_bimodal.hydro.yaml |
Adds damping and frequency-domain excitation. |
apps/seastack/single_run.cpp |
Updates Chrono parser directory handling. |
apps/seastack/gui/vsg_water_surface.cpp |
Makes wireframe material opaque. |
apps/seastack/gui/vsg_config.h |
Makes water opaque to avoid VSG crashes. |
adapters/chrono/src/simulation_export.cpp |
Exports reactions for generic joints. |
adapters/chrono/CMakeLists.txt |
Prefers Chrono’s bundled yaml-cpp. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| auto w1 = L->GetReaction1(); | ||
| auto F1 = L->GetFrame1Abs().TransformDirectionLocalToParent(w1.force); | ||
| auto T1 = L->GetFrame1Abs().TransformDirectionLocalToParent(w1.torque); |
a0d34cc switched HCParser::SetScriptDir to m_file_handler.SetReferenceDirectory(dir). That member exists on Chrono main, but not on the Chrono 10.0.0 release that SEA-Stack documents as its baseline, so the app fails to compile against 10.0.0. Restore the protected m_script_directory assignment, which is the Chrono 10.0.0 API. The yaml-cpp half of a0d34cc is kept unchanged -- preferring Chrono::yaml-cpp over a system yaml-cpp is correct on both Chrono versions and avoids the YAML::FpToString / YAML::Emitter::Write link errors Salhus reported. Verified on Ubuntu 22.04 against Chrono 10.0.0 built with Chrono's pinned VSG stack (vsg 1.1.11, vsgXchange 1.1.7, vsgImGui 0.7.0).
…Sorted crash" This reverts 2172d0b, restoring the intended translucent free surface (kWaterOpacity = 0.55) and the faint translucent wireframe overlay (SetOpacity(0.35)). The DepthSorted / vsg::Bin::add crash does not reproduce against the documented Chrono 10.0.0 baseline. Chrono 10.0.0 has no wrapIfTransparent() helper and does not wrap runtime-added nodes in vsg::DepthSorted, so a sub-1.0 material opacity never reaches the bin-10 path described in 2172d0b. That code was added on Chrono main after the 10.0.0 release, which is the most likely reason the crash was seen. Validated on Ubuntu 22.04.5 + RTX 3060 against Chrono 10.0.0 built with Chrono's pinned VSG stack (vsg 1.1.11, vsgXchange 1.1.7, vsgImGui 0.7.0, glslang 15.4.0): the 5SA bimodal GUI runs with translucent water and the wireframe toggle without any FATAL or renderer crash. Please retest on your Linux machine against Chrono 10.0.0 specifically. If the crash returns there, the VSG stack version is the thing to compare first, and we should fix the runtime compile traversal rather than force opacity to 1.0.
On Ubuntu, scripts/unix/build.sh treated an empty HDF5Dir in build-config.json as "HDF5 missing" and forced SEASTACK_ENABLE_HYDRO_IO=OFF. CMake was therefore never given a chance to find the apt libhdf5-dev package, and builds that did want HydroIO failed later on a missing h5_reader.h rather than at configure time. The only workaround was an undocumented manual HDF5Dir entry. Two small changes: * scripts/unix/build.sh - leave HydroIO ON when HDF5Dir is unset and print an INFO note instead. CMake's FindHDF5 then runs normally, and a genuinely missing HDF5 fails at configure time with a clear error. * CMakeLists.txt - Chrono's ChronoConfig can leave HDF5_DIR cached as NOTFOUND when Chrono itself found HDF5 via module mode. Clear that stale value, then probe module-mode find_package(HDF5 COMPONENTS CXX) when HydroIO is enabled and HDF5 is not yet found. Validated on Ubuntu 22.04.5 with "HDF5Dir": "" and Chrono 10.0.0 + VSG: configure reports HydroIO ON, libseastack_hydro_io.a builds, and run_seastack links libhdf5_serial 1.10.7 via module mode while HDF5_DIR stays NOTFOUND.
Dav/pr7 chrono10 followups
There was a problem hiding this comment.
🟡 Changes recommended
Exported reaction frames conflict with their HDF5 metadata, and the smoke test propagates the documented teardown failure.
Get a fresh assessment by requesting another Copilot review.
Review details
Suppressed comments (1)
adapters/chrono/src/simulation_export.cpp:1094
- The core fix broadens reaction export from
ChLinkLockto everyChLink, but the existingtest_export_redesignsuite contains no universal/generic-joint reaction assertion. Add an automated case with a non-lock joint that verifies nonzero reaction datasets, equal-and-opposite world reactions (if that is the intended frame), and the advertised frame metadata; otherwise this Linux regression can silently return.
auto w1 = L->GetReaction1();
- Files reviewed: 5/13 changed files
- Comments generated: 2
- Review effort level: Balanced
| auto F1 = L->GetFrame1Abs().TransformDirectionLocalToParent(w1.force); | ||
| auto T1 = L->GetFrame1Abs().TransformDirectionLocalToParent(w1.torque); |
| auto F2 = L->GetFrame2Abs().TransformDirectionLocalToParent(w2.force); | ||
| auto T2 = L->GetFrame2Abs().TransformDirectionLocalToParent(w2.torque); |
|
Hi @dav-og I saw the meeting notes. I think the PR 7 is all ready to merge. I already merged and tested your PR last week. Could you please update the meeting notes? |
Summary
Five atomic fixes that get SEA-Stack building, running, rendering, and producing correct output on Linux for the first time. Discovered and validated while bringing up the 5SA bimodal demo on Ubuntu 24.04 with Chrono 10.0.0.
Updated after merging #17 (@dav-og), which corrected three of the original commits against the Chrono 10.0.0 baseline — see Revisions from #17 below.
adapters/chrono/CMakeLists.txtlibyaml-cpp.soadapters/chrono/src/simulation_export.cppChLinksubclassesChLinkUniversaletc.data/.../5sa_bimodal.hydro.yamlCMakeLists.txt+scripts/unix/build.shlibhdf5-devhas nohdf5-config.cmakescripts/unix/*.shValidation
5SA bimodal heave runaway — bounded after fix
Joint reactions — zero to physical
The 5sa demo running on Linux with both water and wireframe enabled, and NOT crashing at 280 s
VSG rendering — demos render and accept input
demo_sphere_decayanddemo_oswec_irreg_wavesboth open windows, animate, accept GUI input (including the wireframe toggle), and shut down cleanly.OSWEC irregular waves demo running on Linux with both water and wireframe enabled.
Build + tests (current branch head, Chrono 10.0.0 tag
9faf13dd8f)Revisions from #17
Three of the original commits were written against a newer Chrono
mainAPI rather than the 10.0.0 baseline this project targets. @dav-og caught these and #17 corrects them:single_run.cpp— restored directm_script_directoryassignment.SetReferenceDirectory/m_file_handlerdo not exist in 10.0.0;m_script_directoryisprotectedatchrono_parsers/yaml/ChParserYAML.h:144. Confirmed by building the base branch against 10.0.0, which fails with'm_file_handler' was not declared in this scope.vsg_config.h/vsg_water_surface.cpp— reverted the opaque-water workaround.kWaterOpacityis back to0.55f. Thevsg::Bin::addDepthSortedcrash does not reproduce on Chrono 10.0.0; translucent water renders correctly, verified on VSG 1.1.11 as well as Chrono's pinned stack.build.sh— the[WARN] HDF5 not found; HydroIO will be disabledpath was too aggressive. It now emits[INFO] HDF5Dir unset; HydroIO left ONand lets CMake's module-modeFindHDF5locate Ubuntu'slibhdf5-dev. This pairs with theCMakeLists.txtfallback in this PR.Root cause notes
yaml-cpp (
adapters/chrono/CMakeLists.txt)A system
libyaml-cpp.sowas being linked while headers came from Chrono's bundled copy, yielding link errors against private symbols (YAML::FpToString,YAML::Emitter::Write). The fix prefersChrono::yaml-cppwhenever Chrono is present, falling back to the system package otherwise.Joint reactions for non-LinkLock joints
simulation_export.cpphad:But
GetReaction1,GetReaction2,GetFrame1Abs, andGetFrame2Absare all virtual onChLinkBase. Every concrete joint provides them —ChLinkLock,ChLinkUniversal,ChLinkRevoluteSpherical, etc. Calling them on the base pointer works uniformly. 5SA usesChLinkUniversal, so the previous code wrote zeros for the entire run.Bimodal heave runaway
The bimodal YAML set
linear_damping: [0, 100000, 0, 500000, 0, 0]— zero linear damping in surge, heave, pitch, and yaw — and no quadratic damping. The chain's rigid-body heave mode is essentially undamped (PTOs only damp relative pitch between segments). The bimodal spectrum contains energy near the heave natural frequency, so heave amplitude grew over ~200 s until the entire 180 m chain breached the water surface.The
spreadingcase is a near-identical multi-body configuration that runs to completion; the fix mirrors its damping values intobimodal. Re-tuning the bimodal sea state to avoid the heave-resonant band would be an equally valid fix; matchingspreadingis the minimal, principled choice.HDF5 discovery
Ubuntu's
libhdf5-devships nohdf5-config.cmake, so config-modefind_package(HDF5 CONFIG)fails. Chrono's own config may additionally setHDF5_DIRtoNOTFOUNDwhen Chrono itself used module mode. The fix clears that cache entry and falls back to module-modefind_package(HDF5 COMPONENTS CXX).Known issue (pre-existing, not introduced here)
run_seastackaborts withdouble free or corruption (out)/ exit 134 during process teardown, after the simulation completes and HDF5 output is flushed. Reproduces headless (--nogui, VSG never initialized) and with a clean build, so it is unrelated to the VSG changes in this PR. Output files are complete and readable. Filing separately — worth prioritising, since the "Simulation complete" banner prints before the abort and campaign/CI loops may not check the exit code.Out of scope (will file separately)
CH_USE_SIMD=OFF, and runtime needsVSG_FILE_PATHto include Chrono's data dir. Both belong in adocs/linux-setup.mdfollow-up.demos/5sa/five_sa_model_setup.h): uses the same low damping values that broke the YAML, but neither C++ demo currently triggers heave runaway (different wave forcing). Out of scope here to keep the PR tight.m_script_directoryis aprotectedmember, not public API, so a future Chrono tag could rename or restructure it without that counting as a breaking change — theSetReferenceDirectory/m_file_handlerAPI on Chronomainsuggests that refactor is already underway. Worth a bump-time checklist item since SEA-Stack tags releases against tagged Chrono releases.