Skip to content

Commit cd76da7

Browse files
authored
Merge pull request #49 from tridelat/ex_interp
Interpolate when doing excitation force convolution
2 parents 0a58e4a + 27f8d9a commit cd76da7

5 files changed

Lines changed: 262 additions & 434 deletions

File tree

doc/user/_theory/theory.rst

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ This transform allows the frequency domain coefficients, :math:`B(\omega)`, to b
117117
Wave excitation force, :math:`F_{exc}(t)`
118118
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
119119

120-
The following method to compute the wave excitation force involves convolution between the excitation impulse response function :math:`K_{exc}(t)` and the wave elevation time sequence :math:`\eta(t)`:
120+
The following method to compute the wave excitation force involves convolution between the excitation Impulse Response Function (IRF) :math:`K_{exc}(t)` and the wave elevation time sequence :math:`\eta(t)`:
121121

122122
.. math::
123123
:label: f_ex
@@ -126,6 +126,8 @@ The following method to compute the wave excitation force involves convolution b
126126
127127
By amalgamating these forces into the equation of motion, one can effectively model the behavior of a multibody oceanic system influenced by hydrodynamic forces.
128128

129+
In HydroChrono, the force is computed through trapezoidal integration by discretizing at the time values given by the excitation IRF time array relative to the current simulation time step. Linear interpolation is done for the free surface elevation if a given time value is between two values of the time series of the precomputed free surface elevation.
130+
129131

130132
.. rubric:: Footnotes
131133

include/hydroc/helper.h

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,40 +3,48 @@
33

44
#pragma once
55

6-
#include <string>
7-
#include <iostream>
6+
#include <Eigen/Dense> // Need for the container function
87
#include <fstream>
9-
#include <Eigen/Dense> // Need for the container function
10-
8+
#include <iostream>
9+
#include <string>
1110

1211
#ifndef M_PI
1312
#define M_PI 3.14159265358979323846
1413
#endif
14+
15+
/**@brief Returns last index of vector element below value.
16+
*
17+
* @param value Input value
18+
* @param ticks Array of ticks from which to find lower-bound index (assuming ascending order)
19+
*
20+
*/
21+
size_t get_lower_index(double value, const std::vector<double>& ticks);
22+
1523
/**@brief Base namespace for HydroChrono library
16-
*
17-
*/
24+
*
25+
*/
1826
namespace hydroc {
1927

2028
/**@brief Set initial environment
21-
*
29+
*
2230
* Use command line argument or env variables to set s
2331
* ome static data at initialization.
24-
*
32+
*
2533
* Set the main data directory ..
26-
*
34+
*
2735
* @param argc number of argument (same as for main function)
28-
* @param argv arguments of main function
36+
* @param argv arguments of main function
2937
* @return 1 on error 0 else
30-
*/
38+
*/
3139
int SetInitialEnvironment(int argc, char* argv[]) noexcept;
3240

3341
/**@brief Get base name of data directory
34-
*
42+
*
3543
* @return the string containing the path in standard format
36-
*/
44+
*/
3745
std::string getDataDir() noexcept;
3846
template <typename T>
39-
void WriteDataToFile(const std::vector<T>& data, const std::string& filename){
47+
void WriteDataToFile(const std::vector<T>& data, const std::string& filename) {
4048
std::ofstream outFile(filename);
4149
if (outFile.is_open()) {
4250
for (const auto& item : data) {
@@ -66,7 +74,8 @@ void WriteContainerToFile(const Container& container, const std::string& file_na
6674
* @param file_name file to write container to
6775
*/
6876
template <>
69-
void inline WriteContainerToFile<std::vector<double>>(const std::vector<double>& container, const std::string& file_name) {
77+
void inline WriteContainerToFile<std::vector<double>>(const std::vector<double>& container,
78+
const std::string& file_name) {
7079
std::ofstream output_file(file_name);
7180

7281
if (!output_file) {
@@ -103,6 +112,6 @@ void inline WriteContainerToFile<Eigen::VectorXd>(const Eigen::VectorXd& contain
103112
output_file.close();
104113
};
105114

106-
} // end namespace hydroc
115+
} // end namespace hydroc
107116

108117
#endif

include/hydroc/wave_types.h

Lines changed: 34 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,14 @@
1313
// todo move this helper function somewhere else?
1414
Eigen::VectorXd PiersonMoskowitzSpectrumHz(Eigen::VectorXd& f, double Hs, double Tp);
1515

16-
Eigen::VectorXd JONSWAPSpectrumHz(Eigen::VectorXd& f, double Hs, double Tp, double gamma=3.3);
16+
Eigen::VectorXd JONSWAPSpectrumHz(Eigen::VectorXd& f, double Hs, double Tp, double gamma = 3.3);
1717

1818
std::vector<double> FreeSurfaceElevation(const Eigen::VectorXd& freqs_hz,
1919
const Eigen::VectorXd& spectral_densities,
20-
const Eigen::VectorXd& time_index,
20+
const Eigen::VectorXd& time_array,
2121
double water_depth,
2222
int seed = 1);
2323

24-
2524
enum class WaveMode {
2625
/// @brief No waves
2726
noWaveCIC = 0,
@@ -187,7 +186,7 @@ class RegularWave : public WaveBase {
187186
};
188187

189188
//// class to instantiate WaveBase for irregular waves
190-
//class IrregularWave : public WaveBase {
189+
// class IrregularWave : public WaveBase {
191190
// public:
192191
// IrregularWave();
193192
// IrregularWave(unsigned int num_b);
@@ -207,7 +206,8 @@ class RegularWave : public WaveBase {
207206
// double ramp_duration;
208207
// Eigen::VectorXd eta;
209208
//
210-
// void AddH5Data(std::vector<HydroData::IrregularWaveInfo>& irreg_h5_data, HydroData::SimulationParameters& sim_data);
209+
// void AddH5Data(std::vector<HydroData::IrregularWaveInfo>& irreg_h5_data, HydroData::SimulationParameters&
210+
// sim_data);
211211
//
212212
// private:
213213
// unsigned int num_bodies;
@@ -222,8 +222,8 @@ class RegularWave : public WaveBase {
222222
//
223223
// // Eigen::MatrixXd GetExcitationIRF(int b) const;
224224
// Eigen::VectorXd ResampleTime(const Eigen::VectorXd& t_old, const double dt_new);
225-
// Eigen::MatrixXd ResampleVals(const Eigen::VectorXd& t_old, Eigen::MatrixXd& vals_old, const Eigen::VectorXd& t_new);
226-
// double ExcitationConvolution(int body, int dof, double time);
225+
// Eigen::MatrixXd ResampleVals(const Eigen::VectorXd& t_old, Eigen::MatrixXd& vals_old, const Eigen::VectorXd&
226+
// t_new); double ExcitationConvolution(int body, int dof, double time);
227227
//
228228
// void CreateSpectrum();
229229
// void IrregularWave::CreateFreeSurfaceElevation();
@@ -236,10 +236,10 @@ struct IrregularWaveParams {
236236
double simulation_duration_;
237237
double ramp_duration_ = 0.0;
238238
std::string eta_file_path_;
239-
double wave_height_ = 0.0;
240-
double wave_period_ = 0.0;
239+
double wave_height_ = 0.0;
240+
double wave_period_ = 0.0;
241241
double peak_enhancement_factor_ = 1.0;
242-
int seed_ = 1;
242+
int seed_ = 1;
243243
};
244244

245245
class IrregularWaves : public WaveBase {
@@ -300,12 +300,13 @@ class IrregularWaves : public WaveBase {
300300
Eigen::Vector3<double> GetWaveMeshVelocity();
301301

302302
// user input // TODO add default values in case user doesn't initialize these?
303-
//double wave_height_;
304-
//double wave_period_;
305-
//double simulation_duration_;
306-
//double simulation_dt_;
307-
//double ramp_duration_;
308-
//Eigen::VectorXd eta_; // public for mesh printing functions, TODO maybe make those friends, so this can be private?
303+
// double wave_height_;
304+
// double wave_period_;
305+
// double simulation_duration_;
306+
// double simulation_dt_;
307+
// double ramp_duration_;
308+
// Eigen::VectorXd eta_; // public for mesh printing functions, TODO maybe make those friends, so this can be
309+
// private?
309310

310311
/**
311312
* @brief Initializes other member variables for timestep calculations later.
@@ -329,16 +330,18 @@ class IrregularWaves : public WaveBase {
329330
int seed_;
330331
std::vector<double> spectrum_;
331332
std::vector<double> time_data_;
332-
std::vector<double> free_surface_elevation_;
333+
std::vector<double> free_surface_elevation_sampled_;
334+
std::vector<double> free_surface_time_sampled_;
333335
bool spectrumCreated_;
334336

335337
const WaveMode mode_ = WaveMode::irregular;
336-
//unsigned int num_bodies_;
337-
//const WaveMode mode_ = WaveMode::irregular;
338+
// unsigned int num_bodies_;
339+
// const WaveMode mode_ = WaveMode::irregular;
338340
std::vector<HydroData::IrregularWaveInfo> wave_info_;
339341
HydroData::SimulationParameters sim_data_;
340-
std::vector<Eigen::MatrixXd> ex_irf_resampled_;
341-
std::vector<Eigen::VectorXd> ex_irf_time_resampled_;
342+
std::vector<Eigen::MatrixXd> ex_irf_sampled_;
343+
std::vector<Eigen::VectorXd> ex_irf_time_sampled_;
344+
std::vector<Eigen::VectorXd> ex_irf_width_sampled_;
342345
Eigen::VectorXd spectrum_frequencies_;
343346
Eigen::VectorXd spectral_densities_;
344347
std::string mesh_file_name_;
@@ -350,34 +353,24 @@ class IrregularWaves : public WaveBase {
350353

351354
Eigen::MatrixXd GetExcitationIRF(int b) const;
352355

353-
/**
354-
* @brief resamples irf time vector from old time vector and new timestep.
355-
*
356-
* Creates a resized time vector that starts and ends at the same values as t_old and has timestep t_new.
357-
*
358-
* @param t_old reference to old time vector from h5 file, the first and last element are transfered to the first
359-
* and last element of t_new (return val)
360-
* @param dt_new the time step to use in resampled vector, typically the timestep of chrono simulation
356+
/** @brief Resamples IRF time, widths, and values.
361357
*
362-
* @return newly sized vector that looks like \
363-
* (t_old[0], t_old[0] + dt_new, t_old[0] + 2*dt_new, ... , t_old[t_old.size()-1])
358+
* @param dt Time step value to resample
364359
*/
365-
Eigen::VectorXd ResampleTime(const Eigen::VectorXd& t_old, const double dt_new);
360+
void ResampleIRF(double dt);
366361

367-
/**
368-
* @brief Creates a resized values vector to interpolate values for a new timestep.
369-
*
370-
* @param t_old reference to old time vector from h5 file
371-
* @param vals_old the original values corresponding to the times in t_old from h5 file
372-
* @param t_new resampled times (return value from ResampleTime()) to use in interpolation
373-
*
374-
* @return matrix for interpolated vals_old over t_new
362+
/** @brief Calculates width (used for excitation convolution).
375363
*/
376-
Eigen::MatrixXd ResampleVals(const Eigen::VectorXd& t_old, Eigen::MatrixXd& vals_old, const Eigen::VectorXd& t_new);
364+
void IrregularWaves::CalculateWidthIRF();
377365

378366
/**
379367
* @brief Calculates the component of force from Convolution integral for specified body, dof, time.
380368
*
369+
* The discretization uses the time series of the of the IRF relative to the current time step.
370+
* Linear interpolation is done for the free surface elevation if time_sim-time_irf is between two
371+
* values of the time series of the precomputed free surface elevation.
372+
* Trapezoidal integration is used to compute the force.
373+
*
381374
* @param body which body currently calculating for
382375
* @param dof which degree of freedom to calculate force value for
383376
* @param time the time to compute force for

src/helper.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,22 @@
55
#include <memory>
66
#include <vector>
77

8+
size_t get_lower_index(double value, const std::vector<double>& ticks) {
9+
auto it = std::upper_bound(ticks.begin(), ticks.end(), value);
10+
// get nearest-below index
11+
size_t idx = it - ticks.begin() - 1;
12+
// remove one if equal to value
13+
if (ticks[idx] == value) {
14+
idx -= 1;
15+
}
16+
if (idx <= 0 || idx >= ticks.size() - 1) {
17+
throw std::runtime_error("Could not find index for value " + std::to_string(value) + " in array with bounds (" +
18+
std::to_string(ticks.front()) + ", " + std::to_string(ticks.back()) + ").");
19+
}
20+
// return index
21+
return idx;
22+
}
23+
824
using std::filesystem::path;
925

1026
static path DATADIR{};

0 commit comments

Comments
 (0)