1414#include < chrono/physics/ChLoad.h>
1515#include < unsupported/Eigen/Splines>
1616
17+ #include < Eigen/Dense>
1718#include < algorithm>
1819#include < cmath>
20+ #include < fstream>
21+ #include < iostream>
1922#include < memory>
2023#include < numeric> // std::accumulate
2124#include < random>
22- #include < vector>
23- #include < Eigen/Dense>
24- #include < fstream>
25- #include < iostream>
2625#include < stdexcept>
26+ #include < vector>
2727
2828const int kDofPerBody = 6 ;
2929const int kDofLinOrRot = 3 ;
@@ -96,7 +96,7 @@ ForceFunc6d::ForceFunc6d() : forces_{{this, 0}, {this, 1}, {this, 2}, {this, 3},
9696
9797ForceFunc6d::ForceFunc6d (std::shared_ptr<ChBody> object, TestHydro* user_all_forces) : ForceFunc6d() {
9898 body_ = object;
99- std::string temp = body_->GetNameString (); // remove "body" from "bodyN", convert N to int, get body num
99+ std::string temp = body_->GetNameString (); // remove "body" from "bodyN", convert N to int, get body num
100100 b_num_ = stoi (temp.erase (0 , 4 )); // 1 indexed TODO: fix b_num starting here to be 0 indexed
101101 all_hydro_forces_ = user_all_forces; // TODO switch to smart pointers? does this use = ?
102102 if (all_hydro_forces_ == NULL ) {
@@ -166,19 +166,31 @@ TestHydro::TestHydro(std::vector<std::shared_ptr<ChBody>> user_bodies,
166166 : bodies_(user_bodies),
167167 num_bodies_(bodies_.size()),
168168 file_info_(H5FileInfo(h5_file_name, num_bodies_).ReadH5Data()) {
169-
170- prev_time = -1 ;
171- offset_rirf = 0 ;
169+ prev_time = -1 ;
172170
173171 // Set up time vector
174172 rirf_time_vector = file_info_.GetRIRFTimeVector ();
175- rirf_timestep_ = rirf_time_vector[1 ] - rirf_time_vector[0 ];
173+ // width array
174+ rirf_width_vector.resize (rirf_time_vector.size ());
175+ for (int ii = 0 ; ii < rirf_width_vector.size (); ii++) {
176+ rirf_width_vector[ii] = 0.0 ;
177+ if (ii < rirf_time_vector.size () - 1 ) {
178+ rirf_width_vector[ii] += 0.5 * abs (rirf_time_vector[ii + 1 ] - rirf_time_vector[ii]);
179+ }
180+ if (ii > 0 ) {
181+ rirf_width_vector[ii] += 0.5 * abs (rirf_time_vector[ii] - rirf_time_vector[ii - 1 ]);
182+ }
183+ }
176184
177185 // Total degrees of freedom
178186 int total_dofs = kDofPerBody * num_bodies_;
179187
180188 // Initialize vectors
181- velocity_history_.assign (file_info_.GetRIRFDims (2 ) * total_dofs, 0.0 );
189+ time_history_.clear ();
190+ velocity_history_.clear ();
191+ for (int b = 0 ; b < num_bodies_; ++b) {
192+ velocity_history_.push_back (std::vector<std::vector<double >>(0 ));
193+ }
182194 force_hydrostatic_.assign (total_dofs, 0.0 );
183195 force_radiation_damping_.assign (total_dofs, 0.0 );
184196 total_force_.assign (total_dofs, 0.0 );
@@ -238,48 +250,12 @@ void TestHydro::AddWaves(std::shared_ptr<WaveBase> waves) {
238250 user_waves_->Initialize ();
239251}
240252
241- double TestHydro::GetVelHistoryVal (int step, int c) const {
242- if (step < 0 || step >= file_info_.GetRIRFDims (2 ) || c < 0 || c >= num_bodies_ * kDofPerBody ) {
243- std::cout << " wrong vel history index " << std::endl;
244- return 0 ;
245- }
246-
247- int index = c % kDofPerBody ;
248- int b = c / kDofPerBody ; // 0 indexed
249- int calculated_index = index + (kDofPerBody * b) + (kDofPerBody * num_bodies_ * step);
250-
251- if (calculated_index >= num_bodies_ * kDofPerBody * file_info_.GetRIRFDims (2 ) || calculated_index < 0 ) {
252- std::cout << " bad vel history math" << std::endl;
253- return 0 ;
254- }
255-
256- return velocity_history_[calculated_index];
257- }
258-
259- double TestHydro::SetVelHistory (double val, int step, int b_num, int index) {
260- if (step < 0 || step >= file_info_.GetRIRFDims (2 ) || b_num < 1 || b_num > num_bodies_ || index < 0 ||
261- index >= kDofPerBody ) {
262- std::cout << " bad set vel history indexing" << std::endl;
263- return 0 ;
264- }
265-
266- int calculated_index = index + (kDofPerBody * (b_num - 1 )) + (kDofPerBody * num_bodies_ * step);
267-
268- if (calculated_index < 0 || calculated_index >= num_bodies_ * kDofPerBody * file_info_.GetRIRFDims (2 )) {
269- std::cout << " bad set vel history math" << std::endl;
270- return 0 ;
271- }
272-
273- velocity_history_[calculated_index] = val;
274- return val;
275- }
276-
277253std::vector<double > TestHydro::ComputeForceHydrostatics () {
278254 assert (num_bodies_ > 0 );
279255
280- const double rho = file_info_.GetRhoVal ();
281- const auto g_acc = bodies_[0 ]->GetSystem ()->Get_G_acc (); // assuming all bodies in same system
282- const double gg = g_acc.Length ();
256+ const double rho = file_info_.GetRhoVal ();
257+ const auto g_acc = bodies_[0 ]->GetSystem ()->Get_G_acc (); // assuming all bodies in same system
258+ const double gg = g_acc.Length ();
283259
284260 for (int b = 0 ; b < num_bodies_; b++) {
285261 std::shared_ptr<chrono::ChBody> body = bodies_[b];
@@ -294,7 +270,7 @@ std::vector<double> TestHydro::ComputeForceHydrostatics() {
294270
295271 chrono::ChVectorN<double , kDofPerBody > body_displacement;
296272 for (int ii = 0 ; ii < kDofLinOrRot ; ii++) {
297- body_displacement[ii] = body_position[ii] - body_equilibrium[ii];
273+ body_displacement[ii] = body_position[ii] - body_equilibrium[ii];
298274 body_displacement[ii + kDofLinOrRot ] = body_rotation[ii] - body_equilibrium[ii + kDofLinOrRot ];
299275 }
300276
@@ -328,69 +304,92 @@ std::vector<double> TestHydro::ComputeForceRadiationDampingConv() {
328304 const int numRows = kDofPerBody * num_bodies_;
329305 const int numCols = kDofPerBody * num_bodies_;
330306
331- // "Shift" everything left 1
332- offset_rirf--; // Starts as 0 before timestep change
333-
334- // Keep offset close to 0, avoids small chance of overflow errors in long simulations
335- if (offset_rirf < -1 * size) {
336- offset_rirf += size;
337- }
338-
339307 assert (numRows * size > 0 && numCols > 0 );
340308
341- std::vector<double > timeseries (numRows * numCols * size, 0.0 );
342- std::vector<double > tmp_s (numRows * size, 0.0 );
343-
344- // Helper function for timeseries indexing
345- auto TimeseriesIndex = [&](int row, int col, int step) { return (row * numCols * size) + (col * size) + step; };
309+ // time history
310+ auto t_sim = bodies_[0 ]->GetChTime ();
311+ auto t_min = t_sim - rirf_time_vector.tail <1 >()[0 ];
312+ if (time_history_.size () > 0 && t_sim == time_history_.front ()) {
313+ throw std::runtime_error (" Tried to compute the radiation damping convolution twice within the same time step!" );
314+ }
315+ time_history_.insert (time_history_.begin (), t_sim);
346316
347- // Helper function for tmp_s indexing
348- auto TmpSIndex = [&](int row, int step) { return (row * size) + step; };
317+ // velocity history
318+ for (int b = 0 ; b < num_bodies_; b++) {
319+ auto & body = bodies_[b];
320+ auto & velocity_history_body = velocity_history_[b];
349321
350- // Helper function for circular indexing
351- auto CircularIndex = [&](int value) { return ((value % size) + size) % size; };
322+ auto vel = body->GetPos_dt ();
323+ auto wvel = body->GetWvel_par ();
324+ std::vector<double > vel_vec = {vel[0 ], vel[1 ], vel[2 ], wvel[0 ], wvel[1 ], wvel[2 ]};
325+ velocity_history_body.insert (velocity_history_body.begin (), vel_vec);
326+ }
352327
353- // Set last entry as velocity
354- for (int i = 0 ; i < 3 ; i++) {
355- for (int b = 1 ; b <= num_bodies_; b++) {
356- int vi = CircularIndex (size + offset_rirf);
357- SetVelHistory (bodies_[b - 1 ]->GetPos_dt ()[i], vi, b, i);
358- SetVelHistory (bodies_[b - 1 ]->GetWvel_par ()[i], vi, b, i + 3 );
328+ // remove unnecessary history
329+ if (time_history_.size () > 1 ) {
330+ while (time_history_[time_history_.size () - 2 ] < t_min) {
331+ time_history_.pop_back ();
332+ for (int b = 0 ; b < num_bodies_; b++) {
333+ auto & velocity_history_body = velocity_history_[b];
334+ velocity_history_body.pop_back ();
335+ }
359336 }
360337 }
361338
362- if (convTrapz_) {
363- for (int row = 0 ; row < numRows; row++) {
364- for (int st = 0 ; st < size; st++) {
365- int vi = CircularIndex (st + offset_rirf);
366- tmp_s[TmpSIndex (row, st)] = 0 ;
367- for (int col = 0 ; col < numCols; col++) {
368- timeseries[TimeseriesIndex (row, col, st)] = GetRIRFval (row, col, st) * GetVelHistoryVal (vi, col);
369- tmp_s[TmpSIndex (row, st)] += timeseries[TimeseriesIndex (row, col, st)];
339+ if (time_history_.size () > 1 ) {
340+ int idx_history = 0 ;
341+
342+ // iterate over RIRF steps
343+ for (int step = 0 ; step < size; step++) {
344+ auto t_rirf = t_sim - rirf_time_vector[step];
345+ while (time_history_[idx_history + 1 ] > t_rirf && idx_history < time_history_.size () - 1 ) {
346+ idx_history += 1 ;
347+ }
348+ if (idx_history >= time_history_.size () - 1 ) {
349+ break ;
350+ }
351+
352+ // iterate over bodies
353+ for (int idx_body = 0 ; idx_body < num_bodies_; idx_body++) {
354+ auto & velocity_history_body = velocity_history_[idx_body];
355+ std::vector<double > vel (kDofPerBody );
356+
357+ // interpolate velocity at t_rirf from recorded velocity history
358+ // time values
359+ auto t1 = time_history_[idx_history + 1 ];
360+ auto t2 = time_history_[idx_history];
361+ if (t_rirf == t1) {
362+ vel = velocity_history_body[idx_history + 1 ];
363+ } else if (t_rirf == t2) {
364+ vel = velocity_history_body[idx_history];
365+ } else if (t_rirf > t1 && t_rirf < t2) {
366+ // weights
367+ auto w1 = (t2 - t_rirf) / (t2 - t1);
368+ auto w2 = 1.0 - w1;
369+ // velocity values
370+ auto vel1 = velocity_history_body[idx_history + 1 ];
371+ auto vel2 = velocity_history_body[idx_history];
372+ for (int dof = 0 ; dof < kDofPerBody ; dof++) {
373+ vel[dof] = w1 * vel1[dof] + w2 * vel2[dof];
374+ }
375+ } else {
376+ throw std::runtime_error (" Radiation convolution: wrong interpolation: " + std::to_string (t_rirf) +
377+ " not between " + std::to_string (t1) + " and " + std::to_string (t2) + " ." );
370378 }
371- if (st > 0 ) {
372- // Integrate tmp_s
373- force_radiation_damping_[row] += (tmp_s[TmpSIndex (row, st - 1 )] + tmp_s[TmpSIndex (row, st)]) / 2.0 *
374- (rirf_time_vector[st] - rirf_time_vector[st - 1 ]);
379+
380+ for (int dof = 0 ; dof < kDofPerBody ; dof++) {
381+ // get column index
382+ int col = dof + idx_body * kDofPerBody ;
383+
384+ // iterate over rows
385+ for (int row = 0 ; row < numRows; row++) {
386+ force_radiation_damping_[row] +=
387+ GetRIRFval (row, col, step) * vel[dof] * rirf_width_vector[step];
388+ }
375389 }
376390 }
377391 }
378392 }
379- // else {
380- // // Convolution integral assuming fixed dt
381- // for (int row = 0; row < numRows; row++) {
382- // double sumVelHistoryAndRIRF = 0.0;
383- // for (int col = 0; col < numCols; col++) {
384- // for (int st = 0; st < size; st++) {
385- // int vi = CircularIndex(st + offset_rirf);
386- // timeseries[TimeseriesIndex(row, col, st)] = GetRIRFval(row, col, st) * GetVelHistoryVal(vi, col);
387- // sumVelHistoryAndRIRF += timeseries[TimeseriesIndex(row, col, st)];
388- // }
389- // }
390- // force_radiation_damping_[row] -= sumVelHistoryAndRIRF * rirf_timestep;
391- // }
392- // }
393-
394393 return force_radiation_damping_;
395394}
396395
@@ -450,8 +449,6 @@ double TestHydro::CoordinateFuncForBody(int b, int dof_index) {
450449 std::fill (force_radiation_damping_.begin (), force_radiation_damping_.end (), 0.0 );
451450 std::fill (force_waves_.begin (), force_waves_.end (), 0.0 );
452451
453- // Compute forces using the trapezoidal rule (or other methods in the future)
454- convTrapz_ = true ;
455452 force_hydrostatic_ = ComputeForceHydrostatics ();
456453 force_radiation_damping_ = ComputeForceRadiationDampingConv ();
457454 force_waves_ = ComputeForceWaves ();
0 commit comments