SPH
AggregateSolver.cpp
Go to the documentation of this file.
2 #include "gravity/Collision.h"
3 #include "gravity/IGravity.h"
4 #include "io/Logger.h"
5 #include "post/Analysis.h"
6 #include "quantities/Quantity.h"
7 #include "quantities/Storage.h"
8 #include "sph/Materials.h"
9 #include "system/Factory.h"
10 #include "system/Statistics.h"
11 #include "thread/CheckFunction.h"
12 #include <mutex>
13 
15 
16 const Vector MAX_SPIN = Vector(0.1_f);
17 
22 class Aggregate : public Noncopyable {
23 private:
24  RawPtr<Storage> storage;
25 
28  FlatSet<Size> idxs;
29 
32  Size persistentId;
33 
34 public:
36  Aggregate() = default;
37 
39  Aggregate(Storage& storage, const Size particleIdx)
40  : storage(addressOf(storage)) {
41  idxs.insert(particleIdx);
42  persistentId = particleIdx;
43  }
44 
45  explicit Aggregate(Storage& storage, IndexSequence seq)
46  : storage(addressOf(storage)) {
47  for (Size i : seq) {
48  idxs.insert(i);
49  }
50  persistentId = *seq.begin();
51  }
52 
53  void add(const Size idx) {
54  SPH_ASSERT(!idxs.contains(idx));
55  idxs.insert(idx);
56  // this->fixVelocities();
57  }
58 
59  void remove(const Size idx) {
60  idxs.erase(idxs.find(idx));
61  }
62 
63  void clear() {
64  idxs.clear();
65  }
66 
67  bool contains(const Size idx) const {
68  return idxs.find(idx) != idxs.end();
69  }
70 
71  Size getId() const {
72  return persistentId;
73  }
74 
76  void spin() {
77  if (this->size() == 1) {
78  return;
79  }
80 
85 
87  Float m_ag = 0._f;
88  Vector r_com(0._f);
89  Vector v_com(0._f);
90  for (Size i : idxs) {
91  r_com += m[i] * r[i];
92  v_com += m[i] * v[i];
93  m_ag += m[i];
94  }
95  r_com /= m_ag;
96  v_com /= m_ag;
97  SPH_ASSERT(isReal(r_com) && getLength(r_com) < LARGE, r_com);
98 
99  const Vector omega = clamp(w[persistentId], -MAX_SPIN, MAX_SPIN);
100  AffineMatrix rotationMatrix = AffineMatrix::identity();
101 
102  if (alpha[persistentId] != Vector(0._f)) {
103  Vector dir;
104  Float angle;
105  tieToTuple(dir, angle) = getNormalizedWithLength(alpha[persistentId]);
106  alpha[persistentId] = Vector(0._f);
107  rotationMatrix = AffineMatrix::rotateAxis(dir, angle);
108  }
109 
110  for (Size i : idxs) {
111  SPH_ASSERT(alpha[i] == Vector(0._f));
112  Float h = r[i][H];
113  r[i] = r_com + rotationMatrix * (r[i] - r_com);
114  v[i] += cross(omega, r[i] - r_com);
115  r[i][H] = h;
116  v[i][H] = 0._f;
117  }
118  }
119 
121  void integrate() {
122  SPH_ASSERT(this->size() > 0);
123  if (this->size() == 1) {
124  return;
125  }
126  ArrayView<Vector> r, v, dv;
127  tie(r, v, dv) = storage->getAll<Vector>(QuantityId::POSITION);
129 
130  Float m_ag = 0._f;
131  Vector r_com(0._f);
132  Vector v_com(0._f);
133  Vector dv_com(0._f);
134  for (Size i : idxs) {
135  dv_com += m[i] * dv[i];
136  v_com += m[i] * v[i];
137  r_com += m[i] * r[i];
138  m_ag += m[i];
139  }
140  dv_com /= m_ag;
141  v_com /= m_ag;
142  r_com /= m_ag;
143 
144  Vector L(0._f);
145  SymmetricTensor I = SymmetricTensor::null(); // inertia tensor
146  Vector M(0._f); // torque
147  for (Size i : idxs) {
148  const Vector dr = r[i] - r_com;
149  L += m[i] * cross(dr, v[i] - v_com);
150  I += m[i] * (SymmetricTensor::identity() * getSqrLength(dr) - symmetricOuter(dr, dr));
151  M += m[i] * cross(dr, dv[i] - dv_com);
152  }
153 
154  ArrayView<Vector> w, dw;
155  tie(w, dw) = storage->getAll<Vector>(QuantityId::ANGULAR_FREQUENCY);
156 
157 
158  const bool singular = I.determinant() == 0._f;
159  Vector omega = Vector(0._f);
160  if (!singular) {
161 
162  omega = I.inverse() * L;
163 
164  // const Vector w_loc = Em.transpose() * w[index];
165 
166  // compute the change of angular velocity using Euler's equations
167  // dw[index] = I_inv * (M - cross(w[index], I * w[index]));
168  }
169 
170 
171  /*const SymmetricTensor I = Post::getInertiaTensor(m, r, r_com);
172  (void)I;*/
173 
174  ArrayView<Vector> alpha, dalpha;
175  tie(alpha, dalpha) = storage->getAll<Vector>(QuantityId::PHASE_ANGLE);
176 
177  for (Size i : idxs) {
178  v[i] = v_com;
179  dv[i] = dv_com;
180  w[i] = omega;
181 
182  SPH_ASSERT(alpha[i] == Vector(0._f));
183  }
184  alpha[persistentId] = Vector(0._f);
185  dalpha[persistentId] = w[persistentId];
186  }
187 
188  // replaces unordered motion with bulk velocity + rotation
189  void fixVelocities() {
190  const Integrals ag = this->getIntegrals();
191  ArrayView<Vector> r, v, dv;
192  tie(r, v, dv) = storage->getAll<Vector>(QuantityId::POSITION);
193  for (Size i : idxs) {
194  v[i] = ag.v_com + cross(ag.omega, r[i] - ag.r_com);
195  v[i][H] = 0._f;
196  }
197  }
198 
199  Float mass() const {
201  Float m_ag = 0._f;
202  for (Size i : idxs) {
203  m_ag += m[i];
204  }
205  return m_ag;
206  }
207 
208  Vector velocity() const {
209  ArrayView<Vector> r, v, dv;
210  tie(r, v, dv) = storage->getAll<Vector>(QuantityId::POSITION);
212 
213  Float m_ag = 0._f;
214  Vector v_com(0._f);
215  for (Size i : idxs) {
216  v_com += m[i] * v[i];
217  m_ag += m[i];
218  }
219  v_com /= m_ag;
220  return v_com;
221  }
222 
223  void displace(const Vector& offset) {
224  SPH_ASSERT(offset[H] == 0._f);
225 
227  for (Size i : idxs) {
228  r[i] += offset;
229  }
230  }
231 
232 
233  Size size() const {
234  return idxs.size();
235  }
236 
237  bool empty() const {
238  return idxs.empty();
239  }
240 
241  auto begin() const {
242  return idxs.begin();
243  }
244 
245  auto end() const {
246  return idxs.end();
247  }
248 
249 private:
250  struct Integrals {
251  Float m;
252  Vector r_com;
253  Vector v_com;
254  Vector omega;
255  SymmetricTensor I;
256  Vector L;
257  };
258 
259  Integrals getIntegrals() const {
260  ArrayView<Vector> r, v, dv;
261  tie(r, v, dv) = storage->getAll<Vector>(QuantityId::POSITION);
263 
264  Float m_ag = 0._f;
265  Vector r_com(0._f);
266  Vector v_com(0._f);
267  for (Size i : idxs) {
268  v_com += m[i] * v[i];
269  r_com += m[i] * r[i];
270  m_ag += m[i];
271  }
272  v_com /= m_ag;
273  r_com /= m_ag;
274 
275  Vector L(0._f);
276  SymmetricTensor I = SymmetricTensor::null(); // inertia tensor
277  for (Size i : idxs) {
278  const Vector dr = r[i] - r_com;
279  L += m[i] * cross(dr, v[i] - v_com);
280  I += m[i] * (SymmetricTensor::identity() * getSqrLength(dr) - symmetricOuter(dr, dr));
281  }
282 
283  Integrals value;
284  value.m = m_ag;
285  value.r_com = r_com;
286  value.v_com = v_com;
287  value.I = I;
288  value.L = L;
289 
290  if (I.determinant() != 0._f) {
291  value.omega = clamp(I.inverse() * L, -MAX_SPIN, MAX_SPIN);
292  } else {
293  value.omega = Vector(0._f);
294  }
295  return value;
296  }
297 };
298 
303 private:
305  Array<Aggregate> aggregates;
306 
311  Array<RawPtr<Aggregate>> particleToAggregate;
312 
314  mutable std::mutex mutex;
315 
316 public:
317  AggregateHolder(Storage& storage, const AggregateEnum source) {
318  // create an aggregate for each particle, even if its empty, so we can add particles to it later
319  // without reallocations
320  const Size n = storage.getParticleCnt();
321  aggregates.resize(n);
322 
323  switch (source) {
325  for (Size i = 0; i < n; ++i) {
326  aggregates[i] = Aggregate(storage, i);
327  particleToAggregate.emplaceBack(addressOf(aggregates[i]));
328  }
329  break;
330  }
332  for (Size matId = 0; matId < storage.getMaterialCnt(); ++matId) {
333  MaterialView mat = storage.getMaterial(matId);
334  IndexSequence seq = mat.sequence();
335  // need to create all aggregates to storage pointer to storage
336  for (Size i : seq) {
337  aggregates[i] = Aggregate(storage, i);
338  aggregates[i].clear();
339  }
340 
341  const Size idx = *seq.begin();
342  aggregates[idx] = Aggregate(storage, seq);
343 
344  for (Size i = 0; i < seq.size(); ++i) {
345  particleToAggregate.emplaceBack(addressOf(aggregates[idx]));
346  }
347  }
348  break;
349  }
350  default:
352  }
353  }
354 
356  Aggregate& getAggregate(const Size particleIdx) {
357  Aggregate& ag = *particleToAggregate[particleIdx];
358  SPH_ASSERT(ag.contains(particleIdx));
359  return ag;
360  }
361 
363  const Aggregate& getAggregate(const Size particleIdx) const {
364  const Aggregate& ag = *particleToAggregate[particleIdx];
365  SPH_ASSERT(ag.contains(particleIdx));
366  return ag;
367  }
368 
370  /*merge(Aggregate& ag1, Aggregate& ag2) {
371  CHECK_FUNCTION(CheckFunction::NON_REENRANT);
372  std::unique_lock<std::mutex> lock(mutex);
373 
374  if (ag1.size() > ag1.size()) {
375  ag1.merge(ag2);
376  } else {
377  ag2.merge(ag1);
378  }
379  // SPH_ASSERT(ag1.contains(ag1.getId()));
380  // relink pointers of ag2 particles to ag1
381  for (Size i : ag2) {
382  particleToAggregate[i] = addressOf(ag1);
383  }
384 
385  // remove all particles from ag2; we actually keep the aggregate in the holder (with zero particles)
386  // for simplicity, otherwise we would have to shift the aggregates in the array, invalidating the
387  // pointers held in particleToAggregate.
388  ag2.clear();
389  SPH_ASSERT(ag2.size() == 0);
390  }*/
391 
392  void merge(Aggregate& ag1, Aggregate& ag2) {
393  if (ag1.size() < ag2.size()) {
394  this->merge(ag2, ag1);
395  return;
396  }
397 
398  SPH_ASSERT(ag1.size() >= ag2.size());
399  // accumulate single particle
400  if (ag2.size() == 1) {
401  const Size id = ag2.getId();
402  ag1.add(id);
403  particleToAggregate[id] = &ag1;
404  ag2.clear();
405  } else {
406 
407  // break the aggregate
408  this->disband(ag2);
409  }
410 
411  ag1.fixVelocities();
412  }
413 
414  void separate(Aggregate& ag, const Size idx) {
415 
416  if (ag.getId() == idx) {
417  return;
418  }
419 
420  aggregates[idx].add(idx);
421  particleToAggregate[idx] = addressOf(aggregates[idx]);
422  ag.remove(idx);
423  ag.fixVelocities();
424  }
425 
426  void disband(Aggregate& ag) {
427  const Size mainId = ag.getId();
428  for (Size i : ag) {
429  // put the particle back to its original aggregate
430  if (i != mainId) {
431  aggregates[i].add(i);
432  particleToAggregate[i] = addressOf(aggregates[i]);
433  }
434  }
435 
436  ag.clear();
437  ag.add(mainId);
438  }
439 
440  void spin() {
441  // std::unique_lock<std::mutex> lock(mutex);
442  for (Aggregate& ag : aggregates) {
443  if (!ag.empty()) {
444  ag.spin();
445  }
446  }
447  }
448 
450  void integrate() {
451  // std::unique_lock<std::mutex> lock(mutex);
452 
453  for (Aggregate& ag : aggregates) {
454  if (!ag.empty()) {
455  ag.integrate();
456  }
457  }
458  }
459 
460  Optional<Size> getAggregateId(const Size particleIdx) const {
461  std::unique_lock<std::mutex> lock(mutex);
462  const Aggregate& ag = getAggregate(particleIdx);
463  if (ag.size() > 1) {
464  return ag.getId();
465  } else {
466  return NOTHING;
467  }
468  }
469 
470  virtual Size count() const override {
471  std::unique_lock<std::mutex> lock(mutex);
472  Size cnt = 0;
473  for (const Aggregate& ag : aggregates) {
474  if (ag.size() > 1) {
475  cnt++;
476  }
477  }
478  return cnt;
479  }
480 };
481 
483 private:
484  Float bounceLimit;
485 
486  struct {
489  } restitution;
490 
495 
496 public:
497  explicit AggregateCollisionHandler(const RunSettings& settings) {
498  bounceLimit = settings.get<Float>(RunSettingsId::COLLISION_BOUNCE_MERGE_LIMIT);
499  restitution.n = settings.get<Float>(RunSettingsId::COLLISION_RESTITUTION_NORMAL);
500  restitution.t = settings.get<Float>(RunSettingsId::COLLISION_RESTITUTION_TANGENT);
501  }
502 
503  virtual void initialize(Storage& storage) override {
504  holder = dynamicCast<AggregateHolder>(storage.getUserData().get());
505  SPH_ASSERT(holder);
506 
507  r = storage.getValue<Vector>(QuantityId::POSITION);
508  v = storage.getDt<Vector>(QuantityId::POSITION);
509  m = storage.getValue<Float>(QuantityId::MASS);
510  }
511 
512  virtual CollisionResult collide(const Size i, const Size j, FlatSet<Size>& UNUSED(toRemove)) override {
513  // this function SHOULD be called by one thread only, so we do not need to lock here
515 
516  Aggregate& ag_i = holder->getAggregate(i);
517  Aggregate& ag_j = holder->getAggregate(j);
518  if (addressOf(ag_i) == addressOf(ag_j)) {
519  // particles belong to the same aggregate, do not process collision
520  return CollisionResult::NONE;
521  }
522 
523  const Vector v_com = weightedAverage(v[i], m[i], v[j], m[j]);
524  const Vector dr = getNormalized(r[i] - r[j]);
525  v[i] = this->reflect(v[i], v_com, -dr);
526  v[j] = this->reflect(v[j], v_com, dr);
527  v[i][H] = v[j][H] = 0._f;
528 
529  /*if (getSqrLength(v[i] - ag_i.velocity()) > sqr(MAX_STRAIN)) {
530  holder->separate(ag_i, i);
531  }
532 
533  if (getSqrLength(v[j] - ag_j.velocity()) > sqr(MAX_STRAIN)) {
534  holder->separate(ag_j, j);
535  }*/
536 
537  // particle are moved back after collision handling, so we need to make sure they have correct
538  // velocities to not move them away from the aggregate
539  ag_i.fixVelocities();
540  ag_j.fixVelocities();
541 
542  /*
543  if (ag_i.size() > ag_j.size()) {
544  holder->disband(ag_j);
545  } else {
546  holder->disband(ag_i);
547  }*/
548 
549  // if the particles are gravitationally bound, add them to the aggregate, otherwise bounce
550  if (areParticlesBound(m[i] + m[j], r[i][H] + r[j][H], v[i] - v[j], bounceLimit)) {
551  // add to aggregate
552  holder->merge(ag_i, ag_j);
553 
554  return CollisionResult::NONE;
555 
556 
557  } else {
558  holder->separate(ag_i, i);
559  holder->separate(ag_j, j);
560 
562  }
563  }
564 
565 private:
567  INLINE Vector reflect(const Vector& v, const Vector& v_com, const Vector& dir) const {
568  SPH_ASSERT(almostEqual(getSqrLength(dir), 1._f), dir);
569  const Vector v_rel = v - v_com;
570  const Float proj = dot(v_rel, dir);
571  const Vector v_t = v_rel - proj * dir;
572  const Vector v_n = proj * dir;
573 
574  // flip the orientation of normal component (bounce) and apply coefficients of restitution
575  return restitution.t * v_t - restitution.n * v_n + v_com;
576  }
577 };
578 
580 private:
584 
586 
587 public:
588  explicit AggregateOverlapHandler(const RunSettings& settings)
589  : handler(settings) {}
590 
591  virtual void initialize(Storage& storage) override {
592  holder = dynamicCast<AggregateHolder>(storage.getUserData().get());
593  SPH_ASSERT(holder);
594 
595  handler.initialize(storage);
596  m = storage.getValue<Float>(QuantityId::MASS);
597  r = storage.getValue<Vector>(QuantityId::POSITION);
598  }
599 
600  virtual bool overlaps(const Size i, const Size j) const override {
601  // this is called from multiple threads, but we are not doing any merging here
602  const Aggregate& ag_i = holder->getAggregate(i);
603  const Aggregate& ag_j = holder->getAggregate(j);
604  if (addressOf(ag_i) == addressOf(ag_j)) {
605  // false as in "overlap does not have to be handled"
606  return false;
607  }
608  return true;
609  }
610 
611  virtual void handle(const Size i, const Size j, FlatSet<Size>& toRemove) override {
612  // this function SHOULD be called by one thread only, so we do not need to lock here
614 
615  Aggregate& ag_i = holder->getAggregate(i);
616  Aggregate& ag_j = holder->getAggregate(j);
617 
618  // even though we previously checked for this in function overlaps, the particles might have been
619  // assinged to the same aggregate during collision processing, so we have to check again
620  if (addressOf(ag_i) == addressOf(ag_j)) {
621  return;
622  }
623 
624  Vector dir;
625  Float dist;
626  tieToTuple(dir, dist) = getNormalizedWithLength(r[i] - r[j]);
627  dir[H] = 0._f; // don't mess up radii
628 
629  if (dist > r[i][H] + r[j][H]) {
630  // not a real overlap
631  return;
632  }
633 
634  const Float m1 = ag_i.mass();
635  const Float m2 = ag_j.mass();
636  const Float x1 = (r[i][H] + r[j][H] - dist) / (1._f + m1 / m2);
637  const Float x2 = m1 / m2 * x1;
638  ag_i.displace(dir * x1);
639  ag_j.displace(-dir * x2);
640 
641  handler.collide(i, j, toRemove);
642  }
643 };
644 
646  : HardSphereSolver(scheduler,
647  settings,
648  Factory::getGravity(settings),
650  makeAuto<AggregateOverlapHandler>(settings)) {}
651 // makeAuto<RepelHandler<AggregateCollisionHandler>>(settings)) {}
652 
653 
655 
657  holder->spin();
658  HardSphereSolver::integrate(storage, stats);
659  holder->integrate();
660 
661  // storage IDs and aggregate stats
662  ArrayView<Size> aggregateIds = storage.getValue<Size>(QuantityId::AGGREGATE_ID);
663  for (Size i = 0; i < aggregateIds.size(); ++i) {
664  aggregateIds[i] = holder->getAggregateId(i).valueOr(Size(-1));
665  }
666  stats.set(StatisticsId::AGGREGATE_COUNT, int(holder->count()));
667 }
668 
669 void AggregateSolver::collide(Storage& storage, Statistics& stats, const Float dt) {
670  holder->spin();
671  HardSphereSolver::collide(storage, stats, dt);
672  holder->integrate();
673 }
674 
675 void AggregateSolver::create(Storage& storage, IMaterial& material) const {
676  HardSphereSolver::create(storage, material);
677 
681 }
682 
684  holder = makeShared<AggregateHolder>(storage, source);
685  storage.setUserData(holder);
686 }
687 
INLINE bool almostEqual(const AffineMatrix &m1, const AffineMatrix &m2, const Float eps=EPS)
Definition: AffineMatrix.h:278
NAMESPACE_SPH_BEGIN const Vector MAX_SPIN
AggregateEnum
Various function for interpretation of the results of a simulation.
INLINE bool isReal(const AntisymmetricTensor &t)
#define SPH_ASSERT(x,...)
Definition: Assert.h:94
#define NOT_IMPLEMENTED
Helper macro marking missing implementation.
Definition: Assert.h:100
INLINE AutoPtr< T > makeAuto(TArgs &&... args)
Definition: AutoPtr.h:124
NAMESPACE_SPH_BEGIN
Definition: BarnesHut.cpp:13
Helper functions to check the internal consistency of the code.
@ NON_REENRANT
Function can be executed by any thread, but only once at a time.
#define CHECK_FUNCTION(flags)
Definition: CheckFunction.h:40
Collision handling.
INLINE bool areParticlesBound(const Float m_sum, const Float h_sum, const Vector &dv, const Float limit)
Definition: Collision.h:87
INLINE T weightedAverage(const T &v1, const Float w1, const T &v2, const Float w2)
Definition: Collision.h:82
CollisionResult
Definition: Collision.h:15
@ BOUNCE
Bounce/scatter collision, no merging and no fragmentation.
@ NONE
No collision took place.
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
Base class for solvers of gravity.
Logging routines of the run.
SPH-specific implementation of particle materials.
constexpr INLINE T clamp(const T &f, const T &f1, const T &f2)
Definition: MathBasic.h:35
constexpr Float LARGE
Definition: MathUtils.h:34
#define INLINE
Macros for conditional compilation based on selected compiler.
Definition: Object.h:31
#define UNUSED(x)
Definition: Object.h:37
#define NAMESPACE_SPH_END
Definition: Object.h:12
const NothingType NOTHING
Definition: Optional.h:16
@ POSITION
Positions (velocities, accelerations) of particles, always a vector quantity,.
@ AGGREGATE_ID
Index of the aggregate containing this particle.
@ MASS
Paricles masses, always a scalar quantity.
Holder of quantity values and their temporal derivatives.
@ FIRST
Quantity with 1st derivative.
@ ZERO
Quantity without derivatives, or "zero order" of quantity.
INLINE RawPtr< T > addressOf(T &ref)
Definition: RawPtr.h:82
StaticArray< T0 &, sizeof...(TArgs)+1 > tie(T0 &t0, TArgs &... rest)
Creates a static array from a list of l-value references.
Definition: StaticArray.h:281
Statistics gathered and periodically displayed during the run.
@ AGGREGATE_COUNT
Number of aggregates in the simulation (single particles are not counted as aggregates).
Container for storing particle quantities and materials.
INLINE SymmetricTensor symmetricOuter(const Vector &v1, const Vector &v2)
SYMMETRIZED outer product of two vectors.
INLINE Tuple< TArgs &... > tieToTuple(TArgs &... args)
Creates a tuple of l-value references. Use IGNORE placeholder to omit one or more parameters.
Definition: Tuple.h:304
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 Tuple< Vector, Float > getNormalizedWithLength(const Vector &v)
Returns normalized vector and length of the input vector as tuple.
Definition: Vector.h:597
INLINE Float getSqrLength(const Vector &v)
Definition: Vector.h:574
INLINE BasicVector< float > cross(const BasicVector< float > &v1, const BasicVector< float > &v2)
Cross product between two vectors.
Definition: Vector.h:559
BasicVector< Float > Vector
Definition: Vector.h:539
INLINE float dot(const BasicVector< float > &v1, const BasicVector< float > &v2)
Make sure the vector is trivially constructible and destructible, needed for fast initialization of a...
Definition: Vector.h:548
INLINE Vector getNormalized(const Vector &v)
Definition: Vector.h:590
@ H
Definition: Vector.h:25
static AffineMatrix identity()
Definition: AffineMatrix.h:132
static AffineMatrix rotateAxis(const Vector &axis, const Float angle)
Definition: AffineMatrix.h:159
virtual void initialize(Storage &storage) override
AggregateCollisionHandler(const RunSettings &settings)
virtual CollisionResult collide(const Size i, const Size j, FlatSet< Size > &UNUSED(toRemove)) override
Holds a set of aggregates.
void integrate()
Integrates all aggregates.
virtual Size count() const override
Returns the number of aggregates in the storage.
Optional< Size > getAggregateId(const Size particleIdx) const
AggregateHolder(Storage &storage, const AggregateEnum source)
void disband(Aggregate &ag)
void separate(Aggregate &ag, const Size idx)
void merge(Aggregate &ag1, Aggregate &ag2)
Merges two aggregates.
Aggregate & getAggregate(const Size particleIdx)
Returns the aggregate holding the given particle.
const Aggregate & getAggregate(const Size particleIdx) const
Returns the aggregate holding the given particle.
AggregateOverlapHandler(const RunSettings &settings)
virtual void initialize(Storage &storage) override
virtual void handle(const Size i, const Size j, FlatSet< Size > &toRemove) override
Handles the overlap of two particles.
virtual bool overlaps(const Size i, const Size j) const override
Returns true if two particles overlaps.
virtual void integrate(Storage &storage, Statistics &stats) override
Computes derivatives of all time-dependent quantities.
virtual void create(Storage &storage, IMaterial &material) const override
Initializes all quantities needed by the solver in the storage.
void createAggregateData(Storage &storage, const AggregateEnum source)
AggregateSolver(IScheduler &scheduler, const RunSettings &settings)
virtual void collide(Storage &storage, Statistics &stats, const Float dt) override
Checks and resolves particle collisions.
Aggregate of particles, moving as a rigid body according to Euler's equations.
void fixVelocities()
void displace(const Vector &offset)
auto begin() const
bool contains(const Size idx) const
void add(const Size idx)
void spin()
Modifies velocities according to saved angular frequency.
Float mass() const
Aggregate(Storage &storage, IndexSequence seq)
void integrate()
Saves angular frequency, sets velocities to COM movement.
Size size() const
Aggregate()=default
Needed due to resize.
void remove(const Size idx)
bool empty() const
Vector velocity() const
Aggregate(Storage &storage, const Size particleIdx)
Single particle.
auto end() const
Size getId() const
Object providing safe access to continuous memory of data.
Definition: ArrayView.h:17
INLINE TCounter size() const
Definition: ArrayView.h:101
void resize(const TCounter newSize)
Resizes the array to new size.
Definition: Array.h:215
StorageType & emplaceBack(TArgs &&... args)
Constructs a new element at the end of the array in place, using the provided arguments.
Definition: Array.h:332
void clear()
Removes all elements from the array, but does NOT release the memory.
Definition: Array.h:434
bool insert(U &&value)
Definition: FlatSet.h:45
bool contains(const T &value)
Definition: FlatSet.h:89
Iterator< T > erase(Iterator< T > pos)
Definition: FlatSet.h:93
Iterator< T > begin()
Definition: FlatSet.h:103
INLINE bool empty() const
Definition: FlatSet.h:32
void clear()
Definition: FlatSet.h:99
Iterator< T > find(const T &value)
Definition: FlatSet.h:76
Iterator< T > end()
Definition: FlatSet.h:111
INLINE Size size() const
Definition: FlatSet.h:28
Solver computing gravitational interactions of hard-sphere particles.
Definition: NBodySolver.h:24
virtual void collide(Storage &storage, Statistics &stats, const Float dt) override
Checks and resolves particle collisions.
virtual void integrate(Storage &storage, Statistics &stats) override
Computes derivatives of all time-dependent quantities.
Definition: NBodySolver.cpp:96
virtual void create(Storage &storage, IMaterial &material) const override
Initializes all quantities needed by the solver in the storage.
Holds aggregate data stored in the storage and used by the solver.
Abstraction of collision outcome.
Definition: Collision.h:29
Material settings and functions specific for one material.
Definition: IMaterial.h:110
Handles overlaps of particles.
Definition: Collision.h:54
Interface that allows unified implementation of sequential and parallelized versions of algorithms.
Definition: Scheduler.h:27
INLINE IndexIterator begin() const
INLINE Size size() const
Non-owning wrapper of a material and particles with this material.
Definition: IMaterial.h:30
INLINE IndexSequence sequence()
Returns iterable index sequence.
Definition: IMaterial.h:75
INLINE Type valueOr(const TOther &other) const
Returns the stored value if the object has been initialized, otherwise returns provided parameter.
Definition: Optional.h:188
TValue get(const TEnum idx, std::enable_if_t<!std::is_enum< std::decay_t< TValue >>::value, int >=0) const
Returns a value of given type from the settings.
Definition: Settings.h:326
INLINE RawPtr< T > get() const
Definition: SharedPtr.h:223
Object holding various statistics about current run.
Definition: Statistics.h:22
Statistics & set(const StatisticsId idx, TValue &&value)
Sets new values of a statistic.
Definition: Statistics.h:52
Container storing all quantities used within the simulations.
Definition: Storage.h:230
Size getMaterialCnt() const
Return the number of materials in the storage.
Definition: Storage.cpp:437
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
StaticArray< Array< TValue > &, 3 > getAll(const QuantityId key)
Retrieves quantity buffers from the storage, given its key and value type.
Definition: Storage.cpp:163
Array< TValue > & getDt(const QuantityId key)
Retrieves a quantity derivative from the storage, given its key and value type.
Definition: Storage.cpp:217
void setUserData(SharedPtr< IStorageUserData > newData)
Stores new user data into the storage.
Definition: Storage.cpp:824
Size getParticleCnt() const
Returns the number of particles.
Definition: Storage.cpp:445
SharedPtr< IStorageUserData > getUserData() const
Returns the stored user data.
Definition: Storage.cpp:828
MaterialView getMaterial(const Size matIdx) const
Returns an object containing a reference to given material.
Definition: Storage.cpp:366
Array< TValue > & getValue(const QuantityId key)
Retrieves a quantity values from the storage, given its key and value type.
Definition: Storage.cpp:191
Symmetric tensor of 2nd order.
INLINE SymmetricTensor inverse() const
static INLINE SymmetricTensor identity()
Returns an identity tensor.
static INLINE SymmetricTensor null()
Returns a tensor with all zeros.
INLINE Float determinant() const
Returns the determinant of the tensor.
Creating code components based on values from settings.
@ COLLISION_BOUNCE_MERGE_LIMIT
@ COLLISION_RESTITUTION_TANGENT
@ COLLISION_RESTITUTION_NORMAL
Provides a convenient way to construct objects from settings.
Definition: Factory.h:46
AutoPtr< IGravity > getGravity(const RunSettings &settings)
Definition: Factory.cpp:325
Object with deleted copy constructor and copy operator.
Definition: Object.h:54