Virtual Testbed
Ship dynamics simulator for extreme conditions
wetted_surface_solver_openmp.cc
1 #include <vtestbed/config/openmp.hh>
2 #include <vtestbed/config/real_type.hh>
3 #include <vtestbed/core/bisection.hh>
4 #include <vtestbed/core/grid_interpolation.hh>
5 #include <vtestbed/core/policy.hh>
6 #include <vtestbed/core/ship.hh>
7 #include <vtestbed/core/ship_hull_panel.hh>
8 #include <vtestbed/core/wetted_surface_solver.hh>
9 #include <vtestbed/geometry/basis.hh>
10 #include <vtestbed/geometry/tetrahedron.hh>
11 #include <vtestbed/geometry/triangle.hh>
12 #include <vtestbed/profile/profile.hh>
13 
14 //#define VTB_DEBUG_TRIANGLES
15 
16 #if defined(VTB_DEBUG_TRIANGLES)
17 #include <iostream>
18 #include <vtestbed/core/debug.hh>
19 #endif
20 
21 namespace vtb {
22 
23  namespace core {
24 
25  template <class T, int N>
27 
28  private:
30  using typename base_type::ship_type;
31  using typename base_type::grid_type;
32  using typename base_type::panel_type;
33  using typename base_type::vertex_type;
34 
35  private:
38 
39  public:
40 
41  void
42  solve(
43  const ship_type& ship,
44  const grid_type& grid_txyz,
45  Array3<T> wavy_surface
46  ) override;
47 
48  void
49  solve(
50  const ship_type& ship,
51  const grid_type& grid_txyz,
52  Array3<vertex_type> wavy_surface
53  ) override;
54 
55  private:
56 
57  template <class Interpolation> void
58  do_solve(
59  const ship_type& ship,
60  const grid_type& grid_txyz,
61  Interpolation interpolate
62  );
63 
64  };
65 
66  }
67 
68 }
69 
70 template <class T, int N>
71 void
73  const ship_type& ship,
74  const grid_type& grid_txyz,
75  Array3<T> wavy_surface
76 ) {
77  using function_type = Linear_function<T,2>;
78  using interpolation_type = Grid_interpolation<T,2,function_type>;
79  const auto _ = blitz::Range::all();
80  Grid<T,2> grid_xy{grid_txyz.select(1,2)};
81  function_type function(wavy_surface(wavy_surface.extent(0)-1,_,_), grid_xy);
82  this->do_solve(ship, grid_txyz, interpolation_type(grid_xy,std::move(function)));
83 }
84 
85 template <class T, int N>
86 void
88  const ship_type& ship,
89  const grid_type& grid_txyz,
90  Array3<vertex_type> wavy_surface
91 ) {
92  using function_type = Barycentric_function<T>;
93  using interpolation_type = Grid_interpolation<T,2,function_type>;
94  const auto _ = blitz::Range::all();
95  Grid<T,2> grid_xy{grid_txyz.select(1,2)};
96  function_type function(wavy_surface(wavy_surface.extent(0)-1,_,_));
97  this->do_solve(ship, grid_txyz, interpolation_type(grid_xy,std::move(function)));
98 }
99 
100 template <class T, int N>
101 template <class Interpolation>
102 void
104  const ship_type& ship,
105  const grid_type& grid_txyz,
106  Interpolation interpolate
107 ) {
108  using vec2 = vtb::core::Vector2<T>;
109  using vec3 = vtb::core::Vector3<T>;
110  using bool3 = blitz::TinyVector<bool,3>;
114  using vtb::geometry::unit;
115  const auto& hull = ship.hull();
116  const auto& bf_vertices = hull.vertices();
117  const int nvertices = bf_vertices.size();
118  auto& vertices = this->_efvertices;
119  vertices.resize(nvertices);
120  // Transform all hull vertices to Earth-fixed coordinate system.
121  #if defined(VTB_OPENMP)
122  #pragma omp parallel for
123  #endif
124  for (int i=0; i<nvertices; ++i) {
125  vertices[i] = ship.rotation_matrix()*bf_vertices[i] + ship.position();
126  }
127  Grid<T,2> grid_xy{grid_txyz.select(1,2)};
128  const auto& faces = hull.faces();
129  const int npanels = faces.size();
130  auto& mask = this->_wetted_vertices_mask;
131  this->_all_panels.resize(npanels);
132  auto& wetted_panels = this->_wetted_panels;
133  wetted_panels.clear();
134  wetted_panels.reserve(npanels/2);
135  auto& dry_panels = this->_dry_panels;
136  dry_panels.clear();
137  dry_panels.reserve(npanels/2);
138  mask.resize(nvertices);
139  // set mask for visualisation
140  mask_array valid_vertex(mask.size());
141  for (int i=0; i<nvertices; ++i) {
142  const auto& v = vertices[i];
143  valid_vertex[i] = grid_xy.contains(vec2{v(0),v(1)});
144  }
145  mask.assign(nvertices, false);
146  // clear waterline
147  auto& waterline = this->_waterline;
148  waterline.clear();
149  Bisection<T,1> bisection;
150  bisection.max_iterations(100);
151  bisection.argument_precision(T{1e-3});
152  bisection.function_precision(T{1e-3});
153  auto intersection_point =
154  [&] (vec3 from, vec3 to) -> vec3 {
155  const vec3 delta = to - from;
156  const T alpha = bisection(
157  T{0}, T{1},
158  [&] (T alpha) -> T {
159  vec3 x = from + alpha*delta;
160  return x(2) - interpolate({x(0),x(1)});
161  }
162  );
163  return from + alpha*delta;
164  };
165  #if defined(VTB_OPENMP)
166  #pragma omp parallel for schedule(dynamic,1)
167  #endif
168  for (int i=0; i<npanels; ++i) {
169  const auto& face = faces[i];
170  const int i0 = face[0];
171  const int i1 = face[1];
172  const int i2 = face[2];
173  if (!valid_vertex[i0] || !valid_vertex[i1] || !valid_vertex[i2]) {
174  continue;
175  }
176  Triangle<T,3> tr{vertices[i0], vertices[i1], vertices[i2]};
177  vec3 centre = centroid(tr);
178  T z_water[3] = {
179  interpolate({tr[0][0], tr[0][1]}),
180  interpolate({tr[1][0], tr[1][1]}),
181  interpolate({tr[2][0], tr[2][1]})
182  };
183  bool3 above{
184  tr[0][2] > z_water[0],
185  tr[1][2] > z_water[1],
186  tr[2][2] > z_water[2]
187  };
188  vec3 n = cross(vec3(tr[0]-tr[1]), vec3(tr[2]-tr[0]));
189  T area = T{0.5}*length(n);
190  // ignore degenerate panels
191  if (!(area > 0)) { continue; }
192  vec3 origin = ship.position();
193  origin(2) = 0; // TODO ???
194  T volume = signed_volume(Tetrahedron<T,3>(origin,tr));
195  Line_segment<T,3> waterline_segment;
196  bool has_waterline_segment = false;
197  bool wet = !all(above);
198  // if we have at least one vertex above the water level
199  // and at least one vertex below the water level
200  if (any(above) && wet) {
201  vec3 a, b;
202  bool x01 = above(0) ^ above(1);
203  bool x02 = above(0) ^ above(2);
204  bool x12 = above(1) ^ above(2);
205  int outstanding = 0;
206  if (x01 && x02) { outstanding = 0, a = tr[1], b = tr[2]; }
207  else if (x01 && x12) { outstanding = 1, a = tr[0], b = tr[2]; }
208  else { outstanding = 2, a = tr[0], b = tr[1]; }
209  const vec3& outstanding_vertex = tr[outstanding];
210  Triangle<T,3> subtr{
211  outstanding_vertex,
212  intersection_point(outstanding_vertex, a),
213  intersection_point(outstanding_vertex, b)
214  };
215  T subarea = vtb::geometry::area(subtr);
216  if (!(subarea > T{0})) { continue; }
217  waterline_segment[0] = subtr[1];
218  waterline_segment[1] = subtr[2];
219  has_waterline_segment = true;
220  #if defined(VTB_DEBUG_TRIANGLES)
221  std::string tag;
222  #endif
223  // TODO why ship.position()
224  T new_volume = signed_volume(Tetrahedron<T,3>(ship.position(),subtr));
225  if (outstanding_vertex(2) > z_water[outstanding]) {
226  area -= subarea;
227  volume -= new_volume;
228  centre = T{0.25} * (subtr[1] + subtr[2] + a + b);
229  #if defined(VTB_DEBUG_TRIANGLES)
230  tag = "polygon";
231  #endif
232  } else {
233  area = subarea;
234  volume = new_volume;
235  centre = centroid(subtr);
236  #if defined(VTB_DEBUG_TRIANGLES)
237  tag = "triangle";
238  #endif
239  }
240  #if defined(VTB_DEBUG_TRIANGLES)
241  const auto& grid_xyz = grid_txyz.select(1,2,3);
242  if (!grid_xyz.contains(centre)) {
243  std::clog << "grid_xyz=" << grid_xyz << std::endl;
244  std::clog << "centre=" << centre << std::endl;
245  std::clog << "tr=" << tr << std::endl;
246  std::clog << "subtr=" << subtr << std::endl;
247  std::clog << "tag=" << tag << std::endl;
248  std::clog << "area=" << area << std::endl;
249  std::clog << "subarea=" << subarea << std::endl;
250  dbg::write_triangle("tr", tr);
251  dbg::write_triangle("subtr", subtr);
252  }
253  #endif
254  }
255  auto& panel = this->_all_panels[i];
256  panel.centre(centre);
257  panel.normal(-unit(n));
258  panel.area(area);
259  panel.volume(volume);
260  panel.wetted(wet);
261  panel.waterline(has_waterline_segment);
262  if (wet) {
263  #if defined(VTB_WITH_OPENMP)
264  #pragma omp critical
265  #endif
266  {
267  wetted_panels.emplace_back(panel);
268  mask[i0] = true, mask[i1] = true, mask[i2] = true;
269  if (has_waterline_segment) {
270  waterline.emplace_back(waterline_segment);
271  }
272  }
273  } else {
274  #if defined(VTB_OPENMP)
275  #pragma omp critical
276  #endif
277  {
278  dry_panels.emplace_back(panel);
279  }
280  }
281  }
282 }
283 
284 template <>
285 auto
286 vtb::core::make_wetted_surface_solver<VTB_REAL_TYPE,3,vtb::core::Policy::OpenMP>() ->
287 std::unique_ptr<Wetted_surface_solver<VTB_REAL_TYPE,3>> {
289  new Wetted_surface_solver_openmp<VTB_REAL_TYPE,3>
290  );
291 }
292 
const vec3 & position(int i=0) const
Get position or its time derivatives in Earth-fixed coordinate system.
Definition: core/ship.hh:253
Rigid ship with a mass and translational and angular velocity.
Definition: core/ship.hh:186
void solve(const ship_type &ship, const grid_type &grid_txyz, Array3< T > wavy_surface) override
Determine underwater hull panels (faces) taking into account ship position and orientation.
TinyVector< T, 1 > cross(const TinyVector< T, 2 > &a, const TinyVector< T, 2 > &b)
Two-dimensional cross product.
Definition: blitz.hh:570
Triangular ship hull panel (face).
T length(const blitz::TinyVector< T, N > &x)
Computes vector length without overflow.
Definition: blitz.hh:471
Main namespace.
Definition: convert.hh:9