Virtual Testbed
Ship dynamics simulator for extreme conditions
gerstner_openmp.cc
1 #include <vtestbed/base/constants.hh>
2 #include <vtestbed/base/for_loop.hh>
3 #include <vtestbed/config/openmp.hh>
4 #include <vtestbed/config/real_type.hh>
5 #include <vtestbed/core/gerstner.hh>
6 #include <vtestbed/core/grid_interpolation.hh>
7 #include <vtestbed/core/ship_hull_panel.hh>
8 #include <vtestbed/core/types.hh>
9 #include <vtestbed/geometry/linear_interpolation.hh>
10 
11 namespace vtb {
12 
13  namespace core {
14 
15  template <class T>
17 
18  protected:
20  using typename base_type::vertex_field_3d;
21  using typename base_type::scalar_field_3d;
22  using typename base_type::panel_array;
23  using typename base_type::panel_type;
24  using typename base_type::vertex_type;
25  using typename base_type::grid4;
26  using typename base_type::grid3;
27  using typename base_type::wave_type;
28  using typename base_type::C;
29  using typename base_type::ship_type;
30 
31  enum class Quantity { Position, Velocity };
32 
33  public:
34 
35  void compute_forces(
36  const ship_type& ship,
37  const grid4& grid_tzxy,
38  panel_array & wetted_panels
39  ) override;
40 
41  void compute_positions(
42  const ship_type& ship,
43  const panel_array& panels,
44  const grid3& grid_txy,
45  vertex_field_3d& result
46  ) override;
47 
48  void generate_field(
49  const grid3& grid_xyz,
50  vertex_field_3d& result,
51  T t,
52  const panel_array& panels,
53  const ship_type& ship,
54  Quantity q,
55  scalar_field_3d* potential=nullptr
56  );
57 
58  };
59 
60  }
61 
62 }
63 
64 template <class T> void
66  const ship_type& ship,
67  const grid4& grid_tzxy,
68  panel_array & wetted_panels
69 ) {
70  int npanels = wetted_panels.size();
71  // clamp grid to panels
72  grid3 grid_zxy = grid_tzxy.select(1,2,3);
73  if (this->clip()) { grid_zxy = clamp(grid_zxy, wetted_panels); }
74  if (grid_zxy.ubound(2) > 0) { grid_zxy.ubound(2) = 0; }
75  if (grid_zxy.empty()) { return; }
76  grid_zxy.compact();
77  this->_velocity_grid_zxy = grid_zxy;
78  // compute velocity at grid points
79  const T t = grid_tzxy.ubound(0);
80  auto& velocity = this->_velocity;
81  auto& potential = this->_potential;
82  velocity.resize(grid_zxy.shape());
83  potential.resize(grid_zxy.shape());
84  auto old_diffraction = this->diffraction();
85  this->diffraction(false);
86  generate_field(grid_zxy, velocity, t, wetted_panels, ship,
87  Quantity::Velocity, &potential);
88  this->diffraction(old_diffraction);
89  // interpolate velocity and compute wave pressure
90  Linear_function_irregular<T,vertex_type> function(velocity, grid_zxy);
91  Grid_interpolation<T,3,Linear_function_irregular<T,vertex_type>,vertex_type>
92  interpolate(grid_zxy, function);
93  constexpr const auto g = vtb::base::constants<T>::g();
94  constexpr const auto rho = vtb::base::constants<T>::water_density();
95  constexpr const auto p0 = vtb::base::constants<T>::atmospheric_pressure();
96  #if defined(VTB_WITH_OPENMP)
97  #pragma omp parallel for
98  #endif
99  for (int i=0; i<npanels; ++i) {
100  auto& panel = wetted_panels[i];
101  const auto& centre = panel.centre();
102  auto z = centre(2);
103  const auto& velocity = interpolate({centre(2),centre(0),centre(1)});
104  T pressure = p0 - rho*(T{0.5}*sum_of_squares(velocity) + g*z);
105  panel.force() = pressure * (-panel.normal()) * panel.area();
106  }
107 }
108 
109 template <class T> void
111  const grid3& grid_zxy,
112  vertex_field_3d& result,
113  T t,
114  const panel_array& all_panels,
115  const ship_type& ship,
116  Quantity q,
117  scalar_field_3d* potential
118 ) {
119  using std::cosh;
120  using std::exp;
121  using std::sqrt;
122  using vtb::geometry::unit;
123  using vec3 = Vector<T,3>;
124  constexpr const auto pi = vtb::base::constants<T>::pi();
125  constexpr const auto g = vtb::base::constants<T>::g();
126  constexpr const C i(0,1);
127  const auto h = this->depth();
128  const bool infinite_depth = is_positive_infinity(h);
129  const bool diffraction = this->diffraction();
130  const bool radiation = this->radiation();
131  const bool waterline_only = this->waterline_only();
132  panel_array panels;
133  panels.reserve(all_panels.size());
134  for (const auto& panel : all_panels) {
135  if ((waterline_only && panel.waterline()) || (!waterline_only && panel.wetted())) {
136  panels.emplace_back(panel);
137  }
138  }
139  parallel_for_loop<3>(
140  grid_zxy.shape(),
141  [&] (const int3& idx) {
142  const auto& zxy = grid_zxy(idx);
143  const auto x = zxy(1), y = zxy(2), z = zxy(0);
144  vertex_type sum_position{x,y,z};
145  vertex_type sum_velocity{0,0,0};
146  T sum_potential{};
147  for (const auto& wave : this->_waves) {
148  const auto& _k_ = wave.wave_number();
149  T u = _k_(0), v = _k_(1);
150  T k = sqrt(u*u+v*v);
151  T omega = wave.angular_frequency();
152  T ampl = wave.amplitude();
153  T exp1 = infinite_depth ? exp(k*z) : cosh(k*(z+h));
154  C exp2 = exp(i*(u*x + v*y - omega*t));
155  C w = exp1 * exp2;
156  vec3 sum_dr{T{}};
157  if (diffraction) {
158  C exp3{};
159  vec3 di(u,v,0), zeta(x,y,z);
160  T sum_weight = 0;
161  for (const auto& panel : panels) {
162  const auto& centre = panel.centre();
163  const auto& n = panel.normal();
164  vec3 ds = 2*dot(di,n)*n;
165  vec3 dr = di-ds;
166  T weight = 1/(1+distance(zeta,centre));
167  //T weight = 1;
168  exp3 += exp(i*(dot(dr,zeta) + dot(ds,centre)))*weight;
169  //T{0.5}*(1+dot(unit(di),n));
170  sum_dr += dr;
171  sum_weight += weight;
172  }
173  if (sum_weight != 0) {
174  exp3 /= sum_weight, sum_dr /= sum_weight;
175  }
176  w += exp1*exp3*exp(-i*omega*t);
177  }
178  vec3 sum_wave_vector{T{}};
180  if (radiation) {
181  C exp4{};
182  vec3 zeta(x,y,z);
183  T sum_weight = 0;
184  for (const auto& panel : panels) {
185  const auto& n = panel.normal();
186  const auto& centre = panel.centre();
187  vec3 velocity = ship.velocity() +
188  cross(ship.angular_velocity(), vec3(centre-ship.position()));
189  auto old_velocity = velocity;
190  velocity = dot(velocity,n)*n;
191  //if (dot(vec3(zeta-ship.position()),n) < 0) { velocity -= n; }
192  T weight = 1/(1+length(vec3(zeta-centre)));
193  //vec3 wave_vector = length(velocity) / g * n;
194  vec3 wave_vector = g / (length(velocity)) * n/2;
195  //vec3 wave_vector = dot(old_velocity,n)/2*n;
196  T omega = dot(wave_vector,velocity);
197  exp4 += exp(i*(dot(wave_vector,zeta) - omega*t))*weight;
198  sum_wave_vector += wave_vector;
199  sum_weight += weight;
200  }
201  if (sum_weight != 0) {
202  exp4 /= sum_weight, sum_wave_vector /= sum_weight;
203  }
204  w += exp1*exp4;
205  }
206  sum_potential += real(w);
207  T scale = ampl*2*pi;
208  if (q == Quantity::Position) {
209  sum_position(0) += (u+sum_dr(0)+sum_wave_vector(0))*real(i*w);
210  sum_position(1) += (v+sum_dr(1)+sum_wave_vector(1))*real(i*w);
211  sum_position(2) += scale*real((k+i*sum_dr(2)+i*sum_wave_vector(2))*w);
212  } else {
213  sum_velocity(0) += omega*(u+sum_dr(0)+sum_wave_vector(0))*real(w);
214  sum_velocity(1) += omega*(v+sum_dr(1)+sum_wave_vector(1))*real(w);
215  sum_velocity(2) += -scale*omega*k*real(i*w);
216  }
217  }
218  result(idx) = (q == Quantity::Position) ? sum_position : sum_velocity;
219  if (potential) { (*potential)(idx) = sum_potential; }
220  }
221  );
222 }
223 
224 template <class T> void
226  const ship_type& ship,
227  const panel_array& panels,
228  const grid3& grid_txy,
229  vertex_field_3d& surface
230 ) {
231  const auto& _ = blitz::Range::all();
232  const auto& grid_xy = grid_txy.select(1, 2);
233  const T t = grid_txy.ubound(0);
234  grid3 grid_zxy{
235  {T{},grid_txy.lbound(1),grid_txy.lbound(2)},
236  {T{},grid_txy.ubound(1),grid_txy.ubound(2)},
237  {1,grid_txy.extent(1),grid_txy.extent(2)}};
238  Array<vertex_type,3> position(grid_zxy.shape());
239  generate_field(grid_zxy, position, t, panels, ship, Quantity::Position);
240  surface(grid_txy.end(0)-1,_,_) = position(0,_,_);
241 }
242 
243 template <>
245 vtb::core::make_gerstner_solver<VTB_REAL_TYPE,3,vtb::core::Policy::OpenMP>() {
247  new Gerstner_solver_openmp<VTB_REAL_TYPE>
248  );
249 }
250 
Trochoidal irrotational waves solves named after Gerstner.
Definition: gerstner.hh:31
const vec3 & position(int i=0) const
Get position or its time derivatives in Earth-fixed coordinate system.
Definition: core/ship.hh:253
static constexpr const T g()
Gravitational acceleration.
Definition: constants.hh:15
Rigid ship with a mass and translational and angular velocity.
Definition: core/ship.hh:186
static constexpr const T water_density()
Sea water density.
Definition: constants.hh:27
static constexpr T atmospheric_pressure()
Sea-level atmospheric pressure.
Definition: constants.hh:24
const vec3 & angular_velocity() const
Angular velocity in Earth-fixed coordinate system.
Definition: core/ship.hh:314
T scale(blitz::Array< T, N > x)
Return the difference between largest and smallest value in the array.
Definition: core/math.hh:35
const vec3 & velocity() const
Get velocity in Earth-fixed coordinate system.
Definition: core/ship.hh:260
static constexpr const T pi()
Definition: constants.hh:18
Triangular ship hull panel (face).
void generate_field(const grid3 &grid_xyz, vertex_field_3d &result, T t, const panel_array &panels, const ship_type &ship, Quantity q, scalar_field_3d *potential=nullptr)
Main namespace.
Definition: convert.hh:9