SPH
Distribution.cpp
Go to the documentation of this file.
2 #include "math/Functional.h"
3 #include "math/Morton.h"
4 #include "math/rng/VectorRng.h"
8 #include "quantities/Quantity.h"
9 #include "quantities/Storage.h"
10 #include "sph/boundary/Boundary.h"
11 #include "system/Profiler.h"
12 #include "thread/ThreadLocal.h"
13 
15 
16 //-----------------------------------------------------------------------------------------------------------
17 // RandomDistribution implementation
18 //-----------------------------------------------------------------------------------------------------------
19 
21  : rng(std::move(rng)) {}
22 
24  : rng(makeRng<UniformRng>(seed)) {}
25 
27  const Size n,
28  const IDomain& domain) const {
29  const Box bounds = domain.getBoundingBox();
30  VectorRng<IRng&> boxRng(*rng);
31  Array<Vector> vecs(0, n);
32  // use homogeneous smoothing lenghs regardless of actual spatial variability of particle concentration
33  const Float volume = domain.getVolume();
34  const Float h = root<3>(volume / n);
35  Size found = 0;
36  for (Size i = 0; i < 1e5 * n && found < n; ++i) {
37  Vector w = boxRng() * bounds.size() + bounds.lower();
38  w[H] = h;
39  if (domain.contains(w)) {
40  vecs.push(w);
41  ++found;
42  }
43  }
44  return vecs;
45 }
46 
47 //-----------------------------------------------------------------------------------------------------------
48 // StratifiedDistribution implementation
49 //-----------------------------------------------------------------------------------------------------------
50 
51 static Float findStep(const Box& bounds, const Size n) {
52  const Vector size = bounds.size();
53  Float step = maxElement(size);
54  Size particlesPerRegion = n;
55  while (particlesPerRegion > 1000) {
56  step /= 2;
57  const Size numRegions = Size(ceil(size[X] / step) * ceil(size[Y] / step) * ceil(size[Z] / step));
58  particlesPerRegion = n / numRegions;
59  }
60  return step;
61 }
62 
64  : rng(makeRng<UniformRng>(seed)) {}
65 
67  const Size n,
68  const IDomain& domain) const {
69  VectorRng<IRng&> boxRng(*rng);
70  Array<Vector> vecs(0, n);
71  const Float volume = domain.getVolume();
72  const Float h = root<3>(volume / n);
73  Size found = 0;
74  const Box bounds = domain.getBoundingBox();
75  const Vector step(findStep(bounds, n));
76  for (Size i = 0; i < 1e5 * n && found < n; ++i) {
77  bounds.iterate(step, [h, &step, &vecs, &found, &domain, &boxRng](const Vector& r) {
78  const Box box(r, r + step);
79  Vector w = boxRng() * box.size() + box.lower();
80  w[H] = h;
81  if (domain.contains(w)) {
82  vecs.push(w);
83  ++found;
84  }
85  });
86  }
87  return vecs;
88 }
89 
90 //-----------------------------------------------------------------------------------------------------------
91 // CubicPacking implementation
92 //-----------------------------------------------------------------------------------------------------------
93 
95  const Size n,
96  const IDomain& domain) const {
97  PROFILE_SCOPE("CubicPacking::generate")
98  SPH_ASSERT(n > 0);
99  const Float volume = domain.getVolume();
100  const Float particleDensity = Float(n) / volume;
101 
102  // interparticle distance based on density
103  const Float h = 1._f / root<3>(particleDensity);
104  SPH_ASSERT(isReal(h));
105 
106  const Box boundingBox = domain.getBoundingBox();
107  const Vector step(h);
108  const Box box(boundingBox.lower() + 0.5_f * step, boundingBox.upper());
109  Array<Vector> vecs;
110  box.iterate(step, [&vecs, &domain, h](Vector&& v) {
111  if (domain.contains(v)) {
112  v[H] = h;
113  vecs.push(std::move(v));
114  }
115  });
116  return vecs;
117 }
118 
119 //-----------------------------------------------------------------------------------------------------------
120 // HexagonalPacking implementation
121 //-----------------------------------------------------------------------------------------------------------
122 
124  : flags(flags) {}
125 
127  : flags(flags)
128  , progressCallback(progressCallback) {}
129 
131  const Size n,
132  const IDomain& domain) const {
134  SPH_ASSERT(n > 0);
135  const Float volume = domain.getVolume();
136  const Float particleDensity = Float(n) / volume;
137 
138  // interparticle distance based on density
139  const Float h = 1._f / root<3>(particleDensity);
140  const Float dx = (flags.has(Options::SPH5_COMPATIBILITY) ? 1._f : 1.1_f) * h;
141  const Float dy = sqrt(3._f) * 0.5_f * dx;
142  const Float dz = sqrt(6._f) / 3._f * dx;
143 
144  const Box boundingBox = domain.getBoundingBox();
145  SPH_ASSERT(boundingBox.volume() > 0._f && boundingBox.volume() < pow<3>(LARGE));
146  const Vector step(dx, dy, dz);
147  const Box box = flags.has(Options::SPH5_COMPATIBILITY)
148  ? boundingBox
149  : Box(boundingBox.lower() + 0.5_f * step, boundingBox.upper());
150  Array<Vector> vecs;
151  const Float deltaX = 0.5_f * dx;
152  const Float deltaY = sqrt(3._f) / 6._f * dx;
153  const Size progressStep = progressCallback ? max(n / 1000, 1u) : Size(-1);
154 
155  box.iterateWithIndices(step, [&](Indices&& idxs, Vector&& v) {
156  if (idxs[2] % 2 == 0) {
157  if (idxs[1] % 2 == 1) {
158  v[X] += deltaX;
159  }
160  } else {
161  if (idxs[1] % 2 == 0) {
162  v[X] += deltaX;
163  }
164  v[Y] += deltaY;
165  }
166  if (domain.contains(v)) {
167  v[H] = h;
168  vecs.push(std::move(v));
169 
170  if (vecs.size() % progressStep == 0) {
171  progressCallback(Float(vecs.size()) / n);
172  }
173  }
174  });
175  if (flags.has(Options::SORTED)) {
176  // sort by Morton code
177  std::sort(vecs.begin(), vecs.end(), [&box](Vector& v1, Vector& v2) {
178  // compute relative coordinates in bounding box
179  const Vector vr1 = (v1 - box.lower()) / box.size();
180  const Vector vr2 = (v2 - box.lower()) / box.size();
181  return morton(vr1) > morton(vr2);
182  });
183  }
184  if (flags.has(Options::CENTER)) {
185  SPH_ASSERT(!vecs.empty());
186  Vector com(0._f);
187  for (const Vector& v : vecs) {
188  com += v;
189  }
190  com /= vecs.size();
191  // match center of mass to center of domain
192  Vector delta = domain.getCenter() - com;
193  delta[H] = 0._f;
194  for (Vector& v : vecs) {
195  v += delta;
196  }
197  }
198  return vecs;
199 }
200 
201 //-----------------------------------------------------------------------------------------------------------
202 // DiehlDistribution implementation
203 //-----------------------------------------------------------------------------------------------------------
204 
206  : params(params) {}
207 
208 namespace {
209 
210 class ForwardingDomain : public IDomain {
211 private:
212  const IDomain& domain;
213 
214 public:
215  explicit ForwardingDomain(const IDomain& domain)
216  : domain(domain) {}
217 
218  virtual Vector getCenter() const override {
219  return domain.getCenter();
220  }
221 
222  virtual Box getBoundingBox() const override {
223  return domain.getBoundingBox();
224  }
225 
226  virtual Float getVolume() const override {
227  return domain.getVolume();
228  }
229 
230  virtual Float getSurfaceArea() const override {
231  return domain.getSurfaceArea();
232  }
233 
234  virtual bool contains(const Vector& v) const override {
235  return domain.contains(v);
236  }
237 
238  virtual void getSubset(ArrayView<const Vector> vs,
239  Array<Size>& output,
240  const SubsetType type) const override {
241  return domain.getSubset(vs, output, type);
242  }
243 
244  virtual void getDistanceToBoundary(ArrayView<const Vector> vs, Array<Float>& distances) const override {
245  domain.getDistanceToBoundary(vs, distances);
246  }
247 
248  virtual void project(ArrayView<Vector> vs, Optional<ArrayView<Size>> indices = NOTHING) const override {
249  domain.project(vs, indices);
250  }
251  virtual void addGhosts(ArrayView<const Vector> vs,
252  Array<Ghost>& ghosts,
253  const Float radius = 2._f,
254  const Float eps = 0.05_f) const override {
255  domain.addGhosts(vs, ghosts, radius, eps);
256  }
257 };
258 
259 } // namespace
260 
270 template <typename TDensity>
271 static auto renormalizeDensity(const IDomain& domain, Size& n, const Size error, TDensity& density) {
273 
274  Float multiplier = n / domain.getVolume();
275  auto actDensity = [&domain, &density, &multiplier](const Vector& v) {
276  if (domain.contains(v)) {
277  return multiplier * density(v);
278  } else {
279  return 0._f;
280  }
281  };
282 
283  Integrator<HaltonQrng> mc(domain);
284  Size cnt = 0;
285  Float particleCnt;
286  for (particleCnt = mc.integrate(actDensity); abs(particleCnt - n) > error;) {
287  const Float ratio = n / max(particleCnt, 1._f);
288  SPH_ASSERT(ratio > EPS, ratio);
289  multiplier *= ratio;
290  particleCnt = mc.integrate(actDensity);
291  if (cnt++ > 100) { // break potential infinite loop
292  break;
293  }
294  }
295  n = Size(particleCnt);
296  // create a different functor that captures multiplier by value, so we can return it from the function
297  return [&domain, &density, multiplier](const Vector& v) {
298  if (domain.contains(v)) {
299  return multiplier * density(v);
300  } else {
301  return 0._f;
302  }
303  };
304 }
305 
310 template <typename TDensity>
311 static Storage generateInitial(const IDomain& domain, const Size N, TDensity&& density) {
312  Box boundingBox = domain.getBoundingBox();
313  VectorPdfRng<HaltonQrng> rng(boundingBox, density);
314 
315  Array<Vector> r(0, N);
316  for (Size i = 0; i < N; ++i) {
317  Vector pos = rng();
318  const Float n = density(pos);
319  pos[H] = 1._f / root<3>(n);
320  SPH_ASSERT(isReal(pos));
321  r.push(pos);
322  }
323 
324  // create a dummy storage so that we can use the functionality of GhostParticles
325  Storage storage;
326  storage.insert<Vector>(QuantityId::POSITION, OrderEnum::ZERO, std::move(r));
327  return storage;
328 }
329 
331  const Size expectedN,
332  const IDomain& domain) const {
334 
335  Size N = expectedN;
336  auto actDensity = renormalizeDensity(domain, N, params.maxDifference, params.particleDensity);
337  SPH_ASSERT(abs(int(N) - int(expectedN)) <= int(params.maxDifference));
338 
339  // generate initial particle positions
340  Storage storage = generateInitial(domain, N, actDensity);
342 
343  GhostParticles bc(makeAuto<ForwardingDomain>(domain), 2._f, EPS);
344 
345  UniformGridFinder finder;
346  ThreadLocal<Array<NeighbourRecord>> neighs(scheduler);
347  finder.build(scheduler, r);
348 
349  const Float correction = params.strength / (1._f + params.small);
350  // radius of search, does not have to be equal to radius of used SPH kernel
351  const Float kernelRadius = 2._f;
352 
353  Array<Vector> deltas(N);
354  for (Size k = 0; k < params.numOfIters; ++k) {
355  VerboseLogGuard guard("DiehlDistribution::generate - iteration " + std::to_string(k));
356 
357  // notify caller, if requested
358  if (params.onIteration && !params.onIteration(k, r)) {
359  break;
360  }
361 
362  // gradually decrease the strength of particle dislocation
363  const Float converg = 1._f / sqrt(Float(k + 1));
364 
365  // add ghost particles
366  bc.initialize(storage);
367 
368  // reconstruct finder to allow for variable topology of particles (we need to reset the internal
369  // arrayview as we added ghosts)
370  finder.build(scheduler, r);
371 
372  // clean up the previous displacements
373  deltas.fill(Vector(0._f));
374 
375  auto lambda = [&](const Size i, Array<NeighbourRecord>& neighsTl) {
376  const Float rhoi = actDensity(r[i]); // average particle density
377  // average interparticle distance at given point
378  const Float neighbourRadius = kernelRadius / root<3>(rhoi);
379  finder.findAll(i, neighbourRadius, neighsTl);
380 
381  for (Size j = 0; j < neighsTl.size(); ++j) {
382  const Size k = neighsTl[j].index;
383  const Vector diff = r[k] - r[i];
384  const Float lengthSqr = getSqrLength(diff);
385  // for ghost particles, just copy the density (density outside the domain is always 0)
386  const Float rhok = (k >= N) ? rhoi : actDensity(r[k]);
387  if (rhoi == 0._f || rhok == 0._f) {
388  // outside of the domain? do not move
389  continue;
390  }
391  // average kernel radius to allow for the gradient of particle density
392  const Float h = kernelRadius * (0.5_f / root<3>(rhoi) + 0.5_f / root<3>(rhok));
393  if (lengthSqr > h * h || lengthSqr == 0) {
394  continue;
395  }
396  const Float hSqrInv = 1._f / (h * h);
397  const Float length = getLength(diff);
398  SPH_ASSERT(length != 0._f);
399  const Vector diffUnit = diff / length;
400  const Float t =
401  converg * h *
402  (params.strength / (params.small + getSqrLength(diff) * hSqrInv) - correction);
403  deltas[i] += diffUnit * min(t, h); // clamp the displacement to particle distance
404  SPH_ASSERT(isReal(deltas[i]));
405  }
406  deltas[i][H] = 0._f; // do not affect smoothing lengths
407  };
408  parallelFor(scheduler, neighs, 0, N, 100, lambda);
409 
410  // apply the computed displacements; note that r might be larger than deltas due to ghost particles -
411  // we don't need to move them
412  for (Size i = 0; i < deltas.size(); ++i) {
413  r[i] -= deltas[i];
414  }
415 
416  // remove the ghosts
417  bc.finalize(storage);
418 
419  // project particles outside of the domain to the boundary
420  // (there shouldn't be any, but it may happen for large strengths / weird boundaries)
421  domain.project(r);
422  }
423 
424 #ifdef SPH_DEBUG
425  for (Size i = 0; i < N; ++i) {
426  SPH_ASSERT(isReal(r[i]) && r[i][H] > 1.e-20_f);
427  }
428 #endif
429  // extract the buffers from the storage
430  Array<Vector> positions = std::move(storage.getValue<Vector>(QuantityId::POSITION));
431  return positions;
432 }
433 
434 //-----------------------------------------------------------------------------------------------------------
435 // ParametrizedSpiralingDistribution implementation
436 //-----------------------------------------------------------------------------------------------------------
437 
439  : seed(seed) {}
440 
442  const Size n,
443  const IDomain& domain) const {
444  const Vector center = domain.getCenter();
445  const Float volume = domain.getVolume();
446  const Box bbox = domain.getBoundingBox();
447  const Float R = 0.5_f * maxElement(bbox.size());
448 
449  // interparticle distance based on density
450  const Float h = root<3>(volume / n);
451  const Size numShells = Size(R / h);
452  Array<Float> shells(numShells);
453  Float total = 0._f;
454  for (Size i = 0; i < numShells; ++i) {
455  shells[i] = sqr((i + 1) * h);
456  total += shells[i];
457  }
458  SPH_ASSERT(isReal(total));
459 
460  Float mult = Float(n) / total;
461  for (Size i = 0; i < numShells; ++i) {
462  shells[i] *= mult;
463  }
464 
465  Array<Vector> pos;
466  Float phi = 0._f;
467  Size shellIdx = 0;
468  UniformRng rng(seed);
469  for (Float r = h; r <= R; r += h, shellIdx++) {
470  Vector dir = sampleUnitSphere(rng);
471  Float rot = 2._f * PI * rng();
472  AffineMatrix rotator = AffineMatrix::rotateAxis(dir, rot);
473  const Size m = Size(ceil(shells[shellIdx]));
474  for (Size k = 1; k < m; ++k) {
475  const Float hk = -1._f + 2._f * Float(k) / m;
476  const Float theta = acos(hk);
477  phi += 3.8_f / sqrt(m * (1._f - sqr(hk)));
478  Vector v = center + rotator * sphericalToCartesian(r, theta, phi);
479  if (domain.contains(v)) {
480  v[H] = h; // 0.66_f * sqrt(sphereSurfaceArea(r) / m);
481  SPH_ASSERT(isReal(v));
482  pos.push(v);
483  }
484  }
485  }
486  return pos;
487 }
488 //-----------------------------------------------------------------------------------------------------------
489 // LinearDistribution implementation
490 //-----------------------------------------------------------------------------------------------------------
491 
493  const Size n,
494  const IDomain& domain) const {
495  const Float center = domain.getCenter()[X];
496  const Float radius = 0.5_f * domain.getBoundingBox().size()[X];
497  Array<Vector> vs(0, n);
498  const Float dx = 2._f * radius / (n - 1);
499  for (Size i = 0; i < n; ++i) {
500  const Float x = center - radius + (2._f * radius * i) / (n - 1);
501  vs.push(Vector(x, 0._f, 0._f, 1.5_f * dx)); // smoothing length = interparticle distance
502  }
503  return vs;
504 }
505 
INLINE bool isReal(const AntisymmetricTensor &t)
#define SPH_ASSERT(x,...)
Definition: Assert.h:94
NAMESPACE_SPH_BEGIN
Definition: BarnesHut.cpp:13
Boundary conditions.
const float radius
Definition: CurveDialog.cpp:18
Filling spatial domain with SPH particles.
Object defining computational domain.
SubsetType
Definition: Domain.h:16
INLINE Float maxElement(const T &value)
Returns maximum element, simply the value iself by default.
Definition: Generic.h:29
uint32_t Size
Integral type used to index arrays (by default).
Definition: Globals.h:16
double Float
Precision used withing the code. Use Float instead of float or double where precision is important.
Definition: Globals.h:13
#define VERBOSE_LOG
Helper macro, creating.
Definition: Logger.h:242
constexpr INLINE T max(const T &f1, const T &f2)
Definition: MathBasic.h:20
NAMESPACE_SPH_BEGIN constexpr INLINE T min(const T &f1, const T &f2)
Minimum & Maximum value.
Definition: MathBasic.h:15
constexpr Float EPS
Definition: MathUtils.h:30
constexpr INLINE T sqr(const T &f) noexcept
Return a squared value.
Definition: MathUtils.h:67
INLINE T sqrt(const T f)
Return a squared root of a value.
Definition: MathUtils.h:78
constexpr INLINE Float pow< 3 >(const Float v)
Definition: MathUtils.h:132
INLINE Float root< 3 >(const Float f)
Definition: MathUtils.h:105
INLINE T acos(const T f)
Definition: MathUtils.h:306
INLINE auto ceil(const T &f)
Definition: MathUtils.h:351
INLINE auto abs(const T &f)
Definition: MathUtils.h:276
constexpr Float PI
Mathematical constants.
Definition: MathUtils.h:361
constexpr Float LARGE
Definition: MathUtils.h:34
#define UNUSED(x)
Definition: Object.h:37
#define NAMESPACE_SPH_END
Definition: Object.h:12
Wrapper of type value of which may or may not be present.
const NothingType NOTHING
Definition: Optional.h:16
Tool to measure time spent in functions and profile the code.
#define PROFILE_SCOPE(name)
Definition: Profiler.h:175
@ POSITION
Positions (velocities, accelerations) of particles, always a vector quantity,.
Holder of quantity values and their temporal derivatives.
@ ZERO
Quantity without derivatives, or "zero order" of quantity.
INLINE Vector sampleUnitSphere(TRng &rng)
Generates a random position on a unit sphere.
Definition: Rng.h:166
AutoPtr< RngWrapper< TRng > > makeRng(TArgs &&... args)
Definition: Rng.h:112
INLINE void parallelFor(IScheduler &scheduler, const Size from, const Size to, TFunctor &&functor)
Executes a functor concurrently from all available threads.
Definition: Scheduler.h:98
Container for storing particle quantities and materials.
constexpr int N
Template for thread-local storage.
Simple algorithm for finding nearest neighbours using spatial partitioning of particles.
Objects for generating random vectors.
INLINE Float getLength(const Vector &v)
Returns the length of the vector. Enabled only for vectors of floating-point precision.
Definition: Vector.h:579
INLINE Float getSqrLength(const Vector &v)
Definition: Vector.h:574
BasicVector< Float > Vector
Definition: Vector.h:539
INLINE Vector sphericalToCartesian(const Float r, const Float theta, const Float phi)
Constructs a vector from spherical coordinates.
Definition: Vector.h:788
@ H
Definition: Vector.h:25
@ Y
Definition: Vector.h:23
@ X
Definition: Vector.h:22
@ Z
Definition: Vector.h:24
static AffineMatrix rotateAxis(const Vector &axis, const Float angle)
Definition: AffineMatrix.h:159
Object providing safe access to continuous memory of data.
Definition: ArrayView.h:17
Generic dynamically allocated resizable storage.
Definition: Array.h:43
INLINE void push(U &&u)
Adds new element to the end of the array, resizing the array if necessary.
Definition: Array.h:306
void fill(const T &t)
Sets all elements of the array to given value.
Definition: Array.h:187
INLINE TCounter size() const noexcept
Definition: Array.h:193
Helper object defining three-dimensional interval (box).
Definition: Box.h:17
INLINE const Vector & lower() const
Returns lower bounds of the box.
Definition: Box.h:82
INLINE const Vector & upper() const
Returns upper bounds of the box.
Definition: Box.h:94
INLINE Vector size() const
Returns box dimensions.
Definition: Box.h:106
void iterateWithIndices(const Vector &step, TFunctor &&functor) const
Execute functor for all possible values of vector (with constant stepping), passing auxiliary indices...
Definition: Box.h:182
INLINE Float volume() const
Returns the volume of the box.
Definition: Box.h:118
void iterate(const Vector &step, TFunctor &&functor) const
Execute functor for all possible values of vector (with constant stepping)
Definition: Box.h:168
virtual Array< Vector > generate(IScheduler &scheduler, const Size n, const IDomain &domain) const override
Generates the requested number of particles in the domain.
DiehlDistribution(const DiehlParams &params)
Constructs the distribution.
virtual Array< Vector > generate(IScheduler &scheduler, const Size n, const IDomain &domain) const override
Returns generated particle distribution.
virtual Size findAll(const Size index, const Float radius, Array< NeighbourRecord > &neighbours) const override
Finds all neighbours within given radius from the point given by index.
constexpr INLINE bool has(const TEnum flag) const
Checks if the object has a given flag.
Definition: Flags.h:77
Adds ghost particles symmetrically for each SPH particle close to boundary.
Definition: Boundary.h:71
HexagonalPacking(const Flags< Options > flags=Options::CENTER)
virtual Array< Vector > generate(IScheduler &scheduler, const Size n, const IDomain &domain) const override
Generates the requested number of particles in the domain.
@ SPH5_COMPATIBILITY
Generates the grid to match code SPH5 for 1-1 comparison.
Base class for computational domains.
Definition: Domain.h:29
virtual Float getSurfaceArea() const =0
Returns the surface area of the domain.
virtual void getSubset(ArrayView< const Vector > vs, Array< Size > &output, const SubsetType type) const =0
Returns an array of indices, marking vectors with given property by their index.
virtual void getDistanceToBoundary(ArrayView< const Vector > vs, Array< Float > &distances) const =0
Returns distances of particles lying close to the boundary.
virtual Box getBoundingBox() const =0
Returns the bounding box of the domain.
virtual Float getVolume() const =0
Returns the total volume of the domain.
virtual void project(ArrayView< Vector > vs, Optional< ArrayView< Size >> indices=NOTHING) const =0
Projects vectors outside of the domain onto its boundary.
virtual void addGhosts(ArrayView< const Vector > vs, Array< Ghost > &ghosts, const Float eta=2._f, const Float eps=0.05_f) const =0
Duplicates positions located close to the boundary, placing copies ("ghosts") symmetrically to the ot...
virtual bool contains(const Vector &v) const =0
Checks if the given point lies inside the domain.
virtual Vector getCenter() const =0
Returns the center of the domain.
Interface that allows unified implementation of sequential and parallelized versions of algorithms.
Definition: Scheduler.h:27
void build(IScheduler &scheduler, ArrayView< const Vector > points, Flags< FinderFlag > flags=FinderFlag::MAKE_RANK)
Constructs the struct with an array of vectors.
Helper object for storing three (possibly four) int or bool values.
Definition: Indices.h:16
Object for integrating a generic three-dimensional scalar function.
Definition: Functional.h:36
virtual Array< Vector > generate(IScheduler &scheduler, const Size n, const IDomain &domain) const override
Generates the requested number of particles in the domain.
Wrapper of type value of which may or may not be present.
Definition: Optional.h:23
virtual Array< Vector > generate(IScheduler &scheduler, const Size n, const IDomain &domain) const override
Generates the requested number of particles in the domain.
ParametrizedSpiralingDistribution(const Size seed)
virtual Array< Vector > generate(IScheduler &scheduler, const Size n, const IDomain &domain) const override
Generates the requested number of particles in the domain.
RandomDistribution(AutoPtr< IRng > &&rng)
Creates a random distribution given random number generator.
Container storing all quantities used within the simulations.
Definition: Storage.h:230
Quantity & insert(const QuantityId key, const OrderEnum order, const TValue &defaultValue)
Creates a quantity in the storage, given its key, value type and order.
Definition: Storage.cpp:270
Array< TValue > & getValue(const QuantityId key)
Retrieves a quantity values from the storage, given its key and value type.
Definition: Storage.cpp:191
virtual Array< Vector > generate(IScheduler &scheduler, const Size n, const IDomain &domain) const override
Generates the requested number of particles in the domain.
StratifiedDistribution(const Size seed)
Template for storing a copy of a value for every thread in given scheduler.
Definition: ThreadLocal.h:36
Finder projecting a uniform grid on the particles.
Definition: UniformGrid.h:14
Random number generator with uniform distribution.
Definition: Rng.h:16
Generic generator of random vectors using sampling with given PDF.
Definition: VectorRng.h:60
Wrapper for generating random vectors.
Definition: VectorRng.h:18
RAII guard writing called functions and their durations to a special verbose logger.
Definition: Logger.h:224
Overload of std::swap for Sph::Array.
Definition: Array.h:578
Parameters of DiehlDistribution.
Definition: Distribution.h:108
Float small
Normalization value to prevent division by zero for overlapping particles.
Definition: Distribution.h:136
DensityFunc particleDensity
Function specifies the particle density in space.
Definition: Distribution.h:115
Size numOfIters
Number of iterations.
Definition: Distribution.h:126
Float strength
Magnitude of a repulsive force between particles that moves them to their final locations.
Definition: Distribution.h:131
Function< bool(Size iter, ArrayView< const Vector > r)> onIteration
Optional callback executed once every iteration.
Definition: Distribution.h:143
Size maxDifference
Allowed difference between the expected and actual number of particles.
Definition: Distribution.h:120