SPH
AsymmetricSolver.cpp
Go to the documentation of this file.
2 #include "objects/Exceptions.h"
4 #include "quantities/IMaterial.h"
8 #include "sph/kernel/Kernel.h"
9 #include "system/Factory.h"
10 #include "system/Statistics.h"
11 
13 
14 void RadiiHashMap::build(ArrayView<const Vector> r, const Float kernelRadius) {
15  cellSize = 0._f;
16  for (Size i = 0; i < r.size(); ++i) {
17  cellSize = max(cellSize, r[i][H] * kernelRadius);
18  }
19 
20  std::unordered_map<Indices, Float, std::hash<Indices>, IndicesEqual> newMap;
21  for (Size i = 0; i < r.size(); ++i) {
22  // floor needed to properly handle negative values
23  const Indices idxs = floor(r[i] / cellSize);
24  Float& radius = newMap[idxs];
25  radius = max(radius, r[i][H] * kernelRadius);
26  }
27 
28  // create map by dilating newMap
29  map.clear();
30  for (const auto& p : newMap) {
31  const Indices& idxs0 = p.first;
32  Float radius = p.second;
33  for (int i = -1; i <= 1; ++i) {
34  for (int j = -1; j <= 1; ++j) {
35  for (int k = -1; k <= 1; ++k) {
36  const Indices idxs = idxs0 + Indices(i, j, k);
37  auto iter = newMap.find(idxs);
38  if (iter != newMap.end()) {
39  radius = std::max(radius, iter->second);
40  }
41  }
42  }
43  }
44  map[idxs0] = radius;
45  }
46 }
47 
49  const Indices idxs = floor(r / cellSize);
50  Float radius = 0._f;
51  const auto iter = map.find(idxs);
52  if (iter != map.end()) {
53  radius = max(radius, iter->second);
54  }
55  return radius;
56 }
57 
59  const RunSettings& settings,
60  const EquationHolder& eqs)
61  : scheduler(scheduler) {
62  kernel = Factory::getKernel<DIMENSIONS>(settings);
63  finder = Factory::getFinder(settings);
64  equations += eqs;
65 
67  radiiMap.emplace();
68  }
69 }
70 
73 
74  // initialize all materials (compute pressure, apply yielding and damage, ...)
75  for (Size i = 0; i < storage.getMaterialCnt(); ++i) {
76  PROFILE_SCOPE("IAsymmetricSolver initialize materials")
77  MaterialView material = storage.getMaterial(i);
78  material->initialize(scheduler, storage, material.sequence());
79  }
80 
81  // initialize equations, derivatives, accumulate storages, ...
82  this->beforeLoop(storage, stats);
83 
84  // main loop over pairs of interacting particles
85  this->loop(storage, stats);
86 
87  // store results to storage, finalizes equations, save statistics, ...
88  this->afterLoop(storage, stats);
89 
90  // finalize all materials (integrate fragmentation model)
91  for (Size i = 0; i < storage.getMaterialCnt(); ++i) {
92  PROFILE_SCOPE("IAsymmetricSolver finalize materials")
93  MaterialView material = storage.getMaterial(i);
94  material->finalize(scheduler, storage, material.sequence());
95  }
96 }
97 
98 void IAsymmetricSolver::create(Storage& storage, IMaterial& material) const {
100  equations.create(storage, material);
101  this->sanityCheck(storage);
102 }
103 
106  Float maxH = 0._f;
107  for (Size i = 0; i < r.size(); ++i) {
108  maxH = max(maxH, r[i][H]);
109  }
110  return maxH * kernel.radius();
111 }
112 
115  finder->build(scheduler, r);
116  return &*finder;
117 }
118 
120  const RunSettings& settings,
121  const EquationHolder& eqs)
122  : AsymmetricSolver(scheduler, settings, eqs, Factory::getBoundaryConditions(settings)) {}
123 
125  const RunSettings& settings,
126  const EquationHolder& eqs,
128  : IAsymmetricSolver(scheduler, settings, eqs)
129  , bc(std::move(bc))
130  , threadData(scheduler) {
131 
132  // creates all derivatives required by the equation terms
134 }
135 
137 
138 
141 
142  // initialize boundary conditions first, as they may change the number of particles (ghosts, killbox, ...)
143  bc->initialize(storage);
144 
145  // initialize all equation terms (applies dependencies between quantities)
146  const Float t = stats.getOr<Float>(StatisticsId::RUN_TIME, 0._f);
147  equations.initialize(scheduler, storage, t);
148 
149  // sets up references to storage buffers for all derivatives
150  derivatives.initialize(storage);
151 }
152 
155 
156  // (re)build neighbour-finding structure; this needs to be done after all equations
157  // are initialized in case some of them modify smoothing lengths
159  const IBasicFinder& actFinder = *this->getFinder(r);
160 
161  // precompute the search radii
162  Float maxRadius = 0._f;
163  if (radiiMap) {
164  radiiMap->build(r, kernel.radius());
165  } else {
166  maxRadius = this->getMaxSearchRadius(storage);
167  }
168 
170 
171  // we need to symmetrize kernel in smoothing lenghts to conserve momentum
173 
174  auto functor = [this, r, &neighs, maxRadius, &symmetrizedKernel, &actFinder](Size i, ThreadData& data) {
175  const Float radius = radiiMap ? radiiMap->getRadius(r[i]) : maxRadius;
176  SPH_ASSERT(radius > 0._f);
177 
178  actFinder.findAll(i, radius, data.neighs);
179  data.grads.clear();
180  data.idxs.clear();
181  for (auto& n : data.neighs) {
182  const Size j = n.index;
183  const Float hbar = 0.5_f * (r[i][H] + r[j][H]);
184  SPH_ASSERT(hbar > EPS, hbar);
185  if (i == j || n.distanceSqr >= sqr(kernel.radius() * hbar)) {
186  // aren't actual neighbours
187  continue;
188  }
189  const Vector gr = symmetrizedKernel.grad(r[i], r[j]);
190  SPH_ASSERT(isReal(gr) && dot(gr, r[i] - r[j]) <= 0._f, gr, r[i] - r[j]);
191  data.grads.emplaceBack(gr);
192  data.idxs.emplaceBack(j);
193  }
194  derivatives.eval(i, data.idxs, data.grads);
195  neighs[i] = data.idxs.size();
196  };
197  PROFILE_SCOPE("AsymmetricSolver::loop");
198  parallelFor(scheduler, threadData, 0, r.size(), functor);
199 }
200 
203 
204  // store the computed values into the storage
205  Accumulated& accumulated = derivatives.getAccumulated();
206  accumulated.store(storage);
207 
208  // using the stored values, integrates all equation terms
209  const Float t = stats.getOr<Float>(StatisticsId::RUN_TIME, 0._f);
210  equations.finalize(scheduler, storage, t);
211 
212  // lastly, finalize boundary conditions, to make sure the computed quantities will not change any further
213  bc->finalize(storage);
214 
215  // compute neighbour statistics
217  MinMaxMean neighsStats;
218  const Size size = storage.getParticleCnt();
219  for (Size i = 0; i < size; ++i) {
220  neighsStats.accumulate(neighs[i]);
221  }
222  stats.set(StatisticsId::NEIGHBOUR_COUNT, neighsStats);
223 }
224 
225 void AsymmetricSolver::sanityCheck(const Storage& UNUSED(storage)) const {
226  // we must solve smoothing length somehow
228  throw InvalidSetup(
229  "No solver of smoothing length specified; add either ConstSmootingLength or "
230  "AdaptiveSmootingLength into the list of equations");
231  }
232 
233  // we allow both velocity divergence and density velocity divergence as the former can be used by some
234  // terms (e.g. Balsara switch) even in Standard formulation
235 }
236 
Buffer storing quantity values accumulated by summing over particle pairs.
INLINE bool isReal(const AntisymmetricTensor &t)
#define SPH_ASSERT(x,...)
Definition: Assert.h:94
SPH solver with asymmetric particle evaluation.
NAMESPACE_SPH_BEGIN
Definition: BarnesHut.cpp:13
Boundary conditions.
const float radius
Definition: CurveDialog.cpp:18
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
Additional equation terms computing SPH statistics rather than physical quantities.
Base class for all particle materials.
SPH kernels.
#define VERBOSE_LOG
Helper macro, creating.
Definition: Logger.h:242
constexpr INLINE T max(const T &f1, const T &f2)
Definition: MathBasic.h:20
constexpr Float EPS
Definition: MathUtils.h:30
constexpr INLINE T sqr(const T &f) noexcept
Return a squared value.
Definition: MathUtils.h:67
INLINE auto floor(const T &f)
Definition: MathUtils.h:346
#define UNUSED(x)
Definition: Object.h:37
#define NAMESPACE_SPH_END
Definition: Object.h:12
#define PROFILE_SCOPE(name)
Definition: Profiler.h:175
@ POSITION
Positions (velocities, accelerations) of particles, always a vector quantity,.
@ NEIGHBOUR_CNT
Number of neighbouring particles (in radius h * kernel.radius)
@ ZERO
Quantity without derivatives, or "zero order" of quantity.
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
Statistics gathered and periodically displayed during the run.
@ NEIGHBOUR_COUNT
Number of neighbours (min, max, mean)
@ RUN_TIME
Current time of the simulation in code units. Does not necessarily have to be 0 when run starts.
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
@ H
Definition: Vector.h:25
Storage for accumulating derivatives.
Definition: Accumulated.h:30
void store(Storage &storage)
Stores accumulated values to corresponding quantities.
Definition: Accumulated.cpp:86
Evolutionary equation for the (scalar) smoothing length.
Definition: EquationTerm.h:65
Object providing safe access to continuous memory of data.
Definition: ArrayView.h:17
INLINE TCounter size() const
Definition: ArrayView.h:101
Generic SPH solver, evaluating equations for each particle separately.
AutoPtr< IBoundaryCondition > bc
virtual void beforeLoop(Storage &storage, Statistics &stats) override
virtual void sanityCheck(const Storage &storage) const override
AsymmetricSolver(IScheduler &scheduler, const RunSettings &settings, const EquationHolder &eqs)
virtual void afterLoop(Storage &storage, Statistics &stats) override
virtual void loop(Storage &storage, Statistics &stats) override
ThreadLocal< ThreadData > threadData
DerivativeHolder derivatives
Holds all derivatives (shared for all threads)
Helper term to keep smoothing length constant during the simulation.
Definition: EquationTerm.h:219
void eval(const Size idx, ArrayView< const Size > neighs, ArrayView< const Vector > grads)
Evaluates all held derivatives for given particle.
Definition: Derivative.cpp:113
INLINE Accumulated & getAccumulated()
Definition: Derivative.h:226
virtual void initialize(const Storage &input)
Initialize derivatives before loop.
Definition: Derivative.cpp:96
Container holding equation terms.
Definition: EquationTerm.h:238
void setDerivatives(DerivativeHolder &derivatives, const RunSettings &settings) const
Calls EquationTerm::setDerivatives for all stored equation terms.
Definition: EquationTerm.h:277
bool contains() const
Checks if the holder contains term of given type.
Definition: EquationTerm.h:265
void create(Storage &storage, IMaterial &material) const
Calls EquationTerm::create for all stored equation terms.
Definition: EquationTerm.h:300
void initialize(IScheduler &scheduler, Storage &storage, const Float t)
Calls EquationTerm::initialize for all stored equation terms.
Definition: EquationTerm.h:284
void finalize(IScheduler &scheduler, Storage &storage, const Float t)
Calls EquationTerm::finalize for all stored equation terms.
Definition: EquationTerm.h:293
Base class for asymmetric SPH solvers.
IScheduler & scheduler
Scheduler used to parallelize the solver.
Float getMaxSearchRadius(const Storage &storage) const
virtual void loop(Storage &storage, Statistics &stats)=0
virtual void sanityCheck(const Storage &storage) const =0
LutKernel< DIMENSIONS > kernel
Selected SPH kernel.
EquationHolder equations
Holds all equation terms evaluated by the solver.
Optional< RadiiHashMap > radiiMap
Hash map used to determine search radii of particles.
virtual void beforeLoop(Storage &storage, Statistics &stats)=0
virtual void afterLoop(Storage &storage, Statistics &stats)=0
AutoPtr< ISymmetricFinder > finder
Structure used to search for neighbouring particles.
virtual void create(Storage &storage, IMaterial &material) const override
Initializes all quantities needed by the solver in the storage.
IAsymmetricSolver(IScheduler &scheduler, const RunSettings &settings, const EquationHolder &eqs)
virtual RawPtr< const IBasicFinder > getFinder(ArrayView< const Vector > r)
Returns a finder, already build using the provided positions.
virtual void integrate(Storage &storage, Statistics &stats) override
Computes derivatives of all time-dependent quantities.
Interface of objects finding neighbouring particles.
virtual void finalize(Storage &storage)=0
Applies the boundary conditions after the derivatives are computed.
virtual void initialize(Storage &storage)=0
Applies the boundary conditions before the derivatives are computed.
Material settings and functions specific for one material.
Definition: IMaterial.h:110
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
Thrown when components of the run are mutually incompatible.
Definition: Exceptions.h:24
INLINE Float radius() const noexcept
Definition: Kernel.h:107
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
Helper class for statistics, accumulating minimal, maximal and mean value of a set of numbers.
Definition: Means.h:172
void emplace(TArgs &&... args)
Constructs the uninitialized object from a list of arguments.
Definition: Optional.h:95
Float getRadius(const Vector &r) const
Returns the required search radius for particle at given position.
void build(ArrayView< const Vector > r, const Float kernelRadius)
Computes the search radii at each cell in space.
Non-owning wrapper of pointer.
Definition: RawPtr.h:19
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
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
TValue getOr(const StatisticsId idx, const TValue &other) const
Returns value of a statistic, or a given value if the statistic is not stored.
Definition: Statistics.h:98
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
Size getParticleCnt() const
Returns the number of particles.
Definition: Storage.cpp:445
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
Creating code components based on values from settings.
@ SPH_ASYMMETRIC_COMPUTE_RADII_HASH_MAP
Provides a convenient way to construct objects from settings.
Definition: Factory.h:46
AutoPtr< ISymmetricFinder > getFinder(const RunSettings &settings)
Definition: Factory.cpp:156
AutoPtr< IBoundaryCondition > getBoundaryConditions(const RunSettings &settings, SharedPtr< IDomain > domain)
Definition: Factory.cpp:460
Overload of std::swap for Sph::Array.
Definition: Array.h:578