Virtual Testbed
Ship dynamics simulator for extreme conditions
anlt_wind_solver_openmp.cc
1 #include <vtestbed/base/blitz.hh>
2 #include <vtestbed/base/constants.hh>
3 #include <vtestbed/config/openmp.hh>
4 #include <vtestbed/config/real_type.hh>
5 #include <vtestbed/core/anlt_wind_solver.hh>
6 #include <vtestbed/core/policy.hh>
7 #include <vtestbed/core/ship_hull_panel.hh>
8 #include <vtestbed/geometry/tetrahedron.hh>
9 #include <vtestbed/linalg/linear_algebra.hh>
10 
11 //#define VTB_DEBUG_WIND
12 //#define VTB_DEBUG_WIND_CYLINDER
13 
14 #if defined(VTB_DEBUG_WIND)
15 #include <fstream>
16 #endif
17 
18 namespace vtb {
19 
20  namespace core {
21 
22  template <class T>
24 
25  private:
27  using typename base_type::array_type;
28  using typename base_type::wind_field_type;
29  using typename base_type::grid_type;
30  using typename base_type::panel_type;
31  using typename base_type::panel_array;
32  using typename base_type::ray_type;
33  using typename base_type::ray_array;
34 
35  public:
36  void step(const grid_type& grid, panel_array& panels) override;
37 
38  };
39  }
40 }
41 
42 template <class T>
44  const grid_type& grid,
45  panel_array& panels
46 ) {
47  using vec3 = blitz::TinyVector<T,3>;
49  using std::pow;
50  vec3 u(0,50,0);
51  auto& wind_field = this->_wind_field;
52  wind_field.resize(grid.shape());
53  wind_field = T{};
54  auto stratification = this->stratification();
55  const auto& delta = grid.delta();
56  #if defined(VTB_DEBUG_WIND_CYLINDER)
57  constexpr T R = T{54.8858}/2;
58  T U = u(0);
59  #endif
60  if (this->near_the_boundary()) {
61  parallel_for_loop<3>(
62  grid.shape(),
63  [&] (const int3& index) {
64  const auto& r = grid(index, delta);
65  vec3 sum{T{}};
66  T total_weight{T{}};
67  for (const auto& panel : panels) {
68  const auto& n = panel.normal();
69  const auto& S = panel.centre();
70  //if ((dot(n,u) > 0) || (dot(r-S, n) < 0)) {
71  // continue;
72  //}
73  //if (dot(n,u) > 0) { continue; }
74  if (stratification) {
75  T coef = 25.0;
76  T alpha = 1.15;
77  T z0 = 10.0;
78  T S_z = panel.centre()(2);
79  T z = r(2);
80  vec3 u_r = u - 2 * dot(u,n) * n;
81  vec3 u1(0, 0, (1+alpha)*pow(S_z,alpha)*dot(u, S));
82  vec3 u2(0, 0, (1+alpha)*pow(S_z,alpha));
83  vec3 u3(1, 1, (1+alpha)*pow(S_z,alpha + 1));
84  vec3 u4(0, 0, (1+alpha)*pow(z,alpha));
85  T S_r = sqrt(dot(S-r,S-r));
86  vec3 delta_phi(0, 0, 0);
87  T z_a = pow(z0, -alpha)/(alpha + 1);
88 
89  //T C2 = 1.0;
90  T C2 = dot(vec3(u*pow(S_z,alpha+1)+ u1), n)/
91  dot(vec3(u2*dot(u_r,S) + u3*u_r), n);
92  //delta_phi += z_a*u;
93  //delta_phi = z_a*C2*u_r*exp(-S_r/coef)*pow(z,1+alpha)+
94  delta_phi += z_a*C2*u_r*exp(-S_r/coef)*pow(z,1+alpha);
95  //delta_phi += z_a*C2*u_r*exp(-S_r/coef)*pow(z,1+alpha);
96  //z_a*C2*dot(u_r,r)*exp(-S_r);
97  //z_a*C2*dot(u_r,r)*exp(-S_r)*
98  //(u2 + (S-r)*pow(z,1+alpha))/S_r;
99 
100  sum += delta_phi;
101  } else {
102  vec3 u_r = u - T{2}*dot(u,n)*n;
103  T weight = T{1} / (T{1}+sum_of_squares(vec3(r-S)));
104  sum += u_r * weight;
105  total_weight += weight;
106  }
107  }
108  if (!all(isfinite(sum))) {
109  throw std::runtime_error("wind field is not finite");
110  }
111  if (total_weight != 0) { sum /= total_weight; }
112  if (stratification) {
113  T alpha = 1.15;
114  T z_a = pow(10.0, -alpha)/(alpha + 1);
115  //T z_a = pow(10.0, -alpha);
116  sum += u * z_a * pow(r(2), alpha);
117  //sum += u * z_a;
118  } else {
119  sum += u;
120  }
121  #if defined(VTB_DEBUG_WIND_CYLINDER)
122  // solution for potential flow around a cylinder
123  auto x = r(0), y = r(1);
124  auto pow2 = [] (T x) { return x*x; };
125  sum = vec3{U*(R*R*(y*y-x*x)+pow2(x*x+y*y)), -2*R*R*U*x*y, 0}/pow2(x*x+y*y);
126  #endif
127  wind_field(index) = sum;
128  }
129  );
130  }
131  #if defined(VTB_DEBUG_WIND)
132  {
133  #if defined(VTB_DEBUG_WIND_CYLINDER)
134  std::ofstream out("wind-orig");
135  #else
136  std::ofstream out("wind-our");
137  #endif
138  for_loop<3>(
139  grid.shape(),
140  [&] (const int3& index) {
141  if (index(2) != grid.extent(2)/2) { return; }
142  const auto& v = wind_field(index);
143  const auto& r = grid(index, delta);
144  #if defined(VTB_DEBUG_WIND_CYLINDER)
145  if (r(0)*r(0)+r(1)*r(1) < R*R) { return; }
146  #endif
147  out << r(0) << ' ' << r(1) << ' ';
148  out << v(0) << ' ' << v(1) << ' ';
149  out << '\n';
150  }
151  );
152  }
153  auto m = minmax(wind_field);
154  std::clog << "phi_min=" << m.min << std::endl;
155  std::clog << "phi_max=" << m.max << std::endl;
156  #endif
157  auto& wind_field_boundary = this->_wind_field_boundary;
158  if (this->on_the_boundary()) {
159  const int npanels = panels.size();
160  wind_field_boundary.resize(npanels);
161  constexpr auto rho = constants<T>::air_density();
162  constexpr auto g = constants<T>::g();
163  constexpr auto p0 = constants<T>::atmospheric_pressure();
164  #if defined(VTB_WITH_OPENMP)
165  #pragma omp parallel for
166  #endif
167  for (int i=0; i<npanels; ++i) {
168  auto& panel = panels[i];
169  const auto& r = panel.centre();
170  const auto& n = panel.normal();
171  vec3 u_r = u - 2*dot(u,n)*n;
172  vec3 velocity = u + u_r;
173  auto z = r(2);
174  auto pressure = p0-rho*(T{0.5}*sum_of_squares(velocity) + g*z);
175  panel.force() = pressure * (-n) * panel.area();
176  wind_field_boundary[i] = ray_type(r, velocity);
177  }
178  } else {
179  wind_field_boundary.clear();
180  }
181 }
182 
183 template <>
184 auto
185 vtb::core::make_anlt_wind_solver<VTB_REAL_TYPE,vtb::core::Policy::OpenMP>() ->
186 std::unique_ptr<ANLT_wind_solver<VTB_REAL_TYPE>> {
188  new ANLT_wind_solver_openmp<VTB_REAL_TYPE>
189  );
190 }
191 
T minmax(T... args)
T exp(T... args)
Triangular ship hull panel (face).
T isfinite(T... args)
Main namespace.
Definition: convert.hh:9
T pow(T... args)
T sqrt(T... args)