@@ -254,142 +254,187 @@ std::vector<double> TestHydro::ComputeForceHydrostatics() {
254254 assert (num_bodies_ > 0 );
255255
256256 const double rho = file_info_.GetRhoVal ();
257- const auto g_acc = bodies_[0 ]->GetSystem ()->GetGravitationalAcceleration (); // assuming all bodies in same system
258- const double gg = g_acc .Length ();
257+ const auto gravitational_acceleration = bodies_[0 ]->GetSystem ()->GetGravitationalAcceleration (); // same system for all bodies
258+ const double rho_times_g = rho * gravitational_acceleration .Length ();
259259
260- for (int b = 0 ; b < num_bodies_; b++) {
261- std::shared_ptr<chrono::ChBody> body = bodies_[b];
262-
263- int b_offset = kDofPerBody * b;
264- double * body_force_hydrostatic = &force_hydrostatic_[b_offset];
265- double * body_equilibrium = &equilibrium_[b_offset];
266-
267- // hydrostatic stiffness due to offset from equilibrium
268- const auto body_position = body->GetPos ();
269- const auto body_rotation = body->GetRot ().GetCardanAnglesXYZ ();
270-
271- chrono::ChVectorN<double , kDofPerBody > body_displacement;
272- for (int ii = 0 ; ii < kDofLinOrRot ; ii++) {
273- body_displacement[ii] = body_position[ii] - body_equilibrium[ii];
274- body_displacement[ii + kDofLinOrRot ] = body_rotation[ii] - body_equilibrium[ii + kDofLinOrRot ];
275- }
276-
277- const auto force_offset = -gg * rho * file_info_.GetLinMatrix (b) * body_displacement;
278- for (int dof = 0 ; dof < kDofPerBody ; dof++) {
279- body_force_hydrostatic[dof] += force_offset[dof];
280- }
281-
282- // buoyancy at equilibrium
283- const auto buoyancy = rho * (-g_acc) * file_info_.GetDispVolVal (b);
284-
285- for (int ii = 0 ; ii < kDofLinOrRot ; ii++) {
286- body_force_hydrostatic[ii] += buoyancy[ii];
260+ for (int b = 0 ; b < num_bodies_; ++b) {
261+ const auto & body = bodies_[b];
262+
263+ const int body_offset = kDofPerBody * b;
264+ double * const body_force_hydrostatic = &force_hydrostatic_[body_offset];
265+ const double * const body_equilibrium = &equilibrium_[body_offset];
266+
267+ // Current pose
268+ const chrono::ChVector3d position_world = body->GetPos ();
269+ const chrono::ChVector3d rotation_rpy = body->GetRot ().GetCardanAnglesXYZ ();
270+
271+ // 6-DOF displacement from equilibrium (translation xyz, rotation rpy)
272+ Eigen::Matrix<double , kDofPerBody , 1 > displacement_from_equilibrium;
273+ displacement_from_equilibrium[0 ] = position_world.x () - body_equilibrium[0 ];
274+ displacement_from_equilibrium[1 ] = position_world.y () - body_equilibrium[1 ];
275+ displacement_from_equilibrium[2 ] = position_world.z () - body_equilibrium[2 ];
276+ displacement_from_equilibrium[3 ] = rotation_rpy.x () - body_equilibrium[3 ];
277+ displacement_from_equilibrium[4 ] = rotation_rpy.y () - body_equilibrium[4 ];
278+ displacement_from_equilibrium[5 ] = rotation_rpy.z () - body_equilibrium[5 ];
279+
280+ // Linear hydrostatic restoring force/torque
281+ const Eigen::MatrixXd restoring_stiffness_matrix = file_info_.GetLinMatrix (b);
282+ const Eigen::Matrix<double , kDofPerBody , 1 > restoring_force_torque =
283+ -rho_times_g * (restoring_stiffness_matrix * displacement_from_equilibrium);
284+ for (int i = 0 ; i < kDofPerBody ; ++i) {
285+ body_force_hydrostatic[i] += restoring_force_torque[i];
287286 }
288287
289- int r_offset = kDofLinOrRot * b;
290- const auto cg2cb =
291- chrono::ChVector3d (cb_minus_cg_[r_offset], cb_minus_cg_[r_offset + 1 ], cb_minus_cg_[r_offset + 2 ]);
292- const auto buoyancy2 = cg2cb % buoyancy;
293-
294- for (int ii = 0 ; ii < kDofLinOrRot ; ii++) {
295- body_force_hydrostatic[ii + kDofLinOrRot ] += buoyancy2[ii];
296- }
288+ // Buoyancy force at equilibrium: F = rho * (-g) * displaced_volume
289+ const double displaced_volume = file_info_.GetDispVolVal (b);
290+ const chrono::ChVector3d buoyancy_force = rho * (-gravitational_acceleration) * displaced_volume;
291+ body_force_hydrostatic[0 ] += buoyancy_force.x ();
292+ body_force_hydrostatic[1 ] += buoyancy_force.y ();
293+ body_force_hydrostatic[2 ] += buoyancy_force.z ();
294+
295+ // Buoyancy-induced moment about CG: (r_CB - r_CG) x buoyancy
296+ const int rotation_offset = kDofLinOrRot * b;
297+ const chrono::ChVector3d cg_to_cb (
298+ cb_minus_cg_[rotation_offset + 0 ],
299+ cb_minus_cg_[rotation_offset + 1 ],
300+ cb_minus_cg_[rotation_offset + 2 ]
301+ );
302+ const chrono::ChVector3d buoyancy_torque = cg_to_cb % buoyancy_force;
303+ body_force_hydrostatic[3 ] += buoyancy_torque.x ();
304+ body_force_hydrostatic[4 ] += buoyancy_torque.y ();
305+ body_force_hydrostatic[5 ] += buoyancy_torque.z ();
297306 }
298307
299308 return force_hydrostatic_;
300309}
301310
302311std::vector<double > TestHydro::ComputeForceRadiationDampingConv () {
303- const int size = file_info_.GetRIRFDims (2 );
304- const int numRows = kDofPerBody * num_bodies_;
305- const int numCols = kDofPerBody * num_bodies_;
312+ const int rirf_steps = file_info_.GetRIRFDims (2 );
313+ const int total_dofs = kDofPerBody * num_bodies_;
306314
307- assert (numRows * size > 0 && numCols > 0 );
315+ assert (total_dofs > 0 && rirf_steps > 0 );
308316
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 ()) {
317+ // Current time and minimum history time window required
318+ const double simulation_time = bodies_[0 ]->GetChTime ();
319+ const int rirf_last_index = static_cast <int >(rirf_time_vector.size ()) - 1 ;
320+ const double history_min_time = simulation_time - (rirf_last_index >= 0 ? rirf_time_vector[rirf_last_index] : 0.0 );
321+
322+ // Prevent duplicate computation within same step
323+ if (!time_history_.empty () && simulation_time == time_history_.front ()) {
313324 throw std::runtime_error (" Tried to compute the radiation damping convolution twice within the same time step!" );
314325 }
315- time_history_.insert (time_history_.begin (), t_sim);
316326
317- // velocity history
318- for (int b = 0 ; b < num_bodies_; b++) {
319- auto & body = bodies_[b];
327+ // Record current time at the front (most recent first)
328+ time_history_.insert (time_history_.begin (), simulation_time);
329+
330+ // Record current velocities per body at the front (matching time_history_ ordering)
331+ for (int b = 0 ; b < num_bodies_; ++b) {
332+ auto & body = bodies_[b];
320333 auto & velocity_history_body = velocity_history_[b];
321334
322- auto vel = body->GetPosDt ();
323- auto wvel = body->GetAngVelParent ();
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);
335+ const auto linear_velocity_world = body->GetPosDt ();
336+ const auto angular_velocity_world = body->GetAngVelParent ();
337+ std::vector<double > velocity_dof_vector = {
338+ linear_velocity_world[0 ], linear_velocity_world[1 ], linear_velocity_world[2 ],
339+ angular_velocity_world[0 ], angular_velocity_world[1 ], angular_velocity_world[2 ]
340+ };
341+ velocity_history_body.insert (velocity_history_body.begin (), std::move (velocity_dof_vector));
326342 }
327343
328- // remove unnecessary history
344+ // Prune history older than the max RIRF time span
329345 if (time_history_.size () > 1 ) {
330- while (time_history_[time_history_.size () - 2 ] < t_min ) {
346+ while (time_history_. size () > 1 && time_history_ [time_history_.size () - 2 ] < history_min_time ) {
331347 time_history_.pop_back ();
332- for (int b = 0 ; b < num_bodies_; b++ ) {
348+ for (int b = 0 ; b < num_bodies_; ++b ) {
333349 auto & velocity_history_body = velocity_history_[b];
334- velocity_history_body.pop_back ();
350+ if (!velocity_history_body.empty ()) {
351+ velocity_history_body.pop_back ();
352+ }
335353 }
336354 }
337355 }
338356
339- if (time_history_.size () > 1 ) {
340- int idx_history = 0 ;
357+ // Nothing to convolve with if we don't yet have at least 2 time points
358+ if (time_history_.size () <= 1 ) {
359+ return force_radiation_damping_;
360+ }
361+
362+ // Walk through RIRF steps and accumulate convolution
363+ size_t history_index = 0 ; // index into descending time_history_ (front is most recent)
364+ for (int step = 0 ; step < rirf_steps; ++step) {
365+ const double rirf_query_time = simulation_time - rirf_time_vector[step];
366+
367+ // Advance history_index until [history_index, history_index+1] brackets rirf_query_time, or we run out
368+ while ((history_index + 1 ) < time_history_.size () && time_history_[history_index + 1 ] > rirf_query_time) {
369+ ++history_index;
370+ }
371+ if ((history_index + 1 ) >= time_history_.size ()) {
372+ break ; // not enough older history to interpolate
373+ }
341374
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 ;
375+ const double newer_time = time_history_[history_index];
376+ const double older_time = time_history_[history_index + 1 ];
377+
378+ // For each body, interpolate 6-DOF velocity at rirf_query_time and apply convolution
379+ for (int body_index = 0 ; body_index < num_bodies_; ++body_index) {
380+ auto & velocity_history_body = velocity_history_[body_index];
381+
382+ // Ensure history is consistent across bodies
383+ if (velocity_history_body.size () <= history_index) {
384+ continue ; // skip if inconsistent; should not happen in normal flow
347385 }
348- if (idx_history >= time_history_.size () - 1 ) {
349- break ;
386+
387+ // Interpolate velocities
388+ double interpolated_velocity_dof[kDofPerBody ];
389+ if (rirf_query_time == older_time) {
390+ const auto & older_velocity = velocity_history_body[history_index + 1 ];
391+ interpolated_velocity_dof[0 ] = older_velocity[0 ];
392+ interpolated_velocity_dof[1 ] = older_velocity[1 ];
393+ interpolated_velocity_dof[2 ] = older_velocity[2 ];
394+ interpolated_velocity_dof[3 ] = older_velocity[3 ];
395+ interpolated_velocity_dof[4 ] = older_velocity[4 ];
396+ interpolated_velocity_dof[5 ] = older_velocity[5 ];
397+ } else if (rirf_query_time == newer_time) {
398+ const auto & newer_velocity = velocity_history_body[history_index];
399+ interpolated_velocity_dof[0 ] = newer_velocity[0 ];
400+ interpolated_velocity_dof[1 ] = newer_velocity[1 ];
401+ interpolated_velocity_dof[2 ] = newer_velocity[2 ];
402+ interpolated_velocity_dof[3 ] = newer_velocity[3 ];
403+ interpolated_velocity_dof[4 ] = newer_velocity[4 ];
404+ interpolated_velocity_dof[5 ] = newer_velocity[5 ];
405+ } else if (rirf_query_time > older_time && rirf_query_time < newer_time) {
406+ const double time_delta = (newer_time - older_time);
407+ const double weight_older = (time_delta != 0.0 ) ? ((newer_time - rirf_query_time) / time_delta) : 0.0 ;
408+ const double weight_newer = 1.0 - weight_older;
409+ const auto & older_velocity = velocity_history_body[history_index + 1 ];
410+ const auto & newer_velocity = velocity_history_body[history_index];
411+ interpolated_velocity_dof[0 ] = weight_older * older_velocity[0 ] + weight_newer * newer_velocity[0 ];
412+ interpolated_velocity_dof[1 ] = weight_older * older_velocity[1 ] + weight_newer * newer_velocity[1 ];
413+ interpolated_velocity_dof[2 ] = weight_older * older_velocity[2 ] + weight_newer * newer_velocity[2 ];
414+ interpolated_velocity_dof[3 ] = weight_older * older_velocity[3 ] + weight_newer * newer_velocity[3 ];
415+ interpolated_velocity_dof[4 ] = weight_older * older_velocity[4 ] + weight_newer * newer_velocity[4 ];
416+ interpolated_velocity_dof[5 ] = weight_older * older_velocity[5 ] + weight_newer * newer_velocity[5 ];
417+ } else {
418+ throw std::runtime_error (
419+ " Radiation convolution: interpolation error; rirf_query_time not bracketed by adjacent history." );
350420 }
351421
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) + " ." );
422+ // Apply convolution: for each DOF column, add RIRF[:, col, step] * vel[dof] * width
423+ const double step_width = rirf_width_vector[step];
424+ const int body_col_offset = body_index * kDofPerBody ;
425+ for (int dof = 0 ; dof < kDofPerBody ; ++dof) {
426+ const int col = body_col_offset + dof;
427+ const double contribution_scale = interpolated_velocity_dof[dof] * step_width;
428+ if (contribution_scale == 0.0 ) {
429+ continue ;
378430 }
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- }
431+ for (int row = 0 ; row < total_dofs; ++row) {
432+ force_radiation_damping_[row] += GetRIRFval (row, col, step) * contribution_scale;
389433 }
390434 }
391435 }
392436 }
437+
393438 return force_radiation_damping_;
394439}
395440
0 commit comments