SPH
TimeStepCriterion.cpp
Go to the documentation of this file.
2 #include "io/Logger.h"
3 #include "quantities/IMaterial.h"
4 #include "quantities/Iterate.h"
5 #include "system/Profiler.h"
6 #include "system/Settings.h"
7 #include "system/Statistics.h"
8 #include "thread/ThreadLocal.h"
9 
11 
12 std::ostream& operator<<(std::ostream& stream, const CriterionId id) {
13  switch (id) {
15  stream << "CFL condition";
16  break;
18  stream << "Acceleration";
19  break;
21  stream << "Derivative";
22  break;
24  stream << "Divergence";
25  break;
27  stream << "Maximal value";
28  break;
30  stream << "Default value";
31  break;
33  stream << "Max. change limit";
34  break;
35  default:
37  }
38  return stream;
39 }
40 
41 
42 //-----------------------------------------------------------------------------------------------------------
43 // DerivativeCriterion implementation
44 //-----------------------------------------------------------------------------------------------------------
45 
47 template <typename T>
50  T value = T(0._f);
51  T derivative = T(0._f);
53 
54  MinimalStepTls(const Float UNUSED(power)) {}
55 
57  INLINE void add(const Float step, const T v, const T dv, const Size idx) {
58  if (step < minStep) {
59  minStep = step;
60  value = v;
61  derivative = dv;
62  particleIdx = idx;
63  }
64  }
65 
67  INLINE void add(const MinimalStepTls& other) {
68  this->add(other.minStep, other.value, other.derivative, other.particleIdx);
69  }
70 
71  INLINE Size isDefined() const {
72  return minStep < INFTY;
73  }
74 
77  return minStep;
78  }
79 
81  INLINE void saveStats(Statistics& stats) const {
85  }
86 };
87 
90 template <typename T>
91 struct MeanStepTls {
93 
94  MeanStepTls(const Float power)
95  : mean(power) {}
96 
97  INLINE void add(const Float step, const T UNUSED(v), const T UNUSED(dv), const Float UNUSED(idx)) {
98  mean.accumulate(step);
99  }
100 
101  INLINE void add(const MeanStepTls& other) {
102  mean.accumulate(other.mean);
103  }
104 
106  if (mean.count() > 0) {
107  const Float step = mean.compute();
108  SPH_ASSERT(isReal(step) || step == INFTY, step);
109  return step;
110  } else {
111  return NOTHING;
112  }
113  }
114 
115  INLINE void saveStats(Statistics& UNUSED(stats)) const {
116  // do nothing
117  }
118 };
119 
120 
124  SPH_ASSERT(power < 0._f); // currently not implemented for non-negative powers
125 }
126 
128  Storage& storage,
129  const Float maxStep,
130  Statistics& stats) {
132  if (power < -1.e3_f) {
133  // very high negative power, this is effectively computing minimal timestep
134  return this->computeImpl<MinimalStepTls>(scheduler, storage, maxStep, stats);
135  } else {
136  // generic case, compute a generalized mean of timesteps
137  return this->computeImpl<MeanStepTls>(scheduler, storage, maxStep, stats);
138  }
139 }
140 
141 template <template <typename> class Tls>
142 TimeStep DerivativeCriterion::computeImpl(IScheduler& scheduler,
143  Storage& storage,
144  const Float maxStep,
145  Statistics& stats) {
146  Float totalMinStep = INFTY;
148 
149  // for each first-order quantity ...
150  iterate<VisitorEnum::FIRST_ORDER>(storage, [&](const QuantityId id, auto& v, auto& dv) {
151  SPH_ASSERT(v.size() == dv.size());
152  using T = typename std::decay_t<decltype(v)>::Type;
153 
154  // ... and for each particle ...
155  Tls<T> result(power);
156  ThreadLocal<Tls<T>> tls(scheduler, power);
157 
158  auto functor = [&](const Size i, Tls<T>& tls) {
159  const auto absdv = abs(dv[i]);
160  const auto absv = abs(v[i]);
161  const Float minValue = storage.getMaterialOfParticle(i)->minimal(id);
162  SPH_ASSERT(minValue > 0._f); // some nonzero minimal value must be set for all quantities
163 
166  SPH_ASSERT(vs.size() == dvs.size());
167 
168  for (Size j = 0; j < vs.size(); ++j) {
169  if (abs(vs[j]) < 2._f * minValue) {
170  continue;
171  }
172  const Float value = factor * (vs[j] + minValue) / (dvs[j] + EPS);
173  SPH_ASSERT(isReal(value));
174  tls.add(value, v[i], dv[i], i);
175  }
176  };
177 
178  parallelFor(scheduler, tls, 0, v.size(), functor);
179  // get min step from thread-local results
180  for (Tls<T>& tl : tls) {
181  result.add(tl);
182  }
183 
184  // save statistics
185  const Optional<Float> minStep = result.getStep();
186  if (minStep && minStep.value() < totalMinStep) {
187  totalMinStep = minStep.value();
188  minId = CriterionId::DERIVATIVE;
190  result.saveStats(stats);
191  }
192  });
193 // make sure only 2nd order quanity is positions, they are handled by Acceleration criterion
194 #ifdef SPH_DEBUG
195  Size cnt = 0;
196  for (auto q : storage.getQuantities()) {
197  if (q.quantity.getOrderEnum() == OrderEnum::SECOND) {
198  cnt++;
199  }
200  }
201  SPH_ASSERT(cnt == 1);
202 #endif
203 
204  if (totalMinStep > maxStep) {
205  totalMinStep = maxStep;
207  }
208  return { totalMinStep, minId };
209 }
210 
211 //-----------------------------------------------------------------------------------------------------------
212 // AccelerationCriterion implementation
213 //-----------------------------------------------------------------------------------------------------------
214 
217 }
218 
220  Storage& storage,
221  const Float maxStep,
222  Statistics& UNUSED(stats)) {
224  ArrayView<const Vector> r, v, dv;
225  tie(r, v, dv) = storage.getAll<Vector>(QuantityId::POSITION);
226  struct Tl {
227  Float minStep = INFTY;
228  };
229 
230  auto functor = [&](const Size i, Tl& tl) {
231  const Float dvNorm = getSqrLength(dv[i]);
232  if (dvNorm > EPS) {
233  const Float step = factor * root<4>(sqr(r[i][H]) / dvNorm);
234  SPH_ASSERT(isReal(step) && step > 0._f && step < INFTY);
235  tl.minStep = min(tl.minStep, step);
236  }
237  };
238  Tl result;
239  ThreadLocal<Tl> tls(scheduler);
240  parallelFor(scheduler, tls, 0, r.size(), functor);
241  for (Tl& tl : tls) {
242  result.minStep = min(result.minStep, tl.minStep);
243  }
244 
245  if (result.minStep > maxStep) {
246  return { maxStep, CriterionId::MAXIMAL_VALUE };
247  } else {
248  return { result.minStep, CriterionId::ACCELERATION };
249  }
250 }
251 
252 //-----------------------------------------------------------------------------------------------------------
253 // DivergenceCriterion implementation
254 //-----------------------------------------------------------------------------------------------------------
255 
258 }
259 
261  Storage& storage,
262  const Float maxStep,
263  Statistics& UNUSED(stats)) {
265  if (!storage.has(QuantityId::VELOCITY_DIVERGENCE)) {
266  return { maxStep, CriterionId::MAXIMAL_VALUE };
267  }
269  struct Tl {
270  Float minStep = INFTY;
271  };
272 
273  auto functor = [&](const Size i, Tl& tl) {
274  const Float dv = abs(divv[i]);
275  if (dv > EPS) {
276  const Float step = factor / dv;
277  SPH_ASSERT(isReal(step) && step > 0._f && step < INFTY);
278  tl.minStep = min(tl.minStep, step);
279  }
280  };
281  Tl result;
282  ThreadLocal<Tl> tls(scheduler);
283  parallelFor(scheduler, tls, 0, divv.size(), functor);
284  for (Tl& tl : tls) {
285  result.minStep = min(result.minStep, tl.minStep);
286  }
287 
288  if (result.minStep > maxStep) {
289  return { maxStep, CriterionId::MAXIMAL_VALUE };
290  } else {
291  return { result.minStep, CriterionId::DIVERGENCE };
292  }
293 }
294 
295 //-----------------------------------------------------------------------------------------------------------
296 // CourantCriterion implementation
297 //-----------------------------------------------------------------------------------------------------------
298 
301 }
302 
303 
305  Storage& storage,
306  const Float maxStep,
307  Statistics& UNUSED(stats)) {
309 
312  ArrayView<const Size> neighs;
313  if (storage.has(QuantityId::NEIGHBOUR_CNT)) {
314  neighs = storage.getValue<Size>(QuantityId::NEIGHBOUR_CNT);
315  }
316 
317  struct Tl {
318  Float minStep = INFTY;
319  };
320 
321  auto functor = [&](const Size i, Tl& tl) {
322  if (cs[i] > 0._f) {
323  const Float value = courant * r[i][H] / cs[i];
324  SPH_ASSERT(isReal(value) && value > 0._f && value < INFTY);
325  tl.minStep = min(tl.minStep, value);
326  }
327  };
328  Tl result;
329  ThreadLocal<Tl> tls(scheduler);
330  parallelFor(scheduler, tls, 0, r.size(), functor);
331  for (Tl& tl : tls) {
332  result.minStep = min(result.minStep, tl.minStep);
333  }
334 
335  if (result.minStep > maxStep) {
336  return { maxStep, CriterionId::MAXIMAL_VALUE };
337  } else {
338  return { result.minStep, CriterionId::CFL_CONDITION };
339  }
340 }
341 
342 //-----------------------------------------------------------------------------------------------------------
343 // MultiCriterion implementation
344 //-----------------------------------------------------------------------------------------------------------
345 
347  const Flags<TimeStepCriterionEnum> flags =
349  if (flags.has(TimeStepCriterionEnum::COURANT)) {
350  criteria.push(makeAuto<CourantCriterion>(settings));
351  }
353  criteria.push(makeAuto<DerivativeCriterion>(settings));
354  }
356  criteria.push(makeAuto<AccelerationCriterion>(settings));
357  }
359  criteria.push(makeAuto<DivergenceCriterion>(settings));
360  }
361 
362  maxChange = settings.get<Float>(RunSettingsId::TIMESTEPPING_MAX_INCREASE);
364 }
365 
367  const Float maxChange,
368  const Float initial)
369  : criteria(std::move(criteria))
370  , maxChange(maxChange)
371  , lastStep(initial) {}
372 
374  Storage& storage,
375  const Float maxStep,
376  Statistics& stats) {
378  SPH_ASSERT(!criteria.empty());
379  Float minStep = INFTY;
381  for (auto& crit : criteria) {
382  const TimeStep step = crit->compute(scheduler, storage, maxStep, stats);
383  if (step.value < minStep) {
384  minStep = step.value;
385  minId = step.id;
386  }
387  }
388 
389  // smooth the timestep if required
390  if (maxChange < INFTY) {
391  const Float maxStep = lastStep * (1._f + maxChange);
392  if (minStep > maxStep) {
393  minStep = maxStep;
394  minId = CriterionId::MAX_CHANGE;
395  }
396  lastStep = minStep;
397  }
398 
399  // we don't have to limit by maxStep as each criterion is limited separately
400  SPH_ASSERT(minStep < INFTY);
401  return { minStep, minId };
402 }
403 
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
NAMESPACE_SPH_BEGIN
Definition: BarnesHut.cpp:13
INLINE StaticArray< Float, 6 > getComponents(const T &value)
Returns the components of the object in array.
Definition: Generic.h:59
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.
Functions for iterating over individual quantities in Storage.
Logging routines of the run.
#define VERBOSE_LOG
Helper macro, creating.
Definition: Logger.h:242
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
INLINE Float root< 4 >(const Float f)
Definition: MathUtils.h:109
constexpr INLINE T sqr(const T &f) noexcept
Return a squared value.
Definition: MathUtils.h:67
constexpr Float INFTY
Definition: MathUtils.h:38
INLINE auto abs(const T &f)
Definition: MathUtils.h:276
#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
Tool to measure time spent in functions and profile the code.
QuantityId
Unique IDs of basic quantities of SPH particles.
Definition: QuantityIds.h:19
@ VELOCITY_DIVERGENCE
Velocity divergence.
@ POSITION
Positions (velocities, accelerations) of particles, always a vector quantity,.
@ NEIGHBOUR_CNT
Number of neighbouring particles (in radius h * kernel.radius)
@ SOUND_SPEED
Sound speed, always a scalar quantity.
@ SECOND
Quantity with 1st and 2nd derivative.
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
Statistics gathered and periodically displayed during the run.
@ LIMITING_PARTICLE_IDX
Index of particle that currently limits the timestep.
@ LIMITING_VALUE
Quantity value of particle that currently limits the timestep.
@ LIMITING_QUANTITY
Quantity that currently limits the timestep.
@ LIMITING_DERIVATIVE
Derivative value of particle that currently limits the timestep.
Template for thread-local storage.
NAMESPACE_SPH_BEGIN std::ostream & operator<<(std::ostream &stream, const CriterionId id)
Criteria for computing the time step.
CriterionId
@ MAX_CHANGE
Timestep is limited by the maximum allowed change from previous timestep.
@ DIVERGENCE
Timestep computed by velocity divergence.
@ INITIAL_VALUE
Timestep is not computed, using given initial value.
@ MAXIMAL_VALUE
Timestep given by selected maximal value.
@ CFL_CONDITION
Timestep computed using CFL condition.
@ ACCELERATION
Timestep constrained by acceleration condition.
@ DERIVATIVE
Timestep based on value-to-derivative ratio.
INLINE Float getSqrLength(const Vector &v)
Definition: Vector.h:574
@ H
Definition: Vector.h:25
AccelerationCriterion(const RunSettings &settings)
virtual TimeStep compute(IScheduler &scheduler, Storage &storage, Float maxStep, Statistics &stats) override
Computes the value of the time step.
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
INLINE bool empty() const noexcept
Definition: Array.h:201
virtual TimeStep compute(IScheduler &scheduler, Storage &storage, Float maxStep, Statistics &stats) override
Storage must contain at least positions of particles and sound speed, checked by assert.
CourantCriterion(const RunSettings &settings)
virtual TimeStep compute(IScheduler &scheduler, Storage &storage, Float maxStep, Statistics &stats) override
Computes the value of the time step.
DerivativeCriterion(const RunSettings &settings)
virtual TimeStep compute(IScheduler &scheduler, Storage &storage, Float maxStep, Statistics &stats) override
Computes the value of the time step.
DivergenceCriterion(const RunSettings &settings)
Convenient object for storing a single value of different types.
Definition: Dynamic.h:35
Wrapper of an integral value providing functions for reading and modifying individual bits.
Definition: Flags.h:20
constexpr INLINE bool has(const TEnum flag) const
Checks if the object has a given flag.
Definition: Flags.h:77
Interface that allows unified implementation of sequential and parallelized versions of algorithms.
Definition: Scheduler.h:27
virtual TimeStep compute(IScheduler &scheduler, Storage &storage, const Float maxStep, Statistics &stats) override
Computes the value of the time step.
MultiCriterion(const RunSettings &settings)
Generalized mean with negative (runtime) power.
Definition: Means.h:137
INLINE void accumulate(const Float value)
Definition: Means.h:142
INLINE Float compute() const
Definition: Means.h:159
INLINE Type & value()
Returns the reference to the stored value.
Definition: Optional.h:172
INLINE Size count() const
Definition: Means.h:124
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
Flags< TValue > getFlags(const TEnum idx) const
Returns Flags from underlying value stored in settings.
Definition: Settings.h:348
Array with fixed number of allocated elements.
Definition: StaticArray.h:19
INLINE TCounter size() const
Returns the current size of the array (number of constructed elements).
Definition: StaticArray.h:147
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
MaterialView getMaterialOfParticle(const Size particleIdx) const
Returns material view for material of given particle.
Definition: Storage.cpp:372
StaticArray< Array< TValue > &, 3 > getAll(const QuantityId key)
Retrieves quantity buffers from the storage, given its key and value type.
Definition: Storage.cpp:163
StorageSequence getQuantities()
Returns the sequence of quantities.
Definition: Storage.cpp:416
bool has(const QuantityId key) const
Checks if the storage contains quantity with given key.
Definition: Storage.cpp:130
Array< TValue > & getValue(const QuantityId key)
Retrieves a quantity values from the storage, given its key and value type.
Definition: Storage.cpp:191
Template for storing a copy of a value for every thread in given scheduler.
Definition: ThreadLocal.h:36
Generic storage and input/output routines of settings.
TimeStepCriterionEnum
Definition: Settings.h:567
@ DIVERGENCE
Time step computed from velocity divergence.
@ DERIVATIVES
Time step computed by limiting value-to-derivative ratio of quantiites.
@ COURANT
Time step determined using CFL condition.
@ ACCELERATION
Time step computed from ratio of acceleration and smoothing length.
@ TIMESTEPPING_INITIAL_TIMESTEP
@ TIMESTEPPING_DERIVATIVE_FACTOR
Multiplicative factor k for the derivative criterion; dt = k * v / dv.
@ TIMESTEPPING_MAX_INCREASE
@ TIMESTEPPING_COURANT_NUMBER
Courant number.
@ TIMESTEPPING_DIVERGENCE_FACTOR
Multiplicative factor for the divergence criterion.
Overload of std::swap for Sph::Array.
Definition: Array.h:578
NegativeMean mean
INLINE void add(const Float step, const T UNUSED(v), const T UNUSED(dv), const Float UNUSED(idx))
INLINE void add(const MeanStepTls &other)
MeanStepTls(const Float power)
INLINE Optional< Float > getStep() const
INLINE void saveStats(Statistics &UNUSED(stats)) const
Helper class storing a minimal value of time step and corresponding statistics.
INLINE void add(const Float step, const T v, const T dv, const Size idx)
Add a time step to the set, given also value, derivative and particle index.
INLINE Optional< Float > getStep() const
Return the computed time step.
MinimalStepTls(const Float UNUSED(power))
INLINE void add(const MinimalStepTls &other)
Add a time step computed by other TLS.
INLINE void saveStats(Statistics &stats) const
Save auxiliary statistics.
INLINE Size isDefined() const
Float value
Value of the time step in code units (currently SI).
CriterionId id
Criterion applied to compute the time step;.