Skip to content

Commit 5b97897

Browse files
committed
Speed up irregular wave animation in VSG
1 parent 98d430b commit 5b97897

4 files changed

Lines changed: 86 additions & 18 deletions

File tree

include/hydroc/waves/irregular_wave.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,21 @@ class IrregularWaves : public WaveBase {
5252
Eigen::Vector3d GetAcceleration(const Eigen::Vector3d& position, double time) override;
5353
Eigen::Vector2d GetElevationGradientXY(const Eigen::Vector3d& position, double time) const override;
5454

55+
/// @brief Compute elevation using only the first N frequency components (for visualization).
56+
///
57+
/// This method is optimized for real-time visualization where visual quality can be
58+
/// traded for performance. Using fewer components (e.g., 50-100 instead of 1000)
59+
/// provides a significant speedup while maintaining a visually acceptable wave surface.
60+
///
61+
/// @param position World coordinates [m]. Only x-coordinate is used (waves propagate in +X).
62+
/// @param time Simulation time [s].
63+
/// @param max_components Maximum number of frequency components to use.
64+
/// If <= 0 or >= num_components, all components are used.
65+
/// @return Free-surface elevation [m] above mean water level.
66+
///
67+
/// @note Physics calculations should use GetElevation() which uses all components.
68+
double GetElevationForVisualization(const Eigen::Vector3d& position, double time, int max_components) const;
69+
5570
private:
5671
IrregularWaveParams params_;
5772
std::vector<double> spectrum_;

src/gui/vsg_gui_component.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,22 @@
11
// =============================================================================
22
// HydroChrono VSG GUI Component - Implementation
33
// =============================================================================
4+
5+
// Suppress MSVC warning about IMGUI_API macro redefinition in vsgImGui headers.
6+
// This is a harmless conflict between vsgImGui/imgui.h and vsgImGui/Export.h.
7+
#ifdef _MSC_VER
8+
#pragma warning(push)
9+
#pragma warning(disable : 4005) // macro redefinition
10+
#endif
11+
412
#include "vsg_gui_component.h"
513

614
#include <vsgImGui/imgui.h>
715

16+
#ifdef _MSC_VER
17+
#pragma warning(pop)
18+
#endif
19+
820
namespace hydroc {
921
namespace gui {
1022

src/gui/vsg_water_surface.cpp

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
#include <chrono/core/ChTypes.h>
1515
#include <chrono/physics/ChBodyEasy.h>
16+
#include <hydroc/waves/irregular_wave.h>
1617

1718
#include <Eigen/Dense>
1819

@@ -692,13 +693,27 @@ void AnimatedWaterSurface::Update(const std::shared_ptr<WaveBase>& wave, double
692693
// -------------------------------------------------------------------------
693694
std::vector<float> grid_eta(orig_verts.size(), 0.0f);
694695

696+
// For irregular waves, use limited frequency components for visualization.
697+
// 500 components provides excellent visual quality while being faster than
698+
// using all components (which can be 1000+). Physics always uses all components.
699+
constexpr int kVizFrequencyLimit = 500;
700+
701+
// Try to cast to IrregularWaves for the optimized visualization path.
702+
IrregularWaves* irreg_wave = nullptr;
703+
if (wave && wave->GetWaveMode() == WaveMode::irregular) {
704+
irreg_wave = dynamic_cast<IrregularWaves*>(wave.get());
705+
}
706+
695707
for (size_t i = 0; i < orig_verts.size(); ++i) {
696708
const auto& grid_pos = orig_verts[i];
709+
const Eigen::Vector3d pos(grid_pos.x(), grid_pos.y(), 0.0);
697710

698-
// Incident wave elevation from the wave model (regular or irregular).
711+
// Incident wave elevation from the wave model.
712+
// For irregular waves, use the visualization-optimized method with limited components.
699713
double eta_incident = 0.0;
700-
if (wave) {
701-
Eigen::Vector3d pos(grid_pos.x(), grid_pos.y(), 0.0);
714+
if (irreg_wave) {
715+
eta_incident = irreg_wave->GetElevationForVisualization(pos, t, kVizFrequencyLimit);
716+
} else if (wave) {
702717
eta_incident = wave->GetElevation(pos, t);
703718
}
704719

src/hydro/waves/irregular_wave.cpp

Lines changed: 41 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -207,19 +207,18 @@ double IrregularWaves::GetElevation(const Eigen::Vector3d& position, double time
207207
// x = position along wave propagation direction [m]
208208
// t = time [s]
209209
//
210-
// Performance: amplitudes_ and angular_freqs_ are pre-computed to avoid
211-
// repeated sqrt() and multiplication calls (critical for visualization).
210+
// Performance: Uses Eigen's vectorized operations (SIMD) for the summation.
211+
// The cos() is applied element-wise and the dot product sums the result.
212212
// -------------------------------------------------------------------------
213213
const double x = position.x();
214-
double eta = 0.0;
215214

216-
const Eigen::Index num_components = amplitudes_.size();
217-
for (Eigen::Index i = 0; i < num_components; ++i) {
218-
const double phase = wavenumbers_[i] * x - angular_freqs_[i] * time + wave_phases_[i];
219-
eta += amplitudes_[i] * std::cos(phase);
220-
}
215+
// Vectorized phase computation: phase_i = k_i*x - ω_i*t + φ_i
216+
const Eigen::ArrayXd phases = wavenumbers_.array() * x
217+
- angular_freqs_.array() * time
218+
+ wave_phases_.array();
221219

222-
return eta;
220+
// Vectorized elevation: η = Σ A_i * cos(phase_i)
221+
return (amplitudes_.array() * phases.cos()).sum();
223222
}
224223

225224
Eigen::Vector2d IrregularWaves::GetElevationGradientXY(const Eigen::Vector3d& position, double time) const {
@@ -240,19 +239,46 @@ Eigen::Vector2d IrregularWaves::GetElevationGradientXY(const Eigen::Vector3d& po
240239
//
241240
// Since waves propagate only in the +X direction, ∂η/∂y = 0.
242241
// The surface normal can be computed as: n = normalize(-∂η/∂x, -∂η/∂y, 1)
242+
//
243+
// Performance: Uses Eigen's vectorized operations (SIMD) for the summation.
243244
// -------------------------------------------------------------------------
244245
const double x = position.x();
245-
double deta_dx = 0.0;
246246

247-
const Eigen::Index num_components = amplitudes_.size();
248-
for (Eigen::Index i = 0; i < num_components; ++i) {
249-
const double phase = wavenumbers_[i] * x - angular_freqs_[i] * time + wave_phases_[i];
250-
deta_dx -= amplitudes_[i] * wavenumbers_[i] * std::sin(phase);
251-
}
247+
// Vectorized phase computation: phase_i = k_i*x - ω_i*t + φ_i
248+
const Eigen::ArrayXd phases = wavenumbers_.array() * x
249+
- angular_freqs_.array() * time
250+
+ wave_phases_.array();
251+
252+
// Vectorized gradient: ∂η/∂x = -Σ A_i * k_i * sin(phase_i)
253+
const double deta_dx = -(amplitudes_.array() * wavenumbers_.array() * phases.sin()).sum();
252254

253255
return Eigen::Vector2d(deta_dx, 0.0);
254256
}
255257

258+
double IrregularWaves::GetElevationForVisualization(const Eigen::Vector3d& position,
259+
double time,
260+
int max_components) const {
261+
// If no pre-computed amplitudes or max_components covers all, use full calculation.
262+
const Eigen::Index num_total = amplitudes_.size();
263+
if (num_total == 0) {
264+
return GetEtaIrregular(position, time, spectrum_frequencies_, spectral_densities_,
265+
spectral_widths_, wave_phases_, wavenumbers_);
266+
}
267+
268+
// Determine how many components to use.
269+
const Eigen::Index n = (max_components <= 0 || max_components >= num_total)
270+
? num_total
271+
: static_cast<Eigen::Index>(max_components);
272+
273+
// Use Eigen head() to get first n elements - still vectorized (SIMD).
274+
const double x = position.x();
275+
const Eigen::ArrayXd phases = wavenumbers_.head(n).array() * x
276+
- angular_freqs_.head(n).array() * time
277+
+ wave_phases_.head(n).array();
278+
279+
return (amplitudes_.head(n).array() * phases.cos()).sum();
280+
}
281+
256282
Eigen::VectorXd IrregularWaves::GetForceAtTime(double t) {
257283
unsigned int total_dofs = params_.num_bodies_ * 6;
258284
Eigen::VectorXd f(total_dofs);

0 commit comments

Comments
 (0)