6 #include <vtestbed/base/constants.hh> 7 #include <vtestbed/base/for_loop.hh> 8 #include <vtestbed/config/openmp.hh> 9 #include <vtestbed/config/real_type.hh> 10 #include <vtestbed/core/bisection.hh> 11 #include <vtestbed/core/gerstner.hh> 12 #include <vtestbed/core/linear_wave.hh> 13 #include <vtestbed/core/ship_hull_panel.hh> 14 #include <vtestbed/core/types.hh> 15 #include <vtestbed/geometry/cubic_spline.hh> 16 #include <vtestbed/geometry/spline_surface.hh> 17 #include <vtestbed/geometry/tetrahedron.hh> 18 #include <vtestbed/opencl/opencl.hh> 19 #include <vtestbed/opencl/pipeline.hh> 20 #include <vtestbed/opencl/vector.hh> 25 using vtb::opencl::make_vector;
38 using typename base_type::vertex_field_3d;
39 using typename base_type::scalar_field_3d;
42 using typename base_type::vertex_type;
49 vertex_type centre{T{}}, normal{T{}};
50 inline small_panel(
const vertex_type& c,
const vertex_type& n):
51 centre(c), normal(n) {}
55 static_assert(
sizeof(small_panel) ==
sizeof(vertex_type)*2,
"bad small_panel");
56 static_assert(
sizeof(
wave_type) == 4*
sizeof(T),
"bad wave_type");
59 clx::kernel _compute_forces;
60 std::array<clx::kernel,(1<<5)> _generate_field;
68 using Context_base::context;
70 void context(
Context* rhs)
override {
71 Context_base::context(rhs);
74 auto t0 = clock::now();
75 size_t nkernels = this->_generate_field.size();
77 #if defined(VTB_WITH_OPENMP) 78 #pragma omp parallel for schedule(dynamic,1) 80 for (
size_t i=0; i<nkernels; ++i) {
84 velocity_and_potential = i & 8,
85 finite_depth = i & 16;
86 auto cc = context()->compiler();
87 auto options = cc.options();
88 if (
diffraction) { options +=
" -DVTB_DIFFRACTION"; }
89 if (
radiation) { options +=
" -DVTB_RADIATION"; }
90 if (position) { options +=
" -DVTB_POSITION"; }
91 if (velocity_and_potential) {
92 options +=
" -DVTB_VELOCITY -DVTB_POTENTIAL";
94 if (finite_depth) { options +=
" -DVTB_FINITE_DEPTH"; }
95 else { options +=
" -DVTB_INFINITE_DEPTH"; }
97 auto prog = cc.compile(
"gerstner.cl");
98 this->_generate_field[i] = prog.kernel(
"generate_field");
100 if (clock::now()-t0 > seconds(1)) {
101 std::fprintf(stderr,
"%5d/%-5lu compile gerstner\n", cnt, nkernels);
104 auto& cc = context()->compiler();
105 auto prog = cc.compile(
"gerstner.cl");
106 this->_compute_forces = prog.kernel(
"compute_forces");
109 inline clx::kernel& generate_field_kernel(
111 bool velocity_and_potential,
117 if (position) { i |= 4; }
118 if (velocity_and_potential) { i |= 8; }
119 if (finite_depth) { i |= 16; }
120 return this->_generate_field[i];
125 const grid4& grid_tzxy,
126 panel_array & wetted_panels
129 void compute_positions(
131 const panel_array& panels,
132 const grid3& grid_txy,
133 vertex_field_3d& result
137 const grid3& grid_zxy,
139 const panel_array& all_panels,
141 vertex_field_3d* position,
142 vertex_field_3d* velocity=
nullptr,
143 scalar_field_3d* potential=
nullptr 159 const grid4 & grid_tzxy,
160 panel_array & wetted_panels
163 grid3 grid_zxy = grid_tzxy.select(1,2,3);
164 if (this->clip()) { grid_zxy = clamp(grid_zxy, wetted_panels); }
165 if (grid_zxy.ubound(2) > 0) { grid_zxy.ubound(2) = 0; }
166 if (grid_zxy.empty()) {
return; }
168 this->_velocity_grid_zxy = grid_zxy;
170 const T t = grid_tzxy.ubound(0);
171 auto& velocity = this->_velocity;
172 auto& potential = this->_potential;
173 velocity.resize(grid_zxy.shape());
174 potential.resize(grid_zxy.shape());
175 generate_field(grid_zxy, t, wetted_panels, ship,
nullptr, &velocity, &potential);
176 auto& ppl = context()->pipeline();
177 auto& kernel = this->_compute_forces;
180 ppl.copy(wetted_panels, d_wetted_panels);
181 ppl.copy(velocity, d_velocity);
182 kernel.arguments(make_vector(grid_zxy.lbound()), make_vector(grid_zxy.ubound()),
183 make_vector(grid_zxy.shape()), d_velocity, d_wetted_panels);
185 ppl.kernel(kernel, clx::range(wetted_panels.size()));
187 ppl.copy(d_wetted_panels, wetted_panels);
196 const panel_array& panels,
197 const grid3 & grid_txy,
198 vertex_field_3d& surface
200 const auto& _ = blitz::Range::all();
201 const auto& grid_xy = grid_txy.select(1, 2);
202 const T t = grid_txy.ubound(0);
203 grid3 grid_zxy{Grid<T,1>{T{},T{},1}, grid_txy.select(1), grid_txy.select(2)};
204 Array<vertex_type,3> position(grid_zxy.shape());
205 generate_field(grid_zxy, t, panels, ship, &position,
nullptr,
nullptr);
206 surface(grid_txy.end(0)-1,_,_) = position(0,_,_);
209 template <
class T>
void 211 const grid3& grid_zxy,
213 const panel_array& all_panels,
215 vertex_field_3d* position,
216 vertex_field_3d* velocity,
217 scalar_field_3d* potential
219 const auto h = this->depth();
220 const bool infinite_depth = is_positive_infinity(h);
221 const bool waterline_only = this->waterline_only();
222 auto& ppl = context()->pipeline();
223 const auto& cc = context()->compiler();
224 auto& waves = this->_waves;
225 auto& d_waves = this->_d_waves;
226 ppl.copy(waves, d_waves);
227 auto& kernel = generate_field_kernel(position, velocity && potential, !infinite_depth);
228 kernel.arguments(t, h, d_waves,
int(waves.size()), make_vector(grid_zxy.lbound()),
229 make_vector(grid_zxy.delta()), make_vector(grid_zxy.shape()));
230 size_t argument_index = 7;
231 if (this->diffraction() || this->radiation()) {
232 small_panel_array panels;
233 panels.reserve(all_panels.size());
234 for (
const auto& panel : all_panels) {
235 if ((waterline_only && panel.waterline()) || (!waterline_only && panel.wetted())) {
236 panels.emplace_back(panel.centre(), panel.normal());
239 auto& d_panels = this->_d_small_panels;
240 int npanels = panels.size();
242 ppl.copy(panels, d_panels);
244 kernel.argument(argument_index++, npanels);
245 kernel.argument(argument_index++, d_panels);
247 const auto& device = cc.devices().front();
248 auto wg = kernel.work_group(device);
249 auto local_memory_size = device.local_memory_size();
250 num_local_panels = std::max(
size_t(1),
251 std::min({wg.size, local_memory_size /
sizeof(small_panel), panels.size()}));
252 kernel.argument(argument_index++,
int(num_local_panels));
253 kernel.argument(argument_index++, clx::local<small_panel>(num_local_panels));
255 if (position && !velocity && !potential) {
257 ppl.allocate(position->shape(), d_result);
258 kernel.argument(argument_index++, d_result);
260 ppl.kernel(kernel, grid_zxy.shape());
262 ppl.copy(d_result, *position);
264 }
else if (!position && velocity && potential) {
265 Array<Vector<T,4>,3> velocity_and_potential(velocity->shape());
267 ppl.allocate(velocity->shape(), d_velocity_and_potential);
268 kernel.argument(argument_index++, d_velocity_and_potential);
270 ppl.kernel(kernel, grid_zxy.shape());
272 ppl.copy(d_velocity_and_potential, velocity_and_potential);
274 auto first = velocity->data();
275 for (
const auto& v : velocity_and_potential) {
276 *first++ = vertex_type(v(0),v(1),v(2));
278 auto first2 = potential->data();
279 for (
const auto& v : velocity_and_potential) { *first2++ = v(3); }
288 vtb::core::make_gerstner_solver<VTB_REAL_TYPE,3,vtb::core::Policy::OpenCL>() {
290 new Gerstner_solver_opencl<VTB_REAL_TYPE>
Trochoidal irrotational waves solves named after Gerstner.
Rigid ship with a mass and translational and angular velocity.
Triangular ship hull panel (face).
bool radiation() const
Calculate radiation forces?
bool diffraction() const
Calculate diffraction forces?