Virtual Testbed
Ship dynamics simulator for extreme conditions
velocity_potential_opencl.cc
1 #include <vtestbed/base/constants.hh>
2 #include <vtestbed/config/real_type.hh>
3 #include <vtestbed/core/math.hh>
4 #include <vtestbed/core/velocity_potential.hh>
5 #include <vtestbed/opencl/fourier_transform.hh>
6 #include <vtestbed/opencl/pipeline.hh>
7 
11 
12 namespace vtb {
13 
14  namespace core {
15 
16  template <class T>
19  public Context_base
20  {
21 
22  private:
23  using C = std::complex<T>;
24  using int2 = blitz::TinyVector<int,2>;
25  using kernel_type = clx::kernel;
27 
28  private:
29  fft_type _fft;
30  Array<T,3> _wf;
31  Buffer<T> _d_window_function;
32  Buffer<T> _d_phi;
33  Grid<T,3> _wfgrid;
34  clx::program _prog;
35 
36  public:
37 
38  using Context_base::context;
39 
40  void
41  solve(
42  const Grid<T,4>& grid_tzxy,
43  const Array<T,3>& wavy_surface,
44  Array<T,4>& velocity_potential
45  ) override;
46 
47  void
48  window_function(
49  const Grid<T,2>& wngrid,
50  const T z,
51  Array2<T>& result
52  );
53 
54  void context(Context* rhs) override {
55  Context_base::context(rhs);
56  this->_fft.context(rhs);
57  fft_type::precompile({10,10}, rhs);
58  auto prog = context()->compiler().compile("velocity_potential.cl");
59  this->_prog = prog;
60  }
61 
62  };
63 
64  }
65 
66 }
67 
68 typedef VTB_REAL_TYPE T;
69 using vtb::core::Policy;
70 
71 namespace {
72 
73 // #define VTB_DEBUG_VELOCITY_POTENTIAL
74 
75  #if defined(VTB_DEBUG_VELOCITY_POTENTIAL)
76  template <class T, int N>
77  void
78  dump(vtb::opencl::Buffer<T> d_x, const blitz::TinyVector<int,N>& shape,
79  const char* name, int i=-1) {
80  blitz::Array<T,N> x(shape);
81  ppl.copy(d_x, x);
82  ppl.wait();
83  std::stringstream filename;
84  filename << name;
85  if (i >=0 ) {
86  filename << i;
87  }
88  std::ofstream(filename.str()) << x;
89  }
90  #endif
91 
92  #if defined(VTB_DEBUG_VELOCITY_POTENTIAL)
93  #define VTB_DUMP(x, shape) ::dump(x, shape, #x)
94  #define VTB_DUMP2(x, shape, i) ::dump(x, shape, #x, i)
95  #define VTB_DUMP3(x, shape, name, i) ::dump(x, shape, name, i)
96  #else
97  #define VTB_DUMP(x, shape)
98  #define VTB_DUMP2(x, shape, i)
99  #define VTB_DUMP3(x, shape, name, i)
100  #endif
101 
102 }
103 
104 template <>
105 void
107  const Grid<T,4>& grid_tzxy,
108  const Array<T,3>& zeta,
109  Array<T,4>& phi
110 ) {
111  using blitz::Range;
112  const int nt = grid_tzxy.extent(0);
113  const Grid<T,2> grid_xy(grid_tzxy.select(2,3));
114  const Range _ = Range::all();
115  Array<C,3> sf(zeta.shape());
116  this->second_function(grid_tzxy, zeta, sf);
117  // update FFT wave table for the new shape
118  {
119  this->_fft.shape(grid_xy.shape());
120  #if defined(VTB_DEBUG_VELOCITY_POTENTIAL)
121  std::ofstream out{"fft.cl"};
122  this->_fft.dump(out);
123  #endif
124  }
125  auto wnrange = this->wave_number_grid();
126  wnrange.end() = grid_xy.shape();
127  Grid<T,3> new_wfgrid{grid_tzxy.select(1), wnrange.select(0), wnrange.select(1)};
128  if (wnrange.empty() || near(wnrange.ubound(), T{0}, T{1e-3})) {
129  phi = 0;
130  return;
131  }
132  // limit wave number by the grid size
133  Vector<T,2> wnmax = base::constants<T>::pi(4) / (grid_xy.ubound() - grid_xy.lbound());
134  wnrange.ubound() = min(wnmax, wnrange.ubound());
135  wnrange.ubound() = min(wnrange.lbound(), wnrange.ubound());
136  auto& ppl = context()->pipeline();
137  auto& d_window_function = this->_d_window_function;
138  if (!new_wfgrid.near(this->_wfgrid, T{1e-3})) {
139  this->_wfgrid = new_wfgrid;
140  const auto& window_function_shape = this->_wfgrid.shape();
141  this->_wf.resize(window_function_shape);
142  ppl.allocate(this->_wfgrid.num_elements(), d_window_function);
143  const T h = this->depth();
144  bool infinite_depth = is_positive_infinity(h);
145  auto lbound{this->_wfgrid.lbound()};
146  auto delta{this->_wfgrid.delta()};
147  auto kernel_name = infinite_depth ? "lvps_wf_infinite_depth" : "lvps_wf_finite_depth";
148  auto kernel = this->_prog.kernel(kernel_name);
149  kernel.argument(0, lbound(0));
150  kernel.argument(1, delta(0));
151  kernel.argument(2, lbound(1));
152  kernel.argument(3, delta(1));
153  kernel.argument(4, lbound(2));
154  kernel.argument(5, delta(2));
155  if (infinite_depth) {
156  kernel.argument(6, d_window_function);
157  } else {
158  kernel.argument(6, h);
159  kernel.argument(7, d_window_function);
160  }
161  ppl.kernel(kernel, window_function_shape);
162  ppl.step();
163  }
164  auto& d_phi = this->_d_phi;
165  ppl.allocate(phi.size(), d_phi);
166  Buffer<C> d_fft_sf, d_result;
167  ppl.allocate(this->_wfgrid.num_elements(), d_result);
168  // for each time instant
169  for (int i=0; i<nt; ++i) {
170  Array<C,2> fft_sf(grid_xy.shape());
171  fft_sf = sf(i,_,_);
172  ppl.copy(fft_sf, d_fft_sf);
173  ppl.step();
174  this->_fft.forward(d_fft_sf);
175  VTB_DUMP2(fft_sf, grid_xy.shape(), i);
176  const auto& window_function_shape = this->_wfgrid.shape();
177  {
178  auto kernel = this->_prog.kernel("lvps_multiply");
179  kernel.argument(0, d_fft_sf);
180  kernel.argument(1, d_window_function);
181  kernel.argument(2, d_result);
182  ppl.step();
183  ppl.kernel(kernel, window_function_shape);
184  }
185  ppl.step();
186  this->_fft.backward(d_result, window_function_shape(0));
187  {
188  auto kernel = this->_prog.kernel("lvps_copy_back");
189  kernel.argument(0, i);
190  kernel.argument(1, d_result);
191  kernel.argument(2, d_phi);
192  ppl.step();
193  ppl.kernel(kernel, window_function_shape);
194  }
195  ppl.wait();
196  }
197  ppl.copy(d_phi, phi);
198  ppl.wait();
199  VTB_DUMP3(phi, phi.shape(), "phi", -1);
200 }
201 
202 template <>
203 auto
204 vtb::core::make_velocity_potential_solver<T,3,Policy::OpenCL>() ->
205 std::unique_ptr<Velocity_potential_solver<T,3>> {
207  new Linear_velocity_potential_solver_opencl<T>
208  );
209 }
210 
T min(T... args)
Main namespace.
Definition: convert.hh:9
Base class for linear velocity potential solver.