swarm.h
Go to the documentation of this file.
1 /*
2 This file is part of the Ristra portage project.
3 Please see the license file at the root of this repository, or at:
4  https://github.com/laristra/portage/blob/master/LICENSE
5 */
6 #ifndef PORTAGE_SWARM_SWARM_H_
7 #define PORTAGE_SWARM_SWARM_H_
8 
9 #include <vector>
10 #include <memory>
11 #include <cassert>
12 #include <cmath>
13 #include <cstdlib>
14 #include <chrono>
15 #include <algorithm>
16 #include <stdexcept>
17 #include <string>
18 #include <iostream>
19 #include <random>
20 
21 // portage includes
23 #include "wonton/support/Point.h"
24 
25 namespace Portage { namespace Meshfree {
26 
34 template<int dim>
35 class Swarm {
36 public:
37 
42  Swarm() = default;
43 
49  explicit Swarm(Portage::vector<Wonton::Point<dim>> const& points)
50  : points_(points),
51  num_local_points_(points_.size())
52  {}
53 
54 #ifdef PORTAGE_ENABLE_THRUST
55 
60  explicit Swarm(std::vector<Wonton::Point<dim>> const& points)
61  : points_(points),
62  num_local_points_(points_.size())
63  {}
64 #endif
65 
75  Swarm(int num_particles, int distribution,
76  unsigned user_seed = 0,
77  double x_min = 0.0, double x_max = 0.0,
78  double y_min = 0.0, double y_max = 0.0,
79  double z_min = 0.0, double z_max = 0.0);
80 
88  template<typename Mesh>
89  Swarm(Mesh const& mesh, Wonton::Entity_kind entity);
90 
98  template<typename Mesh>
99  Swarm(std::vector<Mesh*> const& meshes, Wonton::Entity_kind entity);
100 
105  ~Swarm() = default;
106 
112  int space_dimension() const { return dim; }
113 
119  int num_owned_particles() const { return num_local_points_; }
120 
126  int num_ghost_particles() const { return points_.size() - num_local_points_; }
127 
134  int num_particles(Wonton::Entity_type type = Wonton::ALL) const {
135  switch (type) {
136  case Wonton::PARALLEL_OWNED: return num_owned_particles();
137  case Wonton::PARALLEL_GHOST: return num_ghost_particles();
138  default: return num_owned_particles() + num_ghost_particles();;
139  }
140  }
141 
148  Wonton::Point<dim> get_particle_coordinates(int index) const {
149  Wonton::Point<dim> point = points_[index];
150  return point;
151  }
152 
160  counting_iterator begin(Entity_kind const kind = Wonton::PARTICLE,
161  Entity_type const type = Wonton::ALL) const {
162 
163  assert(kind == Wonton::PARTICLE);
164  return make_counting_iterator(0);
165  }
166 
174  counting_iterator end(Entity_kind const kind = Wonton::PARTICLE,
175  Entity_type const type = Wonton::ALL) const {
176 
177  assert(kind == Wonton::PARTICLE);
178  return (make_counting_iterator(0) + num_particles(type));
179  }
180 
185  void extend_particle_list(std::vector<Wonton::Point<dim>> const& new_pts) {
186  points_.insert(points_.end(), new_pts.begin(), new_pts.end());
187  }
188 
189 private:
192 
194  int num_local_points_ = 0;
195 };
196 
197 /* -------------------------------------------------------------------------- */
198 template<>
199 inline Swarm<1>::Swarm(int num_particles, int distribution, unsigned user_seed,
200  double x_min, double x_max,
201  double /* unused */, double /* unused */,
202  double /* unused */, double /* unused */) {
203 
204  assert(num_particles > 0);
205  assert(0 <= distribution and distribution <= 2);
206 
207  // resize field
208  points_.resize(num_particles);
209  num_local_points_ = num_particles;
210 
211  // set the random engine and generator
212  std::random_device device;
213  std::mt19937 engine { user_seed ? user_seed : device() };
214  std::uniform_real_distribution<double> generator(0.0, 1.0);
215 
216  // update coordinates
217  if (distribution == 0) {
218  for (auto&& current : points_)
219  current = Wonton::Point<1>(x_min + (x_max - x_min) * generator(engine));
220 
221  } else {
222  double const h = (x_max - x_min) / (num_particles - 1);
223  for (int i = 0; i < num_particles; i++)
224  points_[i] = Wonton::Point<1>(x_min + i * h);
225 
226  if (distribution == 2) {
227  for (int i = 0; i < num_particles; i++) {
228  Wonton::Point<1> current = points_[i];
229  current[0] += 0.25 * h * (2 * generator(engine) - 1);
230  points_[i] = Wonton::Point<1>(std::max(x_min, std::min(x_max, current[0])));
231  }
232  }
233  }
234 }
235 
236 /* -------------------------------------------------------------------------- */
237 template<>
238 inline Swarm<2>::Swarm(int num_particles, int distribution, unsigned user_seed,
239  double x_min, double x_max,
240  double y_min, double y_max,
241  double /* unused */, double /* unused */) {
242 
243  assert(num_particles > 0);
244  assert(0 <= distribution and distribution <= 2);
245 
246  // set the random engine and generator
247  std::random_device device;
248  std::mt19937 engine { user_seed ? user_seed : device() };
249  std::uniform_real_distribution<double> generator(0.0, 1.0);
250 
251  if (distribution == 0) {
252  // resize field and update coordinates
253  num_local_points_ = num_particles;
254  points_.resize(num_local_points_);
255 
256  for (auto&& current : points_) {
257  // point coordinates are not always initialized in order
258  // so enforce random number picking sequence
259  double const noise[] = { generator(engine),
260  generator(engine) };
261 
262  current = Wonton::Point<2>(x_min + (x_max - x_min) * noise[0],
263  y_min + (y_max - y_min) * noise[1]);
264  }
265  } else {
266  // resize field
267  int const num_per_dim = std::floor(std::sqrt(num_particles));
268  num_local_points_ = num_per_dim * num_per_dim;
269  points_.resize(num_local_points_);
270  double const hx = (x_max - x_min) / (num_per_dim - 1);
271  double const hy = (y_max - y_min) / (num_per_dim - 1);
272 
273  // update coordinates
274  int k = 0;
275  for (int i = 0; i < num_per_dim; i++)
276  for (int j = 0; j < num_per_dim; ++j)
277  points_[k++] = Wonton::Point<2>(x_min + i * hx, y_min + j * hy);
278 
279  if (distribution == 2) {
280  for (auto&& current : points_) {
281  // point coordinates are not always initialized in order
282  // so enforce random number picking sequence
283  double const noise[] = { generator(engine),
284  generator(engine) };
285 
286  Wonton::Point<2> copy = current;
287  copy[0] += 0.25 * hx * (2 * noise[0] - 1);
288  copy[1] += 0.25 * hy * (2 * noise[1] - 1);
289  current = Wonton::Point<2>(std::max(x_min, std::min(x_max, copy[0])),
290  std::max(y_min, std::min(y_max, copy[1])));
291  }
292  }
293  }
294 }
295 
296 /* -------------------------------------------------------------------------- */
297 template<>
298 inline Swarm<3>::Swarm(int num_particles, int distribution, unsigned user_seed,
299  double x_min, double x_max,
300  double y_min, double y_max,
301  double z_min, double z_max) {
302 
303  assert(num_particles > 0);
304  assert(0 <= distribution and distribution <= 2);
305 
306  // set the random engine and generator
307  std::random_device device;
308  std::mt19937 engine { user_seed ? user_seed : device() };
309  std::uniform_real_distribution<double> generator(0.0, 1.0);
310 
311  if (distribution == 0) {
312  // resize field and update coordinates
313  num_local_points_ = num_particles;
314  points_.resize(num_local_points_);
315 
316  for (int i = 0; i < num_particles; i++) {
317  // point coordinates are not always initialized in order
318  // so enforce random number picking sequence
319  double const noise[] = { generator(engine),
320  generator(engine),
321  generator(engine) };
322 
323  points_[i] = Wonton::Point<3>(x_min + (x_max - x_min) * noise[0],
324  y_min + (y_max - y_min) * noise[1],
325  z_min + (z_max - z_min) * noise[2]);
326  }
327 
328  } else {
329  auto const cubic_root = std::pow(num_particles, 1./3.);
330  auto const num_per_dim = static_cast<int>(std::ceil(cubic_root));
331  auto const hx = (x_max - x_min) / (cubic_root - 1);
332  auto const hy = (y_max - y_min) / (cubic_root - 1);
333  auto const hz = (z_max - z_min) / (cubic_root - 1);
334 
335  // resize field
336  num_local_points_ = num_per_dim * num_per_dim * num_per_dim;
337  points_.resize(num_local_points_);
338 
339  // update coordinates
340  int n = 0;
341  for (int i = 0; i < num_per_dim; i++)
342  for (int j = 0; j < num_per_dim; ++j)
343  for (int k = 0; k < num_per_dim; ++k)
344  points_[n++] = Wonton::Point<3>(x_min + i * hx,
345  y_min + j * hy,
346  z_min + k * hz);
347 
348  if (distribution == 2) {
349  for (auto&& current : points_) {
350  // point coordinates are not always initialized in order
351  // so enforce random number picking sequence
352  double const noise[] = { generator(engine),
353  generator(engine),
354  generator(engine) };
355 
356  Wonton::Point<3> copy = current;
357  copy[0] += 0.25 * hx * (2 * noise[0] - 1);
358  copy[1] += 0.25 * hy * (2 * noise[1] - 1);
359  copy[2] += 0.25 * hz * (2 * noise[2] - 1);
360  current = Wonton::Point<3>(std::max(x_min, std::min(x_max, copy[0])),
361  std::max(y_min, std::min(y_max, copy[1])),
362  std::max(z_min, std::min(z_max, copy[2])));
363  }
364  }
365  }
366 }
367 
368 /* -------------------------------------------------------------------------- */
369 template<int dim>
370 template<typename Mesh>
371 Swarm<dim>::Swarm(Mesh const& mesh, Wonton::Entity_kind entity) {
372  switch (entity) {
373  case Wonton::NODE: {
374  num_local_points_ = mesh.num_owned_nodes();
375  points_.resize(num_local_points_);
376  Wonton::Point<dim> coord;
377  for (int i = 0; i < num_local_points_; ++i) {
378  mesh.node_get_coordinates(i, &coord);
379  points_[i] = coord;
380  }
381  } break;
382  case Wonton::CELL: {
383  num_local_points_ = mesh.num_owned_cells();
384  points_.resize(num_local_points_);
385  Wonton::Point<dim> centroid;
386  for (int i = 0; i < num_local_points_; ++i) {
387  mesh.cell_centroid(i, &centroid);
388  points_[i] = centroid;
389  }
390  } break;
391  default: throw std::runtime_error("unsupported entity");
392  }
393 }
394 
395 /* -------------------------------------------------------------------------- */
396 template<int dim>
397 template<typename Mesh>
398 Swarm<dim>::Swarm(std::vector<Mesh*> const& meshes, Wonton::Entity_kind entity) {
399 
400  // resize particle field
401  int n = 0;
402  switch (entity) {
403  case Wonton::NODE: for (auto&& mesh : meshes) n += mesh->num_owned_nodes(); break;
404  case Wonton::CELL: for (auto&& mesh : meshes) n += mesh->num_owned_cells(); break;
405  default: throw std::runtime_error("unsupported entity");
406  }
407 
408  num_local_points_ = n;
409  points_.resize(num_local_points_);
410 
411  n = 0;
412  switch (entity) {
413  case Wonton::NODE: {
414  for (auto&& mesh : meshes) {
415  int const num_nodes = mesh->num_owned_nodes();
416  Wonton::Point<dim> coord;
417  for (int i = 0; i < num_nodes; i++) {
418  mesh->node_get_coordinates(i, &coord);
419  points_[n++] = coord;
420  }
421  }
422  } break;
423  case Wonton::CELL: {
424  for (auto&& mesh : meshes) {
425  int const num_cells = mesh->num_owned_cells();
426  Wonton::Point<dim> centroid;
427  for (int i = 0; i < num_cells; i++) {
428  mesh->cell_centroid(i, &centroid);
429  points_[n++] = centroid;
430  }
431  }
432  } break;
433  default: break;
434  }
435 }
436 
437 /* -------------------------------------------------------------------------- */
438 }} // namespace Portage::Meshfree
439 
440 #endif // PORTAGE_SWARM_SWARM_H_
std::vector< T > vector
Definition: portage.h:238
Swarm(Portage::vector< Wonton::Point< dim >> const &points)
Create a particle field from a given list.
Definition: swarm.h:49
Wonton::Point< OP::dim > centroid(const typename OP::points_t &apts)
Definition: operator.h:616
int num_ghost_particles() const
Get ghost particles count.
Definition: swarm.h:126
counting_iterator end(Entity_kind const kind=Wonton::PARTICLE, Entity_type const type=Wonton::ALL) const
Get an iterator at last element of the particle field.
Definition: swarm.h:174
int space_dimension() const
Get the dimension.
Definition: swarm.h:112
int num_owned_particles() const
Get owned particles count.
Definition: swarm.h:119
~Swarm()=default
Destructor.
Swarm()=default
Create an empty particle field.
void extend_particle_list(std::vector< Wonton::Point< dim >> const &new_pts)
Extend the particle field.
Definition: swarm.h:185
Definition: coredriver.h:42
An effective "mesh" class for a collection disconnected points (particles).
Definition: swarm.h:35
constexpr std::vector< Point< oper::dimension(domain)> > points()
Definition: operator_references.h:29
counting_iterator begin(Entity_kind const kind=Wonton::PARTICLE, Entity_type const type=Wonton::ALL) const
Get an iterator at first element of the particle field.
Definition: swarm.h:160
counting_iterator make_counting_iterator(unsigned int const i)
Definition: portage.h:244
boost::counting_iterator< unsigned int > counting_iterator
Definition: portage.h:243
int num_particles(Wonton::Entity_type type=Wonton::ALL) const
Get particles count.
Definition: swarm.h:134
Wonton::Point< dim > get_particle_coordinates(int index) const
Get the coordinates of the particle.
Definition: swarm.h:148