Virtual Testbed
Ship dynamics simulator for extreme conditions
wind_generator.hh
1 #ifndef VTESTBED_CORE_WIND_GENERATOR_HH
2 #define VTESTBED_CORE_WIND_GENERATOR_HH
3 
4 #include <memory>
5 #include <random>
6 #include <chrono>
7 #include <cmath>
8 
9 #include <vtestbed/base/blitz.hh>
10 #include <vtestbed/core/debug.hh>
11 #include <vtestbed/core/grid.hh>
12 #include <vtestbed/core/types.hh>
13 #include <vtestbed/core/yule_walker_solver.hh>
14 #include <vtestbed/linalg/linear_algebra.hh>
15 
16 //#define VTB_DEBUG_WIND
17 
18 namespace vtb {
19 
20  namespace core {
21 
22  template <class T>
23  class Wind_param {
24  public:
25  typedef Grid<T,4> grid_type;
26  typedef blitz::TinyVector<int,4> shape_type;
27 
28  public:
29  T _c1, _c2;
30  T _sigma;
31  grid_type _grid;
32  shape_type _order;
33 
34  public:
35  Wind_param() {
36  _order = shape_type{4,4,4,4};
37  _c1 = 0.01;
38  _c2 = 1;
39  _grid = Grid<T,4>{
40  {0,-50,-50,0},
41  {2,50,50,50},
42  {10,10,10,10}};
43  _sigma = 1;
44  }
45  ~Wind_param() = default;
46 
47  Wind_param& operator=(const Wind_param& rhs) {
48  this->_c1 = rhs._c1;
49  this->_c2 = rhs._c2;
50  this->_sigma = rhs._sigma;
51  this->_grid = rhs._grid;
52  this->_order = rhs._order;
53  return *this;
54  }
55  };
56 
57  //template <class T>
58  //class Wind_generator {
59  //private:
60  //public:
61 
62  // Wind_generator() = default;
63  // Wind_generator(const Wind_generator&) = default;
64  // virtual ~Wind_generator() = default;
65  // Wind_generator& operator=(const Wind_generator&) = default;
66 
67  //}
68 
69  template <class T>
71  public:
72  typedef Grid<T,4> grid_type;
73  typedef Array<T,4> array_type;
74  typedef std::mt19937 prng_type;
75  typedef blitz::TinyVector<int,4> shape_type;
76  private:
77  array_type _buffer;
78  int _offset = 0;
79  array_type _coefficients;
80  T _whitenoisevariance;
81  prng_type _prng;
82  shape_type _order_acf;
83  Wind_param<T> _param;
84  public:
85 
86  Wind_generator() {
87  createSeed();
88  }
89 
90  ~Wind_generator() = default;
91  Wind_generator(const Wind_generator&) = default;
92  Wind_generator& operator=(const Wind_generator&) = default;
93 
94  inline const shape_type&
95  order() const noexcept {
96  return this->_order;
97  }
98 
99  blitz::Array<T,4>
100  calculate_acf(blitz::TinyVector<int,4> shape) {
101  blitz::Array<T,4> result(shape);
102  T c1 = this->_param._c1;
103  //T c2 = this->_param._c2;
104  T sigma = this->_param._sigma;
105  grid_type grid = this->_param._grid;
106  //T U = 5;
107  typedef blitz::TinyVector<int,4> index;
108  for_loop<4>(
109  shape,
110  [&] (const index& idx) {
111  T a = idx(0) * grid.length(0) / (shape(0) - 1);
112  T b = idx(1) * grid.length(1) / (shape(1) - 1);
113  T c = idx(2) * grid.length(2) / (shape(2) - 1);
114  T d = idx(3) * grid.length(3) / (shape(3) - 1);
115  result(idx) =
116  sigma*sigma*exp(-c1*(a + b + c + d)) /*
117  (2*c2*(U)*sqrt((b*b + c*c + d*d))) /
118  (pow(c2*sqrt(b*b + c*c + d*d), 2) +
119  a*a*(U)*(U))*/;
120  }
121  );
122  result(0,0,0,0) = sigma;
123  return result;
124  }
125 
126  void setParam(Wind_param<T> param) {
127  this->_param = param;
128  }
129 
130  void calculateCoefficients() {
131  using namespace vtb::core;
132  using blitz::abs;
133  using blitz::all;
134  using blitz::max;
135  using blitz::shape;
136  shape_type order = this->_param._order;
137  T variance = 1.0;
138  blitz::Array<T,4> acf(variance * calculate_acf(order + 1));
139  #if defined(VTB_DEBUG_WIND)
140  const auto _ = blitz::Range::all();
141  dbg::write_animated_surface("wind.acf", acf(0,_,_,_));
142  #endif
144  gauss.chop(true);
145  _coefficients.reference(gauss.solve(acf));
146  _whitenoisevariance = gauss.white_noise_variance();
147  #if defined(VTB_DEBUG_WIND)
148  std::clog << "_whitenoisevariance=" << _whitenoisevariance << std::endl;
149  #endif
150  }
151 
152  void createSeed() {
153  typedef std::chrono::high_resolution_clock clock_type;
154  std::random_device dev;
155  std::seed_seq seq{{
156  clock_type::now().time_since_epoch().count(),
157  clock_type::rep(dev())
158  }};
159  this->_prng.seed(seq);
160  }
161 
162  array_type
163  generate() {
164  grid_type grid = this->_param._grid;
165  array_type result(grid.shape());
166  const auto& phi = this->_coefficients;
167  auto& buffer = this->_buffer;
168  auto& offset = this->_offset;
169 
170  if (buffer.extent(1) != grid.extent(1) ||
171  buffer.extent(2) != grid.extent(2) ||
172  buffer.extent(3) != grid.extent(3) ||
173  buffer.extent(0) < phi.extent(0) + grid.extent(0)) {
174  buffer.resize(
175  std::max(
176  phi.extent(0) + 1,
177  phi.extent(0) + grid.extent(0)),
178  grid.extent(1),
179  grid.extent(2),
180  grid.extent(3)
181  );
182  buffer = 0;
183  offset = 0;
184  }
185 
186  const auto nt = grid.extent(0);
187  if (offset + nt >= buffer.extent(0)) {
188  int shift = offset + nt - buffer.extent(0);
189  int slice_size = buffer.extent(1)*buffer.extent(2);
190  std::memmove(
191  buffer.data(),
192  buffer.data() + shift*slice_size,
193  (offset-shift)*slice_size*sizeof(T)
194  );
195  offset -= shift;
196  }
197  typedef blitz::TinyVector<int,4> index;
198  index r0{offset,0,0,0};
199  index r1{offset+grid.extent(0), buffer.extent(1),
200  buffer.extent(2), buffer.extent(3)};
201  blitz::RectDomain<4> r{r0,r1-1};
202  this->generate_white_noise(buffer(r));
203 
204  for_loop<4>(
205  r,
206  [&] (const index& idx) {
207  T sum{0};
208  index shape{blitz::min(idx+1, phi.shape())};
209  for_loop<4>(
210  shape,
211  [&] (const index& idx2) {
212  sum += phi(idx2) * buffer(index{idx-idx2});
213  }
214  );
215  buffer(idx) += sum;
216  }
217  );
218 
219  result = buffer(r);
220  offset += nt;
221  //auto m = blitz::minmax(result);
222  //std::clog << "m.min=" << m.min << std::endl;
223  //std::clog << "m.max=" << m.max << std::endl;
224  return result;
225  }
226 
227  void
228  generate_white_noise(
229  array_type result
230  ) {
231  const T stdev = std::sqrt(this->_whitenoisevariance);
232  //std::clog << "stdev" << std::endl;
233  //std::clog << stdev << std::endl;
234  std::normal_distribution<T> normal(T{0}, stdev);
235  for (auto& x : result) { x = normal(this->_prng); }
236  }
237 
238 
239  };
240 
241  }
242 
243 }
244 
245 #endif // vim:filetype=cpp
const T length(int i) const noexcept
The size of the region for dimension i.
Definition: core/grid.hh:230
int extent(int i) const noexcept
The number of points for dimension i.
Definition: core/grid.hh:114
value_type white_noise_variance() const noexcept
Core components.
Definition: bstream.hh:181
const int_n shape() const noexcept
The number of points for all dimensions.
Definition: core/grid.hh:108
Main namespace.
Definition: convert.hh:9
array_type solve(array_type acf) override
Solve Yule—Walker system of equations.