SPH
Initial.cpp
Go to the documentation of this file.
1 #include "sph/initial/Initial.h"
2 #include "math/rng/VectorRng.h"
6 #include "physics/Eos.h"
7 #include "physics/Integrals.h"
8 #include "quantities/IMaterial.h"
9 #include "quantities/Quantity.h"
10 #include "quantities/Storage.h"
12 #include "system/Factory.h"
13 #include "system/Profiler.h"
14 #include "thread/Scheduler.h"
15 #include "timestepping/ISolver.h"
16 
18 
19 BodyView::BodyView(Storage& storage, const Size bodyIndex)
20  : storage(&storage)
21  , bodyIndex(bodyIndex) {}
22 
24  // manually clear the h component to make sure we are not modifying smoothing length
25  Vector actDr = dr;
26  actDr[H] = 0.f;
27 
30  for (Size i = 0; i < r.size(); ++i) {
31  if (flag[i] == bodyIndex) {
32  r[i] += actDr;
33  }
34  }
35  return *this;
36 }
37 
41  for (Size i = 0; i < v.size(); ++i) {
42  if (flag[i] == bodyIndex) {
43  v[i] += velocity;
44  }
45  }
46  return *this;
47 }
48 
49 BodyView& BodyView::addRotation(const Vector& omega, const Vector& origin) {
50  ArrayView<Vector> r, v, dv;
51  tie(r, v, dv) = storage->getAll<Vector>(QuantityId::POSITION);
53  for (Size i = 0; i < r.size(); ++i) {
54  if (flag[i] == bodyIndex) {
55  v[i] += cross(omega, r[i] - origin);
56  }
57  }
58  return *this;
59 }
60 
61 Vector BodyView::getOrigin(const RotationOrigin origin) const {
62  switch (origin) {
64  return Vector(0._f);
66  return CenterOfMass(bodyIndex).evaluate(*storage);
67  default:
69  }
70 }
71 
72 BodyView& BodyView::addRotation(const Vector& omega, const RotationOrigin origin) {
73  return this->addRotation(omega, this->getOrigin(origin));
74 }
75 
77  : context(settings) {}
78 
80 
82  AutoPtr<IDomain> domain = Factory::getDomain(body);
83  return this->addMonolithicBody(storage, *domain, body);
84 }
85 
87  const IDomain& domain,
88  const BodySettings& body) {
90  return this->addMonolithicBody(storage, domain, std::move(material));
91 }
92 
94  const IDomain& domain,
95  SharedPtr<IMaterial> material) {
96  AutoPtr<IDistribution> distribution = Factory::getDistribution(material->getParams());
97  return this->addMonolithicBody(storage, domain, std::move(material), *distribution);
98 }
99 
101  const IDomain& domain,
102  SharedPtr<IMaterial> material,
103  const IDistribution& distribution) {
104  Storage body(material);
105 
106  PROFILE_SCOPE("InitialConditions::addBody");
107  const Size n = material->getParam<int>(BodySettingsId::PARTICLE_COUNT);
108 
109  // Generate positions of particles
110  Array<Vector> positions = distribution.generate(*context.scheduler, n, domain);
111  SPH_ASSERT(positions.size() > 0);
112  body.insert<Vector>(QuantityId::POSITION, OrderEnum::SECOND, std::move(positions));
113 
114  this->setQuantities(body, *material, domain.getVolume());
115  storage.merge(std::move(body));
116  const Size particleCnt = storage.getParticleCnt();
117 
119  storage.propagate([&particleCnt, &storage](Storage& act) { //
120  SPH_ASSERT(&act != &storage);
121  (void)storage;
123  });
124  return BodyView(storage, bodyIndex++);
125 }
126 
128  : domain(domain)
129  , material(material) {}
130 
132  : domain(domain)
133  , material(Factory::getMaterial(body)) {}
134 
136 
138 
139 
141  const BodySetup& environment,
143  AutoPtr<IDistribution> distribution = Factory::getDistribution(environment.material->getParams());
144  const Size n = environment.material->getParam<int>(BodySettingsId::PARTICLE_COUNT);
145 
146  // Generate positions of ALL particles
147  Array<Vector> positions = distribution->generate(*context.scheduler, n, *environment.domain);
148  // Create particle storage per body
149  Storage enviroStorage(environment.material);
150  Array<Storage> bodyStorages;
151  for (const BodySetup& body : bodies) {
152  bodyStorages.push(Storage(body.material));
153  }
154  // Assign particles to bodies
155  Array<Vector> pos_env;
156  Array<Array<Vector>> pos_bodies(bodies.size());
157  auto assign = [&](const Vector& p) {
158  for (Size i = 0; i < bodies.size(); ++i) {
159  if (bodies[i].domain->contains(p)) {
160  pos_bodies[i].push(p);
161  return true;
162  }
163  }
164  return false;
165  };
166  for (const Vector& p : positions) {
167  if (!assign(p)) {
168  pos_env.push(p);
169  }
170  }
171 
172  // Initialize storages
173  Float environVolume = environment.domain->getVolume();
174  for (Size i = 0; i < bodyStorages.size(); ++i) {
175  bodyStorages[i].insert<Vector>(QuantityId::POSITION, OrderEnum::SECOND, std::move(pos_bodies[i]));
176  const Float volume = bodies[i].domain->getVolume();
177  this->setQuantities(bodyStorages[i], bodyStorages[i].getMaterial(0), volume);
178  environVolume -= volume;
179  }
180  SPH_ASSERT(environVolume >= 0._f);
181  enviroStorage.insert<Vector>(QuantityId::POSITION, OrderEnum::SECOND, std::move(pos_env));
182  this->setQuantities(enviroStorage, enviroStorage.getMaterial(0), environVolume);
183 
184  // merge all storages
185  storage.merge(std::move(enviroStorage));
186  for (Storage& body : bodyStorages) {
187  storage.merge(std::move(body));
188  }
189 
190  return BodyView(storage, bodyIndex++);
191 }
192 
194  const IDomain& domain,
195  const PowerLawSfd& sfd,
196  const BodySettings& bodySettings) {
197  const Size n = bodySettings.get<int>(BodySettingsId::PARTICLE_COUNT);
198  const Size minN = bodySettings.get<int>(BodySettingsId::MIN_PARTICLE_COUNT);
199 
200  SPH_ASSERT(context.rng);
201  VectorRng<IRng&> rng(*context.rng);
202 
203  // stack of generated spheres, to check for overlap
204  Array<Sphere> spheres;
205 
206  // generate the particles that will be eventually turned into spheres
207  AutoPtr<IDistribution> distribution = Factory::getDistribution(bodySettings);
208  Array<Vector> positions = distribution->generate(*context.scheduler, n, domain);
209  SharedPtr<IMaterial> material = Factory::getMaterial(bodySettings);
210 
211  // counter used to exit the loop (when no more spheres can be generated)
212  Size bailoutCounter = 0;
213  constexpr Size bailoutTarget = 1000;
214 
215  while (bailoutCounter < bailoutTarget) {
216 
217  Vector center;
218  Float radius;
219  while (bailoutCounter < bailoutTarget) {
220 
221  // generate a center of the sphere
222  const Box box = domain.getBoundingBox();
223  center = box.lower() + rng() * box.size();
224  if (!domain.contains(center)) {
225  // outside of the domain, reject (do not increase the bailoutCounter here)
226  continue;
227  }
228 
229  // generate a radius
230  radius = sfd(rng.getAdditional(3));
231 
232  // check for overlap with spheres already generated
233  auto checkOverlap = [&spheres](const Sphere& sphere) {
234  for (const Sphere& s : spheres) {
235  if (s.intersects(sphere)) {
236  return true;
237  }
238  }
239  return false;
240  };
241  Sphere sphere(center, radius);
242  if (checkOverlap(sphere)) {
243  // overlaps, reject
244  bailoutCounter++;
245  continue;
246  }
247 
248  // okay, this sphere seems valid, accept it
249  break;
250  }
251 
252  Sphere sphere(center, radius);
253 
254  // extract all particles inside the sphere, ignore particles outside of the domain
255  Array<Vector> spherePositions;
256  for (Size i = 0; i < positions.size();) {
257  if (sphere.contains(positions[i])) {
258  spherePositions.push(positions[i]);
259  positions.remove(i);
260  } else {
261  ++i;
262  }
263  }
264 
265  // if the body has less than the minimal number of particles, reject it and generate a new sphere
266  if (spherePositions.size() < minN) {
267  // we need to put the (unused) points back
268  positions.pushAll(std::move(spherePositions));
269  bailoutCounter++;
270  continue;
271  }
272  spheres.push(sphere);
273 
274  // create the body
275  Storage body(material);
276  body.insert<Vector>(QuantityId::POSITION, OrderEnum::SECOND, std::move(spherePositions));
277  this->setQuantities(body, *material, sphere.volume());
278 
279  // add it to the storage
280  storage.merge(std::move(body));
281  bodyIndex++;
282 
283  // we are still adding spheres, reset the counter
284  bailoutCounter = 0;
285  }
286 
287  SPH_ASSERT(!spheres.empty());
288 }
289 
293 static Array<Float> getMasses(ArrayView<const Vector> r, const Float totalM) {
294  Array<Float> m(r.size());
295  Float prelimM = 0._f;
296  for (Size i = 0; i < r.size(); ++i) {
297  m[i] = pow<3>(r[i][H]);
298  prelimM += m[i];
299  }
300  // renormalize masses so that they sum up to totalM
301  const Float normalization = totalM / prelimM;
302  for (Size i = 0; i < r.size(); ++i) {
303  m[i] *= normalization;
304  }
305  return m;
306 }
307 
308 void InitialConditions::setQuantities(Storage& storage, IMaterial& material, const Float volume) {
311  for (Size i = 0; i < r.size(); ++i) {
312  r[i][H] *= eta;
313  }
314 
315  const Float rho0 = material.getParam<Float>(BodySettingsId::DENSITY);
316  const Float totalM = volume * rho0; // m = rho * V
317  SPH_ASSERT(totalM > 0._f);
318 
319  // Add masses (possibly heterogeneous, depending on generated smoothing lengths)
320  storage.insert<Float>(QuantityId::MASS, OrderEnum::ZERO, getMasses(r, totalM));
321 
322  // Mark particles of this body
323  storage.insert<Size>(QuantityId::FLAG, OrderEnum::ZERO, bodyIndex);
324 
325  // Initialize material (we need density and energy for EoS)
326  material.create(storage, context);
327 
328  // Generate mapping coordinates for textures
329  if (context.uvMap) {
330  Array<Vector> uvws = context.uvMap->generate(storage);
331  storage.insert<Vector>(QuantityId::UVW, OrderEnum::ZERO, std::move(uvws));
332  }
333 }
334 
337  finder->build(SEQUENTIAL, r);
338  Array<NeighbourRecord> neighs;
339  Size moveCnt = -1;
340  while (moveCnt != 0) {
341  moveCnt = 0;
342  for (Size i = 0; i < r.size(); ++i) {
343  finder->findAll(i, 10._f * r[i][H] * radius, neighs);
344  Vector force = Vector(0._f);
345  if (neighs.size() <= 1) {
346  continue;
347  }
348  for (NeighbourRecord& n : neighs) {
349  if (i != n.index) {
350  const Vector dr = r[n.index] - r[i];
351  force += -0.3_f * dr * pow<3>(r[i][H]) / pow<3>(getLength(dr));
352  if (getLength(dr) < r[i][H] * radius) {
353  moveCnt++;
354  }
355  }
356  }
357  force[H] = 0._f;
358  r[i] += force;
359  }
360  }
361 }
362 
364  SPH_ASSERT(m.size() == r.size());
365  Vector r_com(0._f);
366  Float m_tot = 0._f;
367  for (Size i = 0; i < r.size(); ++i) {
368  r_com += m[i] * r[i];
369  m_tot += m[i];
370  }
371  r_com /= m_tot;
372  r_com[H] = 0._f; // Dangerous! Do not modify smoothing length!
373  for (Size i = 0; i < r.size(); ++i) {
374  r[i] -= r_com;
375  }
376  return r_com;
377 }
378 
385 }
386 
#define SPH_ASSERT(x,...)
Definition: Assert.h:94
#define NOT_IMPLEMENTED
Helper macro marking missing implementation.
Definition: Assert.h:100
NAMESPACE_SPH_BEGIN
Definition: BarnesHut.cpp:13
const float radius
Definition: CurveDialog.cpp:18
Filling spatial domain with SPH particles.
Object defining computational domain.
Equations of state.
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 all particle materials.
Base interface for all solvers.
Vector moveToCenterOfMassSystem(ArrayView< const Float > m, ArrayView< Vector > r)
Modifies particle positions so that their center of mass lies at the origin.
Definition: Initial.cpp:363
void repelParticles(ArrayView< Vector > r, const Float radius)
Displaces particles so that no two particles overlap.
Definition: Initial.cpp:335
Generating initial conditions of SPH particles.
Integrals of motion and other integral quantities.
AutoPtr< IMaterial > getMaterial(const MaterialEnum type)
Definition: Materials.cpp:91
constexpr INLINE Float pow< 3 >(const Float v)
Definition: MathUtils.h:132
#define NAMESPACE_SPH_END
Definition: Object.h:12
Tool to measure time spent in functions and profile the code.
#define PROFILE_SCOPE(name)
Definition: Profiler.h:175
@ FLAG
ID of original body, used to implement discontinuities between bodies in SPH.
@ POSITION
Positions (velocities, accelerations) of particles, always a vector quantity,.
@ MASS
Paricles masses, always a scalar quantity.
@ UVW
Texture mapping coordinates,.
Holder of quantity values and their temporal derivatives.
@ SECOND
Quantity with 1st and 2nd derivative.
@ ZERO
Quantity without derivatives, or "zero order" of quantity.
SequentialScheduler SEQUENTIAL
Global instance of the sequential scheduler.
Definition: Scheduler.cpp:43
Interface for executing tasks (potentially) asynchronously.
Object representing a three-dimensional sphere.
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
Container for storing particle quantities and materials.
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 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
@ H
Definition: Vector.h:25
Object providing safe access to continuous memory of data.
Definition: ArrayView.h:17
INLINE TCounter size() const
Definition: ArrayView.h:101
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 remove(const TCounter idx)
Removes an element with given index from the array.
Definition: Array.h:383
void insert(const TCounter position, U &&value)
Inserts a new element to given position in the array.
Definition: Array.h:345
INLINE TCounter size() const noexcept
Definition: Array.h:193
INLINE bool empty() const noexcept
Definition: Array.h:201
void pushAll(const TIter first, const TIter last)
Definition: Array.h:312
Non-owning view of particles belonging to the same body.
Definition: Initial.h:20
RotationOrigin
Predefined types of center point.
Definition: Initial.h:47
@ CENTER_OF_MASS
Rotate the body around its center of mass.
@ FRAME_ORIGIN
Add angular velocity with respect to origin of coordinates.
BodyView(Storage &storage, const Size bodyIndex)
Definition: Initial.cpp:19
BodyView & addRotation(const Vector &omega, const RotationOrigin origin)
Adds an angular velocity to all particles of the body.
Definition: Initial.cpp:72
BodyView & addVelocity(const Vector &v)
Adds a velocity vector to all particles of the body.
Definition: Initial.cpp:38
BodyView & displace(const Vector &dr)
Moves the particles of the body in given direction.
Definition: Initial.cpp:23
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 Vector size() const
Returns box dimensions.
Definition: Box.h:106
Computes the center of mass of particles.
Definition: Integrals.h:150
virtual Vector evaluate(const Storage &storage) const override
Computes the integral quantity using particles in the storage.
Definition: Integrals.cpp:127
virtual Size findAll(const Size index, const Float radius, Array< NeighbourRecord > &neighbours) const =0
Finds all neighbours within given radius from the point given by index.
Base class for generating vertices with specific distribution.
Definition: Distribution.h:21
virtual Array< Vector > generate(IScheduler &scheduler, const Size n, const IDomain &domain) const =0
Generates the requested number of particles in the domain.
Base class for computational domains.
Definition: Domain.h:29
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 bool contains(const Vector &v) const =0
Checks if the given point lies inside the domain.
Material settings and functions specific for one material.
Definition: IMaterial.h:110
INLINE TValue getParam(const BodySettingsId paramIdx) const
Returns a parameter associated with given particle.
Definition: IMaterial.h:137
INLINE const BodySettings & getParams() const
Returns settings containing material parameters.
Definition: IMaterial.h:142
virtual void create(Storage &storage, const MaterialInitialContext &context)=0
Create all quantities needed by the material.
void build(IScheduler &scheduler, ArrayView< const Vector > points, Flags< FinderFlag > flags=FinderFlag::MAKE_RANK)
Constructs the struct with an array of vectors.
virtual Array< Vector > generate(const Storage &storage) const =0
BodyView addMonolithicBody(Storage &storage, const BodySettings &body)
Creates a monolithic body by filling given domain with particles.
Definition: Initial.cpp:81
InitialConditions(const RunSettings &settings)
Creates new initial conditions.
Definition: Initial.cpp:76
BodyView addHeterogeneousBody(Storage &storage, const BodySetup &environment, ArrayView< const BodySetup > bodies)
Creates particles composed of different materials.
Definition: Initial.cpp:140
void addRubblePileBody(Storage &storage, const IDomain &domain, const PowerLawSfd &sfd, const BodySettings &bodySettings)
Creates a rubble-pile body, composing of monolithic spheres.
Definition: Initial.cpp:193
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
static const Settings & getDefaults()
\brief Returns a reference to object containing default values of all settings.
Definition: Sphere.h:18
INLINE bool contains(const Vector &v) const
Definition: Sphere.h:57
INLINE Float volume() const
Definition: Sphere.h:53
Container storing all quantities used within the simulations.
Definition: Storage.h:230
void merge(Storage &&other)
Merges another storage into this object.
Definition: Storage.cpp:472
void resize(const Size newParticleCnt, const Flags< ResizeFlag > flags=EMPTY_FLAGS)
Changes number of particles for all quantities stored in the storage.
Definition: Storage.cpp:579
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
Size getParticleCnt() const
Returns the number of particles.
Definition: Storage.cpp:445
void propagate(const Function< void(Storage &storage)> &functor)
Executes a given functor recursively for all dependent storages.
Definition: Storage.cpp:424
MaterialView getMaterial(const Size matIdx) const
Returns an object containing a reference to given material.
Definition: Storage.cpp:366
@ KEEP_EMPTY_UNCHANGED
Empty buffers will not be resized to new values.
Array< TValue > & getValue(const QuantityId key)
Retrieves a quantity values from the storage, given its key and value type.
Definition: Storage.cpp:191
Wrapper for generating random vectors.
Definition: VectorRng.h:18
Float getAdditional(const Size i)
Definition: VectorRng.h:49
Creating code components based on values from settings.
@ PARTICLE_COUNT
Number of SPH particles in the body.
@ DENSITY
Density at zero pressure.
@ SMOOTHING_LENGTH_ETA
Eta-factor between smoothing length and particle concentration (h = eta * n^(-1/d) )
Provides a convenient way to construct objects from settings.
Definition: Factory.h:46
AutoPtr< IMaterial > getMaterial(const BodySettings &settings)
Definition: Factory.cpp:508
AutoPtr< ISymmetricFinder > getFinder(const RunSettings &settings)
Definition: Factory.cpp:156
AutoPtr< IDistribution > getDistribution(const BodySettings &settings, Function< bool(Float)> progressCallback=nullptr)
Definition: Factory.cpp:228
AutoPtr< IDomain > getDomain(const RunSettings &settings)
Definition: Factory.cpp:416
Vector velocity(const Float a, const Float e, const Float u, const Float n)
Computes the velocity vector on the elliptic trajectory.
Definition: TwoBody.cpp:86
Holds data needed to create a single body in addHeterogeneousBody function.
Definition: Initial.h:154
SharedPtr< IDomain > domain
Definition: Initial.h:155
SharedPtr< IMaterial > material
Definition: Initial.h:156
BodySetup()
Creates a body with undefined domain and material.
SharedPtr< IScheduler > scheduler
Definition: IMaterial.h:93
AutoPtr< IUvMapping > uvMap
If used, texture mapping coordinates are generated provided mapping.
Definition: IMaterial.h:99
AutoPtr< IRng > rng
Random number generator.
Definition: IMaterial.h:91
Holds information about a neighbour particles.
Holds the information about a power-law size-frequency distributions.
Definition: Initial.h:73