Virtual Testbed
Ship dynamics simulator for extreme conditions
core/testbed.cc
1 #include <cstring>
2 #include <fstream>
3 #include <iostream>
4 #include <limits>
5 
6 #include <vtestbed/config/opencl.hh>
7 #include <vtestbed/config/openmp.hh>
8 #include <vtestbed/config/real_type.hh>
9 #include <vtestbed/core/anlt_wind_solver.hh>
10 #include <vtestbed/core/arma_wind_solver.hh>
11 #include <vtestbed/core/cosine_wave.hh>
12 #include <vtestbed/core/propulsor.hh>
13 #include <vtestbed/core/ship_motion_solver.hh>
14 #include <vtestbed/core/stokes_wave.hh>
15 #include <vtestbed/core/testbed.hh>
16 #include <vtestbed/core/wetted_surface_solver.hh>
17 #include <vtestbed/geometry/basis.hh>
18 #include <vtestbed/profile/profile.hh>
19 
20 #if defined(VTB_WITH_OPENCL)
21 #include <vtestbed/opencl/opencl.hh>
22 #endif
23 
24 static_assert(
26  sizeof(vtb::core::Vector3<VTB_REAL_TYPE>)*4,
27  "bad size"
28 );
29 
30 template <class T, int N>
32 _grid_txyz{
33  {T{-1}, T(-100), T(-100), T{-100}},
34  {T{0}, T(100), T(100), T{2}},
35  {3, 128, 128, 64} // we need three points for zeta time derivative
36 },
37 _wind_grid{
38  {-100/2,-100/2,0},
39  {100/2,100/2,25},
40  {40,40,10}
41 } {
42  this->_wpdomain_xyz.lbound() = 0;
43  this->_wpdomain_xyz.ubound() = 0;
44  grid3 wsgrid{this->wavy_surface_grid()};
45  this->_wavysurface.resize(wsgrid.shape());
46  this->_wavysurface = 0;
47  this->_irregular_wavysurface.resize(wsgrid.shape());
48  parallel_for_loop<N>(
49  wsgrid.shape(),
50  [&] (const blitz::TinyVector<int,N>& idx) {
51  auto txy = wsgrid(idx);
52  this->_irregular_wavysurface(idx) = {txy(1), txy(2), 0};
53  }
54  );
55  grid4 vpgrid{this->_grid_txyz.select(0,3,1,2)};
56  this->_vpotential.resize(vpgrid.shape());
57  this->_statistics_log.open("statistics.log");
58  this->_statistics.write_header(this->_statistics_log);
59  //this->_arma_wind_solver.reset(new arma_wind_solver_type);
60  //this->_arma_wind_solver->initialize();
61  this->_ship_motion_solver.reset(new ship_motion_solver_type);
62 }
63 
64 template <class T, int N>
65 void
67  VTB_PROFILE_BLOCK("step");
68  const T t0 = this->_grid_txyz.ubound(0);
69  this->_grid_txyz.lbound(0) = t0;
70  this->_grid_txyz.ubound(0) = t0 + dt;
71  switch (this->get_solver_type()) {
72  case Solver_type::regular_solver: this->step_regular(); break;
73  case Solver_type::gerstner_solver: this->step_irregular(); break;
74  }
75  /*
76  std::ofstream out("waterline");
77  waterline().gnuplot(out);
78  */
79  //TODO:
80  //this->_arma_wind_solver->step(this->_wssolver->dry_panels());
81  //this->_wind_field.reference(this->_arma_wind_solver->wind_field());
82  this->compute_wind();
83  this->move_ship();
84  this->record_statistics(this->_statistics);
85 }
86 
87 template <class T, int N>
88 void
90  this->generate_waves();
91  this->compute_wetted_panels_regular();
92  if (has_wetted_panels()) {
93  this->clamp_grid_to_wetted_panels();
94  if (has_wave_pressure_domain()) {
95  this->compute_wave_numbers();
96  this->compute_velocity_potential();
97  this->compute_wave_pressure();
98  }
99  }
100 }
101 
102 template <class T, int N>
103 void
105  {
106  VTB_PROFILE_BLOCK("fluid_motion");
107  this->_gerstner_solver->compute_positions(this->_ship, this->_wssolver->all_panels(),
108  this->_grid_txyz.select(0,1,2), this->_irregular_wavysurface);
109  }
110  this->compute_wetted_panels_irregular();
111  if (has_wetted_panels()) {
112  this->clamp_grid_to_wetted_panels();
113  if (has_wave_pressure_domain()) {
114  VTB_PROFILE_BLOCK("compute_forces");
115  // TODO implement for irregular wavy surface
116  //this->compute_wave_numbers();
117  this->_gerstner_solver->compute_forces(
118  this->_ship,
119  this->_grid_txyz.select(0,3,1,2),
120  this->_wssolver->wetted_panels());
121  this->_water_velocity.reference(this->_gerstner_solver->velocity());
122  }
123  }
124 }
125 
126 template <class T, int N>
127 void
129  this->_grid_txyz.lbound(0) = -1;
130  this->_grid_txyz.ubound(0) = 0;
131  this->_ship.reset();
132  this->_statistics.clear();
133  this->_statistics_log.close();
134  this->_statistics_log.open("statistics.log");
135  this->_wavysurface = 0;
136  this->_vpotential = 0;
137  this->_wind_field = T{};
138  this->_irregular_wavysurface = T{};
139 }
140 
141 template <class T, int N>
142 void
144  VTB_PROFILE_BLOCK("waves");
145  grid3 wsgrid{this->wavy_surface_grid()};
146  this->_wavysurface.reference(this->_wsgenerator->generate(wsgrid));
147 }
148 
149 template <class T, int N>
150 void
152  VTB_PROFILE_BLOCK("wind");
153  this->_anlt_wind_solver->step(this->_wind_grid, this->_wssolver->dry_panels());
154  this->_wind_field.reference(this->_anlt_wind_solver->wind_field());
155 }
156 
157 template <class T, int N>
158 void
160  VTB_PROFILE_BLOCK("wetted_panels");
161  this->_wssolver->solve(ship(), grid_txyz(), this->wavy_surface());
162 }
163 
164 template <class T, int N>
165 void
167  VTB_PROFILE_BLOCK("wetted_panels");
168  this->_wssolver->solve(ship(), grid_txyz(), this->irregular_wavy_surface());
169 }
170 
171 template <class T, int N>
172 void
174  using vtb::base::MinMax;
175  const auto& wetted_panels = this->_wssolver->wetted_panels();
176  MinMax<T> mm[3];
177  for (const auto& panel : wetted_panels) {
178  const auto& centre = panel.centre();
179  mm[0].update(centre(0));
180  mm[1].update(centre(1));
181  mm[2].update(centre(2));
182  }
183  vec3 x_min{mm[0].min(),mm[1].min(),mm[2].min()};
184  vec3 x_max{mm[0].max(),mm[1].max(),mm[2].max()};
185  // set Z dimension to the wetted panels Z range
186  if (!wetted_panels.empty()) {
187  T z_max = std::min(x_max(2), blitz::max(this->_wavysurface)) + 1;
188  //T z_max = std::min(x_max(2), blitz::max(this->_wavysurface)) + 1;
189  this->_grid_txyz.ubound(3) = z_max;
190  this->_grid_txyz.lbound(3) = std::min(x_min(2)-1, z_max);
191  }
192  grid3 grid_xyz{this->_grid_txyz.select(1,2,3)};
193  x_min = clamp(x_min, grid_xyz);
194  x_max = clamp(x_max, grid_xyz);
195  int3 idx_min = int3{blitz::floor(grid_xyz.index(x_min))};
196  int3 idx_max = int3{blitz::ceil(grid_xyz.index(x_max))};
197  idx_min = blitz::max(0, idx_min);
198  idx_max = blitz::min(grid_xyz.shape()-1, idx_max);
199  // Make X and Y extent a power of 2. Do not touch Z dimension.
200  int3 extent = idx_max - idx_min + 1;
201  if (blitz::all(extent > 0)) {
202  for (int i=0; i<2; ++i) {
203  int e = extent(i);
204  if (!blitz::is_power_of_two(e)) {
205  extent(i) = blitz::next_power_of_two(e);
206  }
207  }
208  idx_max = idx_min + extent - 1;
209  for (int i=0; i<2; ++i) {
210  int diff = idx_max(i) - (grid_xyz.extent(i) - 1);
211  if (diff > 0) {
212  idx_min(i) -= diff;
213  idx_max(i) -= diff;
214  }
215  }
216  if (blitz::any(idx_min < 0)) {
217  std::clog
218  << "Please, increase wavy surface size to speed-up Fourier transforms"
219  << std::endl;
220  }
221  extent = idx_max - idx_min + 1;
222  }
223  domain3 d{idx_min, idx_max};
224  this->_wpdomain_xyz = d;
225 }
226 
227 template <class T, int N>
228 void
230  const auto& _ = blitz::Range::all();
231  const auto& grid_xy = this->_grid_txyz.select(1,2);
232  const auto& zeta = this->_wavysurface;
233  const int slice_t = zeta.extent(0)-1;
234  const auto& w = wave_statistics(zeta(slice_t,_,_), grid_xy);
235  auto& waves = this->_statistics.waves();
236  waves(1) = w(0);
237  waves(2) = w(1);
238 }
239 
240 template <class T, int N>
241 auto
243  return wave_number_grid(this->_statistics.waves()).select(1,2);
244 }
245 
246 template <class T, int N>
247 void
249  VTB_PROFILE_BLOCK("wave_velocity");
250  const auto _ = blitz::Range::all();
251  _vpgrid_tzxy = _grid_txyz.select(0,3,1,2);
252  _vpgrid_tzxy = _vpgrid_tzxy(_,_wpdomain_xyz[2],_wpdomain_xyz[0],_wpdomain_xyz[1]);
253  _vpotential.resize(_vpgrid_tzxy.shape());
254  _vpsolver->wave_number_grid(this->wave_number_grid_2d());
255  _vpsolver->solve(
256  _vpgrid_tzxy,
257  _wavysurface(_,_wpdomain_xyz[0],_wpdomain_xyz[1]),
258  _vpotential
259  );
260 }
261 
262 template <class T, int N>
263 void
265  VTB_PROFILE_BLOCK("wave_pressure");
266  grid3 wsgrid{_vpgrid_tzxy.select(0,2,3)};
267  this->_wpsolver->solve(
268  wsgrid,
269  this->_wavysurface,
270  _vpgrid_tzxy,
271  this->_vpotential,
272  this->_wssolver->wetted_panels()
273  );
274 }
275 
276 template <class T, int N>
277 void
279  VTB_PROFILE_BLOCK("ship_motions");
280  const T t0 = this->_grid_txyz.lbound(0);
281  const T t1 = this->_grid_txyz.ubound(0);
282  this->_ship_motion_solver->solve(
283  this->_ship,
284  this->wetted_panels(),
285  this->dry_panels(),
286  this->waterline(),
287  t0,
288  t1
289  );
290 }
291 
292 template <class T, int N>
293 void
294 vtb::core::Testbed<T,N>::record_statistics(statistics_type& stats) {
295  using Record = typename statistics_type::Record;
296  VTB_PROFILE_BLOCK("statistics");
297  T t = this->_grid_txyz.ubound(0);
298  const auto& ship = this->_ship;
299  stats.record(Record::Time, t);
300  stats.record(Record::Euler_angles, ship.euler_angles());
301  stats.record(Record::Position, ship.position());
302  stats.record(Record::Velocity, ship.velocity());
303  stats.record(Record::Angular_velocity, vector_to(ship.rotation_matrix(), ship.angular_velocity()));
304  stats.record(Record::Acceleration, vector_to(ship.rotation_matrix(), ship.acceleration()));
305  stats.record(Record::Angular_acceleration, ship.angular_acceleration());
306  stats.record(Record::Underwater_volume,
307  this->_ship_motion_solver->equation().displacement());
308  stats.record(Record::Angular_momentum, ship.angular_momentum());
309  const auto& zeta = this->_wavysurface;
310  const auto nx = zeta.extent(1);
311  const auto ny = zeta.extent(2);
312  stats.record(Record::Wavy_surface, zeta(zeta.extent(0)-1,nx/2,ny/2));
313  stats.record_waves();
314  stats.write_back(this->_statistics_log);
315  this->_statistics_log.flush();
316 }
317 
318 template <class T, int N>
319 void
321  #if defined(VTB_WITH_OPENMP)
322  auto solver_t = get_solver_type();
323  this->velocity_potential_solver(make_velocity_potential_solver<T,3,Policy::OpenMP>());
324  this->wave_pressure_solver(make_wave_pressure_solver<T,Policy::OpenMP>());
325  this->wetted_surface_solver(make_wetted_surface_solver<T,3,Policy::OpenMP>());
326  this->anlt_wind_solver(make_anlt_wind_solver<T,Policy::OpenMP>());
327  using default_wave = Propagating_stokes_wave<T,3>;
328  this->wavy_surface_generator(
329  make_plain_wave_generator<T,3,default_wave,Policy::OpenMP>()
330  );
331  this->gerstner_solver(make_gerstner_solver<T,3,Policy::OpenMP>());
332  set_solver_type(solver_t);
333  #endif
334 }
335 
336 template <class T, int N>
337 void
339  #if defined(VTB_WITH_OPENCL)
340  auto solver_t = get_solver_type();
341  this->velocity_potential_solver(make_velocity_potential_solver<T,3,Policy::OpenCL>());
342  this->wave_pressure_solver(make_wave_pressure_solver<T,Policy::OpenCL>());
343  this->wetted_surface_solver(make_wetted_surface_solver<T,3,Policy::OpenCL>());
344  this->anlt_wind_solver(make_anlt_wind_solver<T,Policy::OpenCL>());
345  using default_wave = Propagating_stokes_wave<T,3>;
346  this->wavy_surface_generator(
347  make_plain_wave_generator<T,3,default_wave,Policy::OpenCL>()
348  );
349  this->gerstner_solver(make_gerstner_solver<T,3,Policy::OpenCL>());
350  set_solver_type(solver_t);
351  #endif
352 }
353 
354 template <class T, int N>
355 void
357  #if defined(VTB_WITH_OPENCL)
358  using namespace vtb::opencl;
359  auto context = reinterpret_cast<Context*>(ptr);
360  if (auto vpsolver = dynamic_cast<Context_base*>(this->_vpsolver.get())) {
361  vpsolver->context(context);
362  }
363  if (auto wpsolver = dynamic_cast<Context_base*>(this->_wpsolver.get())) {
364  wpsolver->context(context);
365  }
366  if (auto wssolver = dynamic_cast<Context_base*>(this->_wssolver.get())) {
367  wssolver->context(context);
368  }
369  if (auto wsgenerator = dynamic_cast<Context_base*>(this->_wsgenerator.get())) {
370  wsgenerator->context(context);
371  }
372  if (auto gerstner_solver = dynamic_cast<Context_base*>(this->_gerstner_solver.get())) {
373  gerstner_solver->context(context);
374  }
375  if (auto wind_solver = dynamic_cast<Context_base*>(this->_anlt_wind_solver.get())) {
376  wind_solver->context(context);
377  }
378  #endif
379 }
380 
Triangular ship hull panel (face).
OpenCL glue code.
Main class for interacting with virtual testbed.
Definition: testbed.hh:33
void reset()
Reset simulation to the initial state and retain solver configuration.