SPH
EnergyConservingSolver.cpp
Go to the documentation of this file.
2 #include "io/Logger.h"
3 
5 
6 // ----------------------------------------------------------------------------------------------------------
7 // Energy partitioners
8 // ----------------------------------------------------------------------------------------------------------
9 
11 public:
12  virtual void initialize(const Storage& UNUSED(storage)) override {}
13 
14  virtual void compute(const Size UNUSED(i),
17  ArrayView<Float> f) const override {
18  for (Size k = 0; k < f.size(); ++k) {
19  f[k] = 0.5_f;
20  }
21  }
22 };
23 
25 private:
28 
29 
30 public:
31  virtual void initialize(const Storage& storage) override {
32  m = storage.getValue<Float>(QuantityId::MASS);
33  u = storage.getValue<Float>(QuantityId::ENERGY);
34  }
35 
36  virtual void compute(const Size i,
37  ArrayView<const Size> neighs,
39  ArrayView<Float> f) const override {
40  for (Size k = 0; k < f.size(); ++k) {
41  const Size j = neighs[k];
42  const Float u_ji = u[j] - u[i];
43  f[k] = 0.5_f * (1._f + u_ji * sgn(e[k]) / (abs(u_ji) + 1._f / (1._f + abs(u_ji))));
44  }
45  }
46 };
47 
49 private:
52 
53 public:
54  virtual void initialize(const Storage& storage) override {
55  m = storage.getValue<Float>(QuantityId::MASS);
56  u = storage.getValue<Float>(QuantityId::ENERGY);
57  }
58 
59  virtual void compute(const Size i,
60  ArrayView<const Size> neighs,
62  ArrayView<Float> f) const override {
63  for (Size k = 0; k < f.size(); ++k) {
64  const Size j = neighs[k];
65  const Float u_ji = u[j] - u[i];
66  if (u_ji != 0._f) {
67  const Float A = e[k] / u_ji;
68  const Float B = (A >= 0._f) ? A / m[i] : A / m[j];
69  SPH_ASSERT(isReal(A) && isReal(B));
70  if (abs(B) <= 1._f) {
71  f[k] = max(0, sgn(B));
72  continue;
73  }
74  } else if (e[k] == 0._f) {
75  // what to do?
76  f[k] = 0.5_f;
77  continue;
78  }
79  // either abs(B) > 1 or u_ji == 0
80  f[k] = m[i] / e[k] * ((e[k] + m[i] * u[i] + m[j] * u[j]) / (m[i] + m[j]) - u[i]);
81  SPH_ASSERT(isReal(f[k]), e[k], u[i], u[j]);
82  }
83  }
84 };
85 
86 template <typename TPrimary, typename TSecondary>
88 private:
89  TPrimary primary;
90  TSecondary secondary;
91 
93 
94 public:
95  virtual void initialize(const Storage& storage) override {
96  primary.initialize(storage);
97  secondary.initialize(storage);
98 
99  u = storage.getValue<Float>(QuantityId::ENERGY);
100  }
101 
102  virtual void compute(const Size i,
103  ArrayView<const Size> neighs,
105  ArrayView<Float> f) const override {
106  for (Size k = 0; k < f.size(); ++k) {
107  const Size j = neighs[k];
108  const Float chi = abs(u[j] - u[i]) / (abs(u[i]) + abs(u[j]) + EPS);
109 
110  Float f1;
111  primary.compute(i, getSingleValueView(j), getSingleValueView(e[k]), getSingleValueView(f1));
112  Float f2;
113  secondary.compute(i, getSingleValueView(j), getSingleValueView(e[k]), getSingleValueView(f2));
114  f[k] = lerp(f1, f2, chi);
115  SPH_ASSERT(f[k] >= 0._f && f[k] <= 1._f, f[k]);
116  }
117  }
118 };
119 
120 // ----------------------------------------------------------------------------------------------------------
121 // EnergyConservingSolver implementation
122 // ----------------------------------------------------------------------------------------------------------
123 
125  const RunSettings& settings,
126  const EquationHolder& eqs)
127  : IAsymmetricSolver(scheduler, settings, eqs)
128  , threadData(scheduler) {
130 
131  partitioner =
132  makeAuto<BlendingPartitioner<SmoothlyDiminishingPartitioner, MonotonicDiminishingPartitioner>>();
133 
134  eqs.setDerivatives(derivatives, settings);
135 }
136 
138  const RunSettings& settings,
139  const EquationHolder& eqs,
141  : EnergyConservingSolver(scheduler, settings, eqs) {
142  if (bc != nullptr) {
143  throw InvalidSetup("ECS does not support boundary conditions yet");
144  }
145 }
146 
147 void EnergyConservingSolver::loop(Storage& storage, Statistics& UNUSED(stats)) {
148  MEASURE_SCOPE("EnergyConservingSolver::loop");
149 
150  ArrayView<const Vector> r, v, dummy;
151  tie(r, v, dummy) = storage.getAll<Vector>(QuantityId::POSITION);
152 
153  // we need to symmetrize kernel in smoothing lenghts to conserve momentum
155 
156  const Float radius = this->getMaxSearchRadius(storage);
157 
158  const IBasicFinder& finder = *this->getFinder(r);
159  // partitioner->initialize(storage);
160 
161  neighList.resize(r.size());
162  gradList.resize(r.size());
163 
164  auto evalDerivatives = [&](const Size i, ThreadData& data) {
165  finder.findAll(i, radius, data.neighs);
166 
167  neighList[i].clear();
168  gradList[i].clear();
169 
170  for (auto& n : data.neighs) {
171  const Size j = n.index;
172  const Float hbar = 0.5_f * (r[i][H] + r[j][H]);
173  SPH_ASSERT(hbar > EPS, hbar);
174  if (i == j || getSqrLength(r[i] - r[j]) >= sqr(kernel.radius() * hbar)) {
175  // aren't actual neighbours
176  continue;
177  }
178  const Vector gr = symmetrizedKernel.grad(r[i], r[j]);
179  SPH_ASSERT(isReal(gr) && dot(gr, r[i] - r[j]) < 0._f, gr, r[i] - r[j]);
180 
181  neighList[i].push(j);
182  gradList[i].push(gr);
183  }
184 
185  derivatives.eval(i, neighList[i], gradList[i]);
186  };
187  parallelFor(scheduler, threadData, 0, r.size(), evalDerivatives);
188 }
189 
190 void EnergyConservingSolver::beforeLoop(Storage& storage, Statistics& stats) {
191  const Float t = stats.getOr<Float>(StatisticsId::RUN_TIME, 0._f);
192  equations.initialize(scheduler, storage, t);
193  derivatives.initialize(storage);
194  const Size particleCnt = storage.getParticleCnt();
195  for (ThreadData& data : threadData) {
196  data.energyChange.resize(particleCnt);
197  data.energyChange.fill(0._f);
198  }
199 }
200 
201 void EnergyConservingSolver::afterLoop(Storage& storage, Statistics& stats) {
202  MEASURE_SCOPE("EnergyConservingSolver::afterLoop");
203 
204  Accumulated& accumulated = derivatives.getAccumulated();
205  accumulated.store(storage);
206 
207  const Float t = stats.getOr<Float>(StatisticsId::RUN_TIME, 0._f);
208  equations.finalize(scheduler, storage, t);
209 
210  // now, we have computed everything that modifies the energy derivatives, so we can override it with stuff
211  // below
212  ArrayView<const Vector> r, v, dv;
213  tie(r, v, dv) = storage.getAll<Vector>(QuantityId::POSITION);
215 
216  // we need to symmetrize kernel in smoothing lenghts to conserve momentum
218 
219  partitioner->initialize(storage);
220 
222  Float dt = stats.getOr<Float>(StatisticsId::TIMESTEP_VALUE, initialDt);
224 
225  auto evalAccelerations = [&](const Size i, ThreadData& data) {
226  data.accelerations.resize(neighList[i].size());
227  derivatives.evalAccelerations(i, neighList[i], gradList[i], data.accelerations);
228 
229  data.energyChange.resize(neighList[i].size());
230  for (Size k = 0; k < neighList[i].size(); ++k) {
231  const Size j = neighList[i][k];
232  const Vector vi12 = v[i] + 0.5_f * dv[i] * dt;
233  const Vector vj12 = v[j] + 0.5_f * dv[j] * dt;
234 
235  data.energyChange[k] = m[i] * dot(vj12 - vi12, data.accelerations[k]);
236  }
237 
238  data.partitions.resize(neighList[i].size());
239  partitioner->compute(i, neighList[i], data.energyChange, data.partitions);
240 
241  du[i] = 0._f;
242  for (Size k = 0; k < neighList[i].size(); ++k) {
243  du[i] += data.partitions[k] * data.energyChange[k] / m[i];
244  }
245  SPH_ASSERT(isReal(du[i]));
246  };
247  parallelFor(scheduler, threadData, 0, r.size(), evalAccelerations);
248 }
249 
250 void EnergyConservingSolver::sanityCheck(const Storage& UNUSED(storage)) const {}
251 
INLINE bool isReal(const AntisymmetricTensor &t)
INLINE ArrayView< T > getSingleValueView(T &value)
Definition: ArrayView.h:167
#define SPH_ASSERT(x,...)
Definition: Assert.h:94
NAMESPACE_SPH_BEGIN
Definition: BarnesHut.cpp:13
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
Logging routines of the run.
constexpr INLINE T max(const T &f1, const T &f2)
Definition: MathBasic.h:20
INLINE T lerp(const T v1, const T v2, const TAmount amount)
Definition: MathUtils.h:341
constexpr Float EPS
Definition: MathUtils.h:30
constexpr INLINE T sqr(const T &f) noexcept
Return a squared value.
Definition: MathUtils.h:67
INLINE int sgn(const T val)
Definition: MathUtils.h:336
INLINE auto abs(const T &f)
Definition: MathUtils.h:276
#define UNUSED(x)
Definition: Object.h:37
#define NAMESPACE_SPH_END
Definition: Object.h:12
#define MEASURE_SCOPE(name)
Definition: Profiler.h:70
@ POSITION
Positions (velocities, accelerations) of particles, always a vector quantity,.
@ ENERGY
Specific internal energy, always a scalar quantity.
@ MASS
Paricles masses, always a scalar 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
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
@ RUN_TIME
Current time of the simulation in code units. Does not necessarily have to be 0 when run starts.
@ TIMESTEP_VALUE
Current value of timestep.
INLINE Float getSqrLength(const Vector &v)
Definition: Vector.h:574
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
void evalAccelerations(const Size idx, ArrayView< const Size > neighs, ArrayView< const Vector > grads, Array< Vector > &dv) const
Storage for accumulating derivatives.
Definition: Accumulated.h:30
void store(Storage &storage)
Stores accumulated values to corresponding quantities.
Definition: Accumulated.cpp:86
INLINE TCounter size() const
Definition: ArrayView.h:101
void resize(const TCounter newSize)
Resizes the array to new size.
Definition: Array.h:215
INLINE void push(U &&u)
Adds new element to the end of the array, resizing the array if necessary.
Definition: Array.h:306
void clear()
Removes all elements from the array, but does NOT release the memory.
Definition: Array.h:434
INLINE TCounter size() const noexcept
Definition: Array.h:193
virtual void compute(const Size i, ArrayView< const Size > neighs, ArrayView< const Float > e, ArrayView< Float > f) const override
virtual void initialize(const Storage &storage) override
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
See Owen 2009: A compatibly differenced total energy conserving form of SPH.
EnergyConservingSolver(IScheduler &scheduler, const RunSettings &settings, const EquationHolder &eqs)
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
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
virtual void compute(const Size UNUSED(i), ArrayView< const Size > UNUSED(neighs), ArrayView< const Float > UNUSED(e), ArrayView< Float > f) const override
virtual void initialize(const Storage &UNUSED(storage)) override
Base class for asymmetric SPH solvers.
IScheduler & scheduler
Scheduler used to parallelize the solver.
Float getMaxSearchRadius(const Storage &storage) const
LutKernel< DIMENSIONS > kernel
Selected SPH kernel.
EquationHolder equations
Holds all equation terms evaluated by the solver.
AutoPtr< ISymmetricFinder > finder
Structure used to search for neighbouring particles.
virtual RawPtr< const IBasicFinder > getFinder(ArrayView< const Vector > r)
Returns a finder, already build using the provided positions.
Interface of objects finding neighbouring particles.
Abstraction of the.
virtual void initialize(const Storage &storage)=0
virtual void compute(const Size i, ArrayView< const Size > neighs, ArrayView< const Float > e, ArrayView< Float > f) const =0
Interface that allows unified implementation of sequential and parallelized versions of algorithms.
Definition: Scheduler.h:27
Thrown when components of the run are mutually incompatible.
Definition: Exceptions.h:24
INLINE Float radius() const noexcept
Definition: Kernel.h:107
virtual void compute(const Size i, ArrayView< const Size > neighs, ArrayView< const Float > e, ArrayView< Float > f) const override
virtual void initialize(const Storage &storage) override
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
virtual void compute(const Size i, ArrayView< const Size > neighs, ArrayView< const Float > e, ArrayView< Float > f) const override
virtual void initialize(const Storage &storage) override
Object holding various statistics about current run.
Definition: Statistics.h:22
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
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
Array< TValue > & getValue(const QuantityId key)
Retrieves a quantity values from the storage, given its key and value type.
Definition: Storage.cpp:191
@ TIMESTEPPING_INITIAL_TIMESTEP