Skip to content

Commit 2c88d25

Browse files
committed
Add RadiationMethod enum and state-space config plumbing
- Add RadiationMethod enum (kRirfConvolution, kStateSpace) to radiation_types.h - Add StateSpaceOptions struct with max_order and r2_threshold - Add YAML parsing for radiation.method and radiation.state_space section - Add HydroSystem::SetRadiationMethod() and SetStateSpaceOptions() setters - Wire config through SetupHydroFromYAML with CLI logging State-space method is not yet implemented; runtime always uses RIRF convolution. All tests passing.
1 parent 1b81e26 commit 2c88d25

6 files changed

Lines changed: 201 additions & 10 deletions

File tree

include/hydroc/config/hydro_config.h

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,22 @@ struct WaveSettings {
5858
struct YAMLHydroData {
5959
std::vector<HydroBody> bodies;
6060
WaveSettings waves;
61-
// Optional system-wide convolution settings
61+
62+
// ─────────────────────────────────────────────────────────────────────────
63+
// Radiation method selection (system-wide)
64+
// ─────────────────────────────────────────────────────────────────────────
65+
// Top-level selection: "rirf_convolution" (default) or "state_space"
66+
std::string radiation_method = "rirf_convolution";
67+
68+
// ─────────────────────────────────────────────────────────────────────────
69+
// State-space options (only used if radiation_method == "state_space")
70+
// ─────────────────────────────────────────────────────────────────────────
71+
int ss_max_order = 10; // Maximum exponential modes per DOF pair
72+
double ss_r2_threshold = 0.95; // R² fit quality threshold
73+
74+
// ─────────────────────────────────────────────────────────────────────────
75+
// Convolution settings (only used if radiation_method == "rirf_convolution")
76+
// ─────────────────────────────────────────────────────────────────────────
6277
std::string radiation_convolution_mode = "Baseline"; // Baseline | TaperedDirect
6378
std::string td_smoothing = "sg";
6479
int td_window_length = 5;

include/hydroc/hydro_system.h

Lines changed: 47 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -337,22 +337,55 @@ class HydroSystem {
337337
double GetRIRFval(int row, int col, int st);
338338

339339
// ─────────────────────────────────────────────────────────────────────────
340-
// Radiation Convolution Configuration
340+
// Radiation Configuration
341341
// ─────────────────────────────────────────────────────────────────────────
342342
// These types are defined in the radiation module (single source of truth):
343-
// - hydrochrono::hydro::RadiationConvolutionMode (enum)
343+
// - hydrochrono::hydro::RadiationMethod (enum: kRirfConvolution, kStateSpace)
344+
// - hydrochrono::hydro::RadiationConvolutionMode (enum: Baseline, TaperedDirect)
344345
// - hydrochrono::hydro::TaperedDirectOptions (struct)
345-
// See: src/hydro/force_components/radiation_component.h
346-
// src/hydro/radiation/radiation_rirf_processing.h
346+
// - hydrochrono::hydro::StateSpaceOptions (struct)
347+
// See: include/hydroc/radiation/radiation_types.h
348+
349+
/**
350+
* @brief Set the radiation damping calculation method.
351+
*
352+
* Selects the overall approach:
353+
* - kRirfConvolution: Direct RIRF convolution (default)
354+
* - kStateSpace: State-space exponential approximation
355+
*
356+
* @note State-space method not yet implemented. This value is stored but
357+
* currently has no effect; runtime always uses RIRF convolution.
358+
*
359+
* @param method RadiationMethod::kRirfConvolution or ::kStateSpace
360+
*/
361+
void SetRadiationMethod(hydrochrono::hydro::RadiationMethod method);
362+
363+
/**
364+
* @brief Set options for state-space radiation approximation.
365+
*
366+
* Only applies when RadiationMethod == kStateSpace.
367+
*
368+
* @note State-space method not yet implemented. Options stored for future use.
369+
*
370+
* @param opts StateSpaceOptions struct with max_order and r2_threshold
371+
*/
372+
void SetStateSpaceOptions(const hydrochrono::hydro::StateSpaceOptions& opts);
347373

348374
/**
349375
* @brief Set the radiation convolution mode. Default is Baseline.
376+
*
377+
* Only applies when RadiationMethod == kRirfConvolution.
378+
*
350379
* @param mode RadiationConvolutionMode::Baseline or ::TaperedDirect
351380
*/
352381
void SetRadiationConvolutionMode(hydrochrono::hydro::RadiationConvolutionMode mode);
353382

354383
/**
355384
* @brief Set options for TaperedDirect preprocessing.
385+
*
386+
* Only applies when RadiationMethod == kRirfConvolution and
387+
* RadiationConvolutionMode == TaperedDirect.
388+
*
356389
* @param opts TaperedDirectOptions struct with smoothing, tapering, and export settings
357390
*/
358391
void SetTaperedDirectOptions(const hydrochrono::hydro::TaperedDirectOptions& opts);
@@ -468,8 +501,16 @@ class HydroSystem {
468501
// Profiling enable flag: stored here because chrono_coupler_ is created lazily.
469502
bool profiling_enabled_ = false;
470503

471-
// Convolution kernel preprocessing (optional)
472-
// Uses canonical types from radiation module (single source of truth)
504+
// ─────────────────────────────────────────────────────────────────────────
505+
// Radiation configuration (uses canonical types from radiation module)
506+
// ─────────────────────────────────────────────────────────────────────────
507+
508+
// Top-level method selection (state-space not yet implemented)
509+
hydrochrono::hydro::RadiationMethod radiation_method_ =
510+
hydrochrono::hydro::RadiationMethod::kRirfConvolution;
511+
hydrochrono::hydro::StateSpaceOptions state_space_opts_;
512+
513+
// Convolution kernel preprocessing (only applies when method == kRirfConvolution)
473514
hydrochrono::hydro::RadiationConvolutionMode convolution_mode_;
474515
bool rirf_processed_ready_ = false;
475516
std::vector<Eigen::Tensor<double, 3>> rirf_processed_; // per body [dof x col x step]

include/hydroc/radiation/radiation_types.h

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@
33
* @brief Public types for radiation damping configuration.
44
*
55
* MAIN TYPES:
6+
* - RadiationMethod: Selects the radiation damping calculation method
67
* - RadiationConvolutionMode: Baseline vs TaperedDirect RIRF processing
78
* - TaperedDirectOptions: Smoothing, tapering, and export settings
9+
* - StateSpaceOptions: Settings for state-space radiation approximation
810
*********************************************************************/
911

1012
#ifndef HYDROC_RADIATION_TYPES_H
@@ -14,8 +16,25 @@
1416

1517
namespace hydrochrono::hydro {
1618

19+
/**
20+
* @brief Radiation damping calculation method.
21+
*
22+
* Selects the overall approach for computing radiation damping forces:
23+
* - kRirfConvolution: Direct convolution of RIRF kernels with velocity history (default)
24+
* - kStateSpace: State-space approximation using exponential decay modes
25+
*
26+
* When using kRirfConvolution, additional options are available via
27+
* RadiationConvolutionMode (Baseline vs TaperedDirect).
28+
*/
29+
enum class RadiationMethod {
30+
kRirfConvolution, ///< Direct RIRF convolution (default, existing method)
31+
kStateSpace ///< State-space approximation (exponential decay modes)
32+
};
33+
1734
/**
1835
* @brief Convolution mode for radiation damping.
36+
*
37+
* Only applies when RadiationMethod == kRirfConvolution.
1938
*/
2039
enum class RadiationConvolutionMode {
2140
Baseline,
@@ -24,6 +43,9 @@ enum class RadiationConvolutionMode {
2443

2544
/**
2645
* @brief Options for TaperedDirect RIRF preprocessing.
46+
*
47+
* Only applies when RadiationMethod == kRirfConvolution and
48+
* RadiationConvolutionMode == TaperedDirect.
2749
*/
2850
struct TaperedDirectOptions {
2951
// smoothing: "sg" (Savitzky–Golay) or "moving_average"
@@ -40,6 +62,37 @@ struct TaperedDirectOptions {
4062
bool export_plot_csv = false; // dump before/after CSV summaries (false by default)
4163
};
4264

65+
/**
66+
* @brief Options for state-space radiation approximation.
67+
*
68+
* Only applies when RadiationMethod == kStateSpace.
69+
*
70+
* The state-space method approximates the radiation impulse response as a sum
71+
* of exponential decay modes: K(τ) ≈ Σ H_m * exp(-α_m * τ). This enables O(1)
72+
* per-timestep computation vs O(N) for direct convolution.
73+
*
74+
* These options control the fitting process that determines the number of
75+
* exponential modes and their parameters (H_m, α_m) from the RIRF data.
76+
*/
77+
struct StateSpaceOptions {
78+
/**
79+
* @brief Maximum number of exponential modes to use per DOF pair.
80+
*
81+
* Higher values improve fit quality but increase computation time.
82+
* The fitter may use fewer modes if a good fit is achieved earlier.
83+
* Typical values: 2-10. Default: 10.
84+
*/
85+
int max_order = 10;
86+
87+
/**
88+
* @brief Minimum R² (coefficient of determination) threshold for fit acceptance.
89+
*
90+
* The fitter adds modes until either R² >= r2_threshold or max_order is reached.
91+
* Values closer to 1.0 require better fits. Default: 0.95.
92+
*/
93+
double r2_threshold = 0.95;
94+
};
95+
4396
} // namespace hydrochrono::hydro
4497

4598
#endif // HYDROC_RADIATION_TYPES_H

src/hydro/config/setup_from_yaml.cpp

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,37 @@ std::unique_ptr<HydroSystem> SetupHydroFromYAML(
172172

173173
hydroc::debug::LogDebug(std::string("Initialized HydroSystem with ") + std::to_string(matched_bodies.size()) + " bodies");
174174

175-
// System-wide convolution settings (applies to all bodies)
175+
// ─────────────────────────────────────────────────────────────────────────
176+
// Radiation method selection
177+
// ─────────────────────────────────────────────────────────────────────────
178+
std::string method = hydro_data.radiation_method;
179+
std::transform(method.begin(), method.end(), method.begin(), ::tolower);
180+
181+
if (method == "state_space") {
182+
hydro_system->SetRadiationMethod(hydrochrono::hydro::RadiationMethod::kStateSpace);
183+
hydroc::cli::LogInfo(hydroc::cli::CreateAlignedLine("", "Radiation Method", "StateSpace (config stored, not yet active)"));
184+
185+
// Set state-space options
186+
hydrochrono::hydro::StateSpaceOptions ss_opts;
187+
ss_opts.max_order = hydro_data.ss_max_order;
188+
ss_opts.r2_threshold = hydro_data.ss_r2_threshold;
189+
hydro_system->SetStateSpaceOptions(ss_opts);
190+
191+
if (hydroc::debug::IsDebugEnabled()) {
192+
hydroc::cli::LogInfo(hydroc::cli::CreateAlignedLine("", "SS Max Order", std::to_string(ss_opts.max_order)));
193+
hydroc::cli::LogInfo(hydroc::cli::CreateAlignedLine("", "SS R² Threshold", std::to_string(ss_opts.r2_threshold)));
194+
}
195+
196+
// Note: State-space method not yet implemented; runtime uses RIRF convolution.
197+
} else {
198+
// Default: rirf_convolution (or any unrecognized value)
199+
hydro_system->SetRadiationMethod(hydrochrono::hydro::RadiationMethod::kRirfConvolution);
200+
hydroc::debug::LogDebug("Radiation method: RIRF Convolution (default)");
201+
}
202+
203+
// ─────────────────────────────────────────────────────────────────────────
204+
// Convolution settings (applies when method == rirf_convolution)
205+
// ─────────────────────────────────────────────────────────────────────────
176206
std::string mode = hydro_data.radiation_convolution_mode;
177207
hydroc::debug::LogDebug("Parsed convolution mode: '" + mode + "'");
178208
std::transform(mode.begin(), mode.end(), mode.begin(), ::tolower);

src/hydro/config/yaml_parser.cpp

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,8 @@ YAMLHydroData ReadHydroYAML(const std::string& hydro_file_path) {
163163
bool in_hydrodynamics = false;
164164
bool in_bodies = false;
165165
bool in_waves = false;
166+
bool in_radiation = false; // Top-level radiation: section
167+
bool in_radiation_state_space = false; // radiation.state_space: subsection
166168
bool in_convolution = false;
167169
bool in_conv_smoothing = false;
168170
bool in_conv_taper = false;
@@ -266,12 +268,29 @@ YAMLHydroData ReadHydroYAML(const std::string& hydro_file_path) {
266268
continue;
267269
}
268270

271+
if (indent == 2 && trimmed == "radiation:") {
272+
// Save any pending body before switching sections
273+
if (in_body && !current_body.name.empty()) {
274+
data.bodies.push_back(current_body);
275+
}
276+
in_radiation = true;
277+
in_radiation_state_space = false;
278+
in_convolution = false;
279+
in_bodies = false;
280+
in_waves = false;
281+
in_body = false;
282+
in_conv_smoothing = in_conv_taper = in_conv_diag = false;
283+
continue;
284+
}
285+
269286
if (indent == 2 && (trimmed == "convolution:" || trimmed == "radiation_convolution:")) {
270287
// Save any pending body before switching sections
271288
if (in_body && !current_body.name.empty()) {
272289
data.bodies.push_back(current_body);
273290
}
274291
in_convolution = true;
292+
in_radiation = false;
293+
in_radiation_state_space = false;
275294
in_bodies = false;
276295
in_waves = false;
277296
in_body = false;
@@ -310,7 +329,9 @@ YAMLHydroData ReadHydroYAML(const std::string& hydro_file_path) {
310329
std::string key;
311330
std::string value;
312331
bool should_parse = (
313-
(!in_bodies && !in_waves && in_hydrodynamics && !in_convolution && indent == 2) ||
332+
(!in_bodies && !in_waves && in_hydrodynamics && !in_convolution && !in_radiation && indent == 2) ||
333+
(in_radiation && indent == 4) ||
334+
(in_radiation_state_space && indent == 6) ||
314335
(in_convolution && indent == 4) ||
315336
(in_conv_smoothing && indent == 6) ||
316337
(in_conv_taper && indent == 6) ||
@@ -319,7 +340,26 @@ YAMLHydroData ReadHydroYAML(const std::string& hydro_file_path) {
319340
(in_waves && (indent == 4 || (in_period_block && indent >= period_block_indent + 2)))
320341
);
321342
if (should_parse && ParseYAMLLine(line, key, value)) {
322-
if (in_convolution && indent == 4) {
343+
// ─────────────────────────────────────────────────────────────
344+
// radiation: section parsing
345+
// ─────────────────────────────────────────────────────────────
346+
if (in_radiation && indent == 4) {
347+
if (key == "method") {
348+
// "rirf_convolution" or "state_space"
349+
data.radiation_method = value;
350+
} else if (key == "state_space") {
351+
// Start of nested state_space: block
352+
if (value.empty()) {
353+
in_radiation_state_space = true;
354+
}
355+
}
356+
} else if (in_radiation_state_space && indent == 6) {
357+
if (key == "max_order") {
358+
try { data.ss_max_order = std::stoi(value); } catch (...) {}
359+
} else if (key == "r2_threshold") {
360+
data.ss_r2_threshold = ParseDouble(value, data.ss_r2_threshold);
361+
}
362+
} else if (in_convolution && indent == 4) {
323363
// Top level keys under convolution
324364
if (key == "mode") {
325365
data.radiation_convolution_mode = value;

src/hydro/hydro_system.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -421,6 +421,18 @@ void HydroSystem::InvalidateRadiationComponent() {
421421
// Radiation configuration setters
422422
// ─────────────────────────────────────────────────────────────────────────
423423

424+
void HydroSystem::SetRadiationMethod(hydrochrono::hydro::RadiationMethod method) {
425+
radiation_method_ = method;
426+
// Note: State-space method is not yet implemented.
427+
// Currently stored for future use; runtime always uses RIRF convolution.
428+
}
429+
430+
void HydroSystem::SetStateSpaceOptions(const hydrochrono::hydro::StateSpaceOptions& opts) {
431+
state_space_opts_ = opts;
432+
// Note: State-space options are stored for future use.
433+
// Currently has no effect; runtime always uses RIRF convolution.
434+
}
435+
424436
void HydroSystem::SetRadiationConvolutionMode(hydrochrono::hydro::RadiationConvolutionMode mode) {
425437
convolution_mode_ = mode;
426438
InvalidateRadiationComponent(); // Invalidate component to recreate with new settings

0 commit comments

Comments
 (0)