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> 16 #if defined(VTB_DEBUG_TRIANGLES) 18 #include <vtestbed/core/debug.hh> 25 template <
class T,
int N>
33 using typename base_type::vertex_type;
45 Array3<T> wavy_surface
52 Array3<vertex_type> wavy_surface
57 template <
class Interpolation>
void 61 Interpolation interpolate
70 template <
class T,
int N>
75 Array3<T> wavy_surface
79 const auto _ = blitz::Range::all();
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)));
85 template <
class T,
int N>
90 Array3<vertex_type> wavy_surface
94 const auto _ = blitz::Range::all();
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)));
100 template <
class T,
int N>
101 template <
class Interpolation>
105 const grid_type& grid_txyz,
106 Interpolation interpolate
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);
121 #if defined(VTB_OPENMP) 122 #pragma omp parallel for 124 for (
int i=0; i<nvertices; ++i) {
125 vertices[i] = ship.rotation_matrix()*bf_vertices[i] + ship.
position();
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;
137 dry_panels.reserve(npanels/2);
138 mask.resize(nvertices);
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)});
145 mask.assign(nvertices,
false);
147 auto& waterline = this->_waterline;
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(
159 vec3 x = from + alpha*delta;
160 return x(2) - interpolate({x(0),x(1)});
163 return from + alpha*delta;
165 #if defined(VTB_OPENMP) 166 #pragma omp parallel for schedule(dynamic,1) 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]) {
176 Triangle<T,3> tr{vertices[i0], vertices[i1], vertices[i2]};
177 vec3 centre = centroid(tr);
179 interpolate({tr[0][0], tr[0][1]}),
180 interpolate({tr[1][0], tr[1][1]}),
181 interpolate({tr[2][0], tr[2][1]})
184 tr[0][2] > z_water[0],
185 tr[1][2] > z_water[1],
186 tr[2][2] > z_water[2]
188 vec3 n =
cross(vec3(tr[0]-tr[1]), vec3(tr[2]-tr[0]));
189 T area = T{0.5}*
length(n);
191 if (!(area > 0)) {
continue; }
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);
200 if (any(above) && wet) {
202 bool x01 = above(0) ^ above(1);
203 bool x02 = above(0) ^ above(2);
204 bool x12 = above(1) ^ above(2);
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];
212 intersection_point(outstanding_vertex, a),
213 intersection_point(outstanding_vertex, b)
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) 224 T new_volume = signed_volume(Tetrahedron<T,3>(ship.
position(),subtr));
225 if (outstanding_vertex(2) > z_water[outstanding]) {
227 volume -= new_volume;
228 centre = T{0.25} * (subtr[1] + subtr[2] + a + b);
229 #if defined(VTB_DEBUG_TRIANGLES) 235 centre = centroid(subtr);
236 #if defined(VTB_DEBUG_TRIANGLES) 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;
246 std::clog <<
"subtr=" << subtr << 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);
255 auto& panel = this->_all_panels[i];
256 panel.centre(centre);
257 panel.normal(-unit(n));
259 panel.volume(volume);
261 panel.waterline(has_waterline_segment);
263 #if defined(VTB_WITH_OPENMP) 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);
274 #if defined(VTB_OPENMP) 278 dry_panels.emplace_back(panel);
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>
const vec3 & position(int i=0) const
Get position or its time derivatives in Earth-fixed coordinate system.
Rigid ship with a mass and translational and angular velocity.
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.
Triangular ship hull panel (face).
T length(const blitz::TinyVector< T, N > &x)
Computes vector length without overflow.