Skip to content

Commit 007bbda

Browse files
committed
Separate IRF truncation from smoothing and tapering
Previously, truncating the radiation impulse response function (RIRF) was bundled into the TaperedDirect mode -- you couldn't shorten the kernel without also enabling smoothing and tapering. Excitation IRF truncation was buried inside the irregular wave settings. Introduce three independent, composable controls: 1. Excitation truncation time -- shorten the excitation IRF to ±T s 2. Radiation truncation time -- shorten the RIRF to [0, T] s 3. Kernel processing -- optionally smooth and/or taper the RIRF Each can be used on its own or combined. All three are exposed via both the C++ API (SetExcitationTruncationTime, SetRadiationTruncationTime, SetRadiationKernelProcessing) and YAML configuration. Truncation works regardless of wave type. YAML schema changes: Old: convolution.mode, convolution.taper.end_time New: excitation.truncation_time, radiation.truncation_time, radiation.smoothing, radiation.taper Additional quality improvements: - ExcitationRampType moved to hydrochrono::waves namespace (kLinear, kCosine) - Frequency defaults extracted to named constants in IrregularWaveParams - SG filter coefficients documented with citation, constexpr std::array - Embed RadiationKernelProcessing directly in YAMLHydroData (was 7 flat fields)
1 parent ba6219e commit 007bbda

16 files changed

Lines changed: 492 additions & 448 deletions

File tree

data/demos/run_hydrochrono/f3of/decay_dt3/inputs/f3of_decay.hydro.yaml

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,14 @@ hydrodynamics:
1010
waves:
1111
type: still
1212

13-
# System-wide convolution options
14-
convolution:
15-
mode: TaperedDirect # Baseline | TaperedDirect
13+
radiation:
14+
method: rirf_convolution
1615
smoothing:
17-
type: savitzky_golay # savitzky_golay | moving_average
18-
window_length: 5 # odd >= 3 (moving_average uses this; SG is fixed to quadratic, window=5)
16+
type: sg # sg | moving_average
17+
window_length: 5 # odd >= 3
1918
taper:
20-
start_percent: 0.8 # start taper at 80% of total time series (taper last 20%)
21-
end_percent: 1.0 # end taper at 100% of total time series
19+
start_percent: 0.8 # start taper at 80% of RIRF length
20+
end_percent: 1.0 # end taper at 100% of RIRF length
2221
final_amplitude: 0.0 # final amplitude (0.0 = zero, 1.0 = no change)
23-
end_time: -1.0 # truncate RIRF at this time (seconds), -1.0 = use full length
2422
diagnostics:
2523
export_csv: true # per-body CSV for representative channel (step,time,k_before,k_after)

data/yaml/rm3/rm3_mooring.hydro.yaml

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,16 @@ hydrodynamics:
77
h5_file: hydroData/rm3.h5
88

99
waves:
10-
type: still
10+
type: irregular
11+
eta_file: ../../verification/rm3_mooring/inputs/eta_rm3_mooring.txt
12+
ramp_duration: 40.0
13+
ramp_type: cosine
14+
frequency_min: 0.001
15+
frequency_max: 1.0
16+
nfrequencies: 1000
17+
18+
excitation:
19+
truncation_time: 20.0
1120

1221
moordyn:
1322
enabled: true

include/hydroc/config/hydro_config.h

Lines changed: 24 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#ifndef HYDROC_CONFIG_HYDRO_CONFIG_H
1212
#define HYDROC_CONFIG_HYDRO_CONFIG_H
1313

14+
#include <hydroc/radiation/radiation_types.h>
1415
#include <string>
1516
#include <vector>
1617
#include <array>
@@ -23,15 +24,6 @@ struct HydroBody {
2324
std::string h5_file = "";
2425
bool include_excitation = true;
2526
bool include_radiation = true;
26-
std::string radiation_calculation = "convolution"; // "convolution" or "state_space"
27-
// Optional convolution mode for radiation kernel preprocessing: "Baseline" (default) or "TaperedDirect"
28-
std::string radiation_convolution_mode = "Baseline";
29-
// Optional TaperedDirect tuning
30-
std::string td_smoothing = "sg"; // "sg" or "moving_average"
31-
int td_window_length = 5; // odd >= 3
32-
double td_rms_threshold_factor = 0.02; // e.g. 0.02
33-
double td_taper_fraction_remaining = 0.25; // e.g. 0.25
34-
bool td_export_plot_csv = false; // export CSV for before/after
3527
// TODO: Add nonlinear buoyancy fields
3628
// TODO: Add drag coefficient fields
3729
};
@@ -49,6 +41,14 @@ struct WaveSettings {
4941
int seed = -1; // optional irregular seed; -1 means unset
5042
// Sweep support (expanded values) for period; if empty, use 'period'
5143
std::vector<double> period_values;
44+
// Elevation import (if non-empty, overrides spectral generation)
45+
std::string eta_file;
46+
// Excitation ramp shape: "linear" (default) or "cosine" (WEC-Sim convention)
47+
std::string ramp_type = "linear";
48+
double ramp_duration = 0.0; // Ramp duration [s]; 0 = no ramp (overrides function param if > 0)
49+
double frequency_min = 0.0; // 0 = use IrregularWaveParams::kDefaultFreqMin
50+
double frequency_max = 0.0; // 0 = use IrregularWaveParams::kDefaultFreqMax
51+
int nfrequencies = 0; // 0 = use IrregularWaveParams::kDefaultNFrequencies
5252
// TODO: Add spectrum parameters (peak enhancement factor, etc.)
5353
};
5454

@@ -60,39 +60,33 @@ struct YAMLHydroData {
6060
WaveSettings waves;
6161

6262
// ─────────────────────────────────────────────────────────────────────────
63-
// Radiation method selection (system-wide)
63+
// Convolution truncation (system-wide, wave-type-independent)
6464
// ─────────────────────────────────────────────────────────────────────────
65-
// Top-level selection: "rirf_convolution" (default) or "state_space"
66-
std::string radiation_method = "rirf_convolution";
65+
double excitation_truncation_time = 0.0; ///< Excitation IRF truncation [s]; 0 = full
66+
double radiation_truncation_time = 0.0; ///< Radiation RIRF truncation [s]; 0 = full
6767

6868
// ─────────────────────────────────────────────────────────────────────────
69-
// State-space options (only used if radiation_method == "state_space")
69+
// Radiation method selection (system-wide)
7070
// ─────────────────────────────────────────────────────────────────────────
71-
int ss_max_order = 10; // Maximum exponential modes per DOF pair
72-
double ss_r2_threshold = 0.95; // R² fit quality threshold
73-
int ss_max_hankel_size = 200; // Max Hankel matrix size for SVD (key performance param)
74-
int ss_r2_num_samples = 50; // Number of samples for R² check during fitting
71+
std::string radiation_method = "rirf_convolution"; ///< "rirf_convolution" or "state_space"
7572

7673
// ─────────────────────────────────────────────────────────────────────────
77-
// Convolution settings (only used if radiation_method == "rirf_convolution")
74+
// Radiation kernel processing (smoothing + tapering, composable)
7875
// ─────────────────────────────────────────────────────────────────────────
79-
std::string radiation_convolution_mode = "Baseline"; // Baseline | TaperedDirect
80-
std::string td_smoothing = "sg";
81-
int td_window_length = 5;
82-
83-
// RIRF truncation
84-
double td_rirf_end_time = -1.0;
76+
hydrochrono::hydro::RadiationKernelProcessing radiation_kernel_processing;
8577

86-
// Simple taper control - sensible defaults for improved stability
87-
double td_taper_start_percent = 0.8; // start taper at 80% (taper last 20%)
88-
double td_taper_end_percent = 1.0; // end taper at 100% of total time series
89-
double td_taper_final_amplitude = 0.0; // final amplitude as fraction of original (0.0 = zero, 1.0 = no change)
90-
bool td_export_plot_csv = false; // dump before/after CSV summaries (false by default)
78+
// ─────────────────────────────────────────────────────────────────────────
79+
// State-space options (only used if radiation_method == "state_space")
80+
// ─────────────────────────────────────────────────────────────────────────
81+
int ss_max_order = 10;
82+
double ss_r2_threshold = 0.95;
83+
int ss_max_hankel_size = 200;
84+
int ss_r2_num_samples = 50;
9185

9286
// ─────────────────────────────────────────────────────────────────────────
9387
// Diagnostics
9488
// ─────────────────────────────────────────────────────────────────────────
95-
bool output_kernel_fit = false; // write kernel fit diagnostics to HDF5
89+
bool output_kernel_fit = false;
9690

9791
// ─────────────────────────────────────────────────────────────────────────
9892
// MoorDyn mooring coupling (optional)
@@ -103,4 +97,3 @@ struct YAMLHydroData {
10397
};
10498

10599
#endif // HYDROC_CONFIG_HYDRO_CONFIG_H
106-

include/hydroc/hydro_system.h

Lines changed: 36 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -360,14 +360,34 @@ class HydroSystem {
360360
double GetRIRFval(int row, int col, int st);
361361

362362
// ─────────────────────────────────────────────────────────────────────────
363-
// Radiation Configuration
363+
// Convolution Truncation and Radiation Configuration
364364
// ─────────────────────────────────────────────────────────────────────────
365-
// These types are defined in the radiation module (single source of truth):
365+
// Types from include/hydroc/radiation/radiation_types.h:
366366
// - hydrochrono::hydro::RadiationMethod (enum: kRirfConvolution, kStateSpace)
367-
// - hydrochrono::hydro::RadiationConvolutionMode (enum: Baseline, TaperedDirect)
368-
// - hydrochrono::hydro::TaperedDirectOptions (struct)
367+
// - hydrochrono::hydro::RadiationKernelProcessing (struct: smoothing + tapering)
369368
// - hydrochrono::hydro::StateSpaceOptions (struct)
370-
// See: include/hydroc/radiation/radiation_types.h
369+
370+
/**
371+
* @brief Truncate excitation IRF to [-T, T] seconds.
372+
*
373+
* 0 = use full IRF from H5 data. Only affects wave modes that use IRF
374+
* convolution (irregular waves). Safe to call for any wave type.
375+
* Must be called before the first timestep.
376+
*
377+
* @param seconds Truncation time in seconds (0 = no truncation)
378+
*/
379+
void SetExcitationTruncationTime(double seconds);
380+
381+
/**
382+
* @brief Truncate radiation RIRF to [0, T] seconds.
383+
*
384+
* 0 = use full RIRF from H5 data. Applied before any kernel processing
385+
* (smoothing/tapering). Works with all radiation methods (convolution and
386+
* state-space). Must be called before the first timestep.
387+
*
388+
* @param seconds Truncation time in seconds (0 = no truncation)
389+
*/
390+
void SetRadiationTruncationTime(double seconds);
371391

372392
/**
373393
* @brief Set the radiation damping calculation method.
@@ -376,9 +396,6 @@ class HydroSystem {
376396
* - kRirfConvolution: Direct RIRF convolution (default)
377397
* - kStateSpace: State-space exponential approximation
378398
*
379-
* @note State-space method not yet implemented. This value is stored but
380-
* currently has no effect; runtime always uses RIRF convolution.
381-
*
382399
* @param method RadiationMethod::kRirfConvolution or ::kStateSpace
383400
*/
384401
void SetRadiationMethod(hydrochrono::hydro::RadiationMethod method);
@@ -388,30 +405,20 @@ class HydroSystem {
388405
*
389406
* Only applies when RadiationMethod == kStateSpace.
390407
*
391-
* @note State-space method not yet implemented. Options stored for future use.
392-
*
393408
* @param opts StateSpaceOptions struct with max_order and r2_threshold
394409
*/
395410
void SetStateSpaceOptions(const hydrochrono::hydro::StateSpaceOptions& opts);
396411

397412
/**
398-
* @brief Set the radiation convolution mode. Default is Baseline.
413+
* @brief Configure RIRF kernel processing (smoothing and/or tapering).
399414
*
415+
* Applied after truncation (SetRadiationTruncationTime). Smoothing and
416+
* tapering are composable: either, both, or neither can be enabled.
400417
* Only applies when RadiationMethod == kRirfConvolution.
401418
*
402-
* @param mode RadiationConvolutionMode::Baseline or ::TaperedDirect
419+
* @param opts RadiationKernelProcessing with smoothing/taper settings
403420
*/
404-
void SetRadiationConvolutionMode(hydrochrono::hydro::RadiationConvolutionMode mode);
405-
406-
/**
407-
* @brief Set options for TaperedDirect preprocessing.
408-
*
409-
* Only applies when RadiationMethod == kRirfConvolution and
410-
* RadiationConvolutionMode == TaperedDirect.
411-
*
412-
* @param opts TaperedDirectOptions struct with smoothing, tapering, and export settings
413-
*/
414-
void SetTaperedDirectOptions(const hydrochrono::hydro::TaperedDirectOptions& opts);
421+
void SetRadiationKernelProcessing(const hydrochrono::hydro::RadiationKernelProcessing& opts);
415422

416423
/**
417424
* @brief Enable or disable kernel fit diagnostic output.
@@ -576,20 +583,22 @@ class HydroSystem {
576583
bool profiling_enabled_ = false;
577584

578585
// ─────────────────────────────────────────────────────────────────────────
579-
// Radiation configuration (uses canonical types from radiation module)
586+
// Convolution truncation and radiation configuration
580587
// ─────────────────────────────────────────────────────────────────────────
581588

589+
double excitation_truncation_time_ = 0.0; ///< Excitation IRF truncation [s], 0 = full
590+
double radiation_truncation_time_ = 0.0; ///< Radiation RIRF truncation [s], 0 = full
591+
582592
// Top-level method selection
583593
hydrochrono::hydro::RadiationMethod radiation_method_ =
584594
hydrochrono::hydro::RadiationMethod::kRirfConvolution;
585595
hydrochrono::hydro::StateSpaceOptions state_space_opts_;
586596
bool output_kernel_fit_ = false;
587597

588-
// Convolution kernel preprocessing (only applies when method == kRirfConvolution)
589-
hydrochrono::hydro::RadiationConvolutionMode convolution_mode_;
598+
// Kernel processing (smoothing + tapering, composable, defaults are no-ops)
599+
hydrochrono::hydro::RadiationKernelProcessing kernel_processing_;
590600
bool rirf_processed_ready_ = false;
591601
std::vector<Eigen::Tensor<double, 3>> rirf_processed_; // per body [dof x col x step]
592-
hydrochrono::hydro::TaperedDirectOptions tapered_opts_;
593602
std::string diagnostics_output_dir_;
594603

595604
void EnsureProcessedRIRF();

include/hydroc/radiation/radiation_types.h

Lines changed: 26 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@
44
*
55
* MAIN TYPES:
66
* - RadiationMethod: Selects the radiation damping calculation method
7-
* - RadiationConvolutionMode: Baseline vs TaperedDirect RIRF processing
8-
* - TaperedDirectOptions: Smoothing, tapering, and export settings
7+
* - RadiationKernelProcessing: Composable smoothing + tapering for RIRF kernels
98
* - StateSpaceOptions: Settings for state-space radiation approximation
109
*********************************************************************/
1110

@@ -23,43 +22,41 @@ namespace hydrochrono::hydro {
2322
* - kRirfConvolution: Direct convolution of RIRF kernels with velocity history (default)
2423
* - kStateSpace: State-space approximation using exponential decay modes
2524
*
26-
* When using kRirfConvolution, additional options are available via
27-
* RadiationConvolutionMode (Baseline vs TaperedDirect).
25+
* RIRF truncation (SetRadiationTruncationTime) is applied before either method.
26+
* Kernel processing (smoothing/tapering) is applied only for kRirfConvolution.
2827
*/
2928
enum class RadiationMethod {
3029
kRirfConvolution, ///< Direct RIRF convolution (default, existing method)
3130
kStateSpace ///< State-space approximation (exponential decay modes)
3231
};
3332

3433
/**
35-
* @brief Convolution mode for radiation damping.
34+
* @brief Composable RIRF kernel processing options (smoothing and/or tapering).
3635
*
37-
* Only applies when RadiationMethod == kRirfConvolution.
38-
*/
39-
enum class RadiationConvolutionMode {
40-
Baseline,
41-
TaperedDirect
42-
};
43-
44-
/**
45-
* @brief Options for TaperedDirect RIRF preprocessing.
36+
* Applied after RIRF truncation (which is handled separately via
37+
* HydroSystem::SetRadiationTruncationTime). Smoothing is applied first,
38+
* then tapering.
4639
*
47-
* Only applies when RadiationMethod == kRirfConvolution and
48-
* RadiationConvolutionMode == TaperedDirect.
40+
* Defaults are no-ops: smoothing is "none" and taper is disabled. If neither
41+
* is configured, no kernel processing occurs.
4942
*/
50-
struct TaperedDirectOptions {
51-
// smoothing: "sg" (Savitzky–Golay) or "moving_average"
52-
std::string smoothing = "sg";
53-
int window_length = 5; // odd, >= 3
54-
55-
// RIRF truncation
56-
double rirf_end_time = -1.0; // end RIRF at this time (seconds), -1.0 = use full length
57-
58-
// Simple taper control - sensible defaults for improved stability
59-
double taper_start_percent = 0.8; // start taper at 80% (taper last 20%)
60-
double taper_end_percent = 1.0; // end taper at 100% of total time series
61-
double taper_final_amplitude = 0.0; // final amplitude as fraction of original (0.0 = zero, 1.0 = no change)
62-
bool export_plot_csv = false; // dump before/after CSV summaries (false by default)
43+
struct RadiationKernelProcessing {
44+
/// Smoothing type: "none" (default), "sg" (Savitzky-Golay), or "moving_average"
45+
std::string smoothing_type = "none";
46+
int smoothing_window = 5; ///< Smoothing window length (odd, >= 3)
47+
48+
/// Tapering: when enabled, applies a half-cosine taper window near the end of the RIRF
49+
bool taper_enabled = false;
50+
double taper_start_percent = 0.8; ///< Start taper at this fraction of RIRF length
51+
double taper_end_percent = 1.0; ///< End taper at this fraction of RIRF length
52+
double taper_final_amplitude = 0.0; ///< Final amplitude (0.0 = zero, 1.0 = no change)
53+
54+
bool export_csv = false; ///< Export before/after CSV for diagnostics
55+
56+
/// Returns true if any processing (smoothing or tapering) is configured.
57+
bool RequiresProcessing() const {
58+
return smoothing_type != "none" || taper_enabled;
59+
}
6360
};
6461

6562
/**

0 commit comments

Comments
 (0)