SPH
TimeStepping.cpp
Go to the documentation of this file.
2 #include "quantities/IMaterial.h"
3 #include "quantities/Iterate.h"
4 #include "system/Factory.h"
5 #include "system/Profiler.h"
6 #include "system/Statistics.h"
7 #include "thread/Scheduler.h"
8 #include "timestepping/ISolver.h"
10 
12 
14  const RunSettings& settings,
15  AutoPtr<ITimeStepCriterion>&& criterion)
16  : storage(storage)
17  , criterion(std::move(criterion)) {
20 }
21 
23  : ITimeStepping(storage, settings, Factory::getTimeStepCriterion(settings)) {}
24 
26 
27 void ITimeStepping::step(IScheduler& scheduler, ISolver& solver, Statistics& stats) {
28  Timer timer;
29  this->stepImpl(scheduler, solver, stats);
30  // update time step
32  if (criterion) {
33  const TimeStep result = criterion->compute(scheduler, *storage, maxTimeStep, stats);
34  timeStep = result.value;
35  criterionId = result.id;
36  }
38  stats.set(StatisticsId::TIMESTEP_CRITERION, criterionId);
40 }
41 
42 //-----------------------------------------------------------------------------------------------------------
43 // Helper functions for stepping
44 //-----------------------------------------------------------------------------------------------------------
45 
46 template <typename TFunc>
47 static void stepFirstOrder(Storage& storage, IScheduler& scheduler, const TFunc& stepper) {
48 
49  // note that derivatives are not advanced in time, but cannot be const as they might be clamped
50  auto process = [&](const QuantityId id, auto& x, auto& dx) {
51  SPH_ASSERT(x.size() == dx.size());
52 
53  parallelFor(scheduler, 0, x.size(), [&](const Size i) INL {
54  stepper(x[i], asConst(dx[i]));
55  const Interval range = storage.getMaterialOfParticle(i)->range(id);
56  if (range != Interval::unbounded()) {
57  tie(x[i], dx[i]) = clampWithDerivative(x[i], dx[i], range);
58  }
59  });
60  };
61 
62  iterate<VisitorEnum::FIRST_ORDER>(storage, process);
63 }
64 
65 template <typename TFunc>
66 static void stepSecondOrder(Storage& storage, IScheduler& scheduler, const TFunc& stepper) {
67 
68  auto process = [&](const QuantityId id, auto& r, auto& v, const auto& dv) {
69  SPH_ASSERT(r.size() == v.size() && r.size() == dv.size());
70 
71  parallelFor(scheduler, 0, r.size(), [&](const Size i) INL {
72  stepper(r[i], v[i], dv[i]);
74  const Interval range = storage.getMaterialOfParticle(i)->range(id);
75  if (range != Interval::unbounded()) {
76  tie(r[i], v[i]) = clampWithDerivative(r[i], v[i], range);
77  }
78  });
79  };
80 
81  iterate<VisitorEnum::SECOND_ORDER>(storage, process);
82 }
83 
84 template <typename TFunc>
85 static void stepFirstOrder(Storage& storage1,
86  Storage& storage2,
87  IScheduler& scheduler,
88  const TFunc& stepper) {
89 
90  auto processPair = [&](QuantityId id, auto& px, auto& pdx, const auto& cx, const auto& cdx) {
91  SPH_ASSERT(px.size() == pdx.size());
92  SPH_ASSERT(cdx.size() == px.size());
93  SPH_ASSERT(cx.empty());
94 
95  parallelFor(scheduler, 0, px.size(), [&](const Size i) {
96  stepper(px[i], pdx[i], cdx[i]);
97 
98  const Interval range = storage1.getMaterialOfParticle(i)->range(id);
99  if (range != Interval::unbounded()) {
100  tie(px[i], pdx[i]) = clampWithDerivative(px[i], pdx[i], range);
101  }
102  });
103  };
104 
105  iteratePair<VisitorEnum::FIRST_ORDER>(storage1, storage2, processPair);
106 }
107 
109 template <typename TFunc>
110 static void stepPairFirstOrder(Storage& storage1,
111  Storage& storage2,
112  IScheduler& scheduler,
113  const TFunc& stepper) {
114 
115  auto processPair = [&](QuantityId id, auto& px, auto& pdx, const auto& cx, const auto& cdx) {
116  SPH_ASSERT(px.size() == pdx.size());
117  SPH_ASSERT(cdx.size() == px.size());
118  SPH_ASSERT(cx.size() == cdx.size());
119 
120  parallelFor(scheduler, 0, px.size(), [&](const Size i) {
121  stepper(px[i], pdx[i], cx[i], cdx[i]);
122 
123  const Interval range = storage1.getMaterialOfParticle(i)->range(id);
124  if (range != Interval::unbounded()) {
125  tie(px[i], pdx[i]) = clampWithDerivative(px[i], pdx[i], range);
126  }
127  });
128  };
129 
130  iteratePair<VisitorEnum::FIRST_ORDER>(storage1, storage2, processPair);
131 }
132 
133 template <typename TFunc>
134 static void stepSecondOrder(Storage& storage1,
135  Storage& storage2,
136  IScheduler& scheduler,
137  const TFunc& stepper) {
138 
139  auto processPair = [&](QuantityId id,
140  auto& pr,
141  auto& pv,
142  const auto& pdv,
143  const auto& cr,
144  const auto& cv,
145  const auto& cdv) {
146  SPH_ASSERT(pr.size() == pv.size() && pr.size() == pdv.size());
147  SPH_ASSERT(cdv.size() == pr.size());
148  SPH_ASSERT(cr.empty());
149  SPH_ASSERT(cv.empty());
150 
151  parallelFor(scheduler, 0, pr.size(), [&](const Size i) {
152  stepper(pr[i], pv[i], pdv[i], cdv[i]);
153 
154  const Interval range = storage1.getMaterialOfParticle(i)->range(id);
155  if (range != Interval::unbounded()) {
156  tie(pr[i], pv[i]) = clampWithDerivative(pr[i], pv[i], range);
157  }
158  });
159  };
160 
161  iteratePair<VisitorEnum::SECOND_ORDER>(storage1, storage2, processPair);
162 }
163 
164 template <typename TFunc>
165 static void stepPairSecondOrder(Storage& storage1,
166  Storage& storage2,
167  IScheduler& scheduler,
168  const TFunc& stepper) {
169 
170  auto processPair = [&](QuantityId id,
171  auto& pr,
172  auto& pv,
173  const auto& pdv,
174  const auto& cr,
175  const auto& cv,
176  const auto& cdv) {
177  SPH_ASSERT(pr.size() == pv.size() && pr.size() == pdv.size());
178  SPH_ASSERT(cdv.size() == pr.size());
179  SPH_ASSERT(cr.size() == cdv.size());
180  SPH_ASSERT(cv.size() == cdv.size());
181 
182  parallelFor(scheduler, 0, pr.size(), [&](const Size i) {
183  stepper(pr[i], pv[i], pdv[i], cr[i], cv[i], cdv[i]);
184 
185  const Interval range = storage1.getMaterialOfParticle(i)->range(id);
186  if (range != Interval::unbounded()) {
187  tie(pr[i], pv[i]) = clampWithDerivative(pr[i], pv[i], range);
188  }
189  });
190  };
191 
192  iteratePair<VisitorEnum::SECOND_ORDER>(storage1, storage2, processPair);
193 }
194 
195 //-----------------------------------------------------------------------------------------------------------
196 // EulerExplicit implementation
197 //-----------------------------------------------------------------------------------------------------------
198 
199 void EulerExplicit::stepImpl(IScheduler& scheduler, ISolver& solver, Statistics& stats) {
201 
202  // clear derivatives from previous timestep
204 
205  // compute derivatives
206  solver.integrate(*storage, stats);
207 
208  PROFILE_SCOPE("EulerExplicit::step")
209  const Float dt = timeStep;
210 
211  // advance velocities
212  stepSecondOrder(*storage, scheduler, [dt](auto& UNUSED(r), auto& v, const auto& dv) INL { //
213  using Type = typename std::decay_t<decltype(v)>;
214  v += Type(dv * dt);
215  });
216  // find positions and velocities after collision (at the beginning of the time step
217  solver.collide(*storage, stats, timeStep);
218  // advance positions
219  stepSecondOrder(*storage, scheduler, [dt](auto& r, auto& v, const auto& UNUSED(dv)) INL { //
220  using Type = typename std::decay_t<decltype(v)>;
221  r += Type(v * dt);
222  });
223 
224  // simply advance first order quanties
225  stepFirstOrder(*storage, scheduler, [dt](auto& x, const auto& dx) INL { //
226  using Type = typename std::decay_t<decltype(x)>;
227  x += Type(dx * dt);
228  });
229 
231 }
232 
233 //-----------------------------------------------------------------------------------------------------------
234 // PredictorCorrector implementation
235 //-----------------------------------------------------------------------------------------------------------
236 
238  : ITimeStepping(storage, settings) {
239  SPH_ASSERT(storage->getQuantityCnt() > 0); // quantities must already been emplaced
240 
241  // we need to keep a copy of the highest derivatives (predictions)
242  predictions = makeShared<Storage>(storage->clone(VisitorEnum::HIGHEST_DERIVATIVES));
243  storage->addDependent(predictions);
244 
245  // clear derivatives before using them in step method
247 }
248 
250 
252  PROFILE_SCOPE("PredictorCorrector::predictions")
253  const Float dt = timeStep;
254  const Float dt2 = 0.5_f * sqr(dt);
256  stepSecondOrder(*storage, scheduler, [dt, dt2](auto& r, auto& v, const auto& dv) INL {
257  using Type = typename std::decay_t<decltype(v)>;
258  r += Type(v * dt + dv * dt2);
259  v += Type(dv * dt);
260  });
261  stepFirstOrder(*storage, scheduler, [dt](auto& x, const auto& dx) INL { //
262  using Type = typename std::decay_t<decltype(x)>;
263  x += Type(dx * dt);
264  });
265 }
266 
268  PROFILE_SCOPE("PredictorCorrector::step Corrections");
269  const Float dt = timeStep;
270  const Float dt2 = 0.5_f * sqr(dt);
271  constexpr Float a = 1._f / 3._f;
272  constexpr Float b = 0.5_f;
273 
274  stepSecondOrder(*storage,
275  *predictions,
276  scheduler,
277  [a, b, dt, dt2](auto& pr, auto& pv, const auto& pdv, const auto& cdv) {
278  using Type = typename std::decay_t<decltype(pr)>;
279  pr -= Type(a * (cdv - pdv) * dt2);
280  pv -= Type(b * (cdv - pdv) * dt);
281  });
282 
283  stepFirstOrder(*storage, *predictions, scheduler, [dt](auto& px, const auto& pdx, const auto& cdx) {
284  using Type = typename std::decay_t<decltype(px)>;
285  px -= Type(0.5_f * (cdx - pdx) * dt);
286  });
287 }
288 
289 void PredictorCorrector::stepImpl(IScheduler& scheduler, ISolver& solver, Statistics& stats) {
291 
292  // make predictions
293  this->makePredictions(scheduler);
294 
295  // save derivatives from predictions
297 
298  // clear derivatives
300 
301  // compute derivatives
302  solver.integrate(*storage, stats);
303  SPH_ASSERT(storage->getParticleCnt() == predictions->getParticleCnt(),
305  predictions->getParticleCnt());
306 
307  // make corrections
308  this->makeCorrections(scheduler);
309 
311 }
312 
313 //-----------------------------------------------------------------------------------------------------------
314 // Leapfrog implementation
315 //-----------------------------------------------------------------------------------------------------------
316 
317 void LeapFrog::stepImpl(IScheduler& scheduler, ISolver& solver, Statistics& stats) {
319 
320  // move positions by half a timestep (drift)
321  const Float dt = timeStep;
322  solver.collide(*storage, stats, 0.5_f * dt);
323  stepSecondOrder(*storage, scheduler, [dt](auto& r, const auto& v, const auto& UNUSED(dv)) INL { //
324  using Type = typename std::decay_t<decltype(v)>;
325  r += Type(v * 0.5_f * dt);
326  });
327 
328  // compute the derivatives
330  solver.integrate(*storage, stats);
331 
332  // integrate first-order quantities as in Euler
334  stepFirstOrder(*storage, scheduler, [dt](auto& x, const auto& dx) INL { //
335  using Type = typename std::decay_t<decltype(x)>;
336  x += Type(dx * dt);
337  });
338 
339 
340  // move velocities by full timestep (kick)
341  stepSecondOrder(*storage, scheduler, [dt](auto& UNUSED(r), auto& v, const auto& dv) INL { //
342  using Type = typename std::decay_t<decltype(v)>;
343  v += Type(dv * dt);
344  });
345 
346  // evaluate collisions
347  solver.collide(*storage, stats, 0.5_f * dt);
348 
349  // move positions by another half timestep (drift)
350  stepSecondOrder(*storage, scheduler, [dt](auto& r, auto& v, const auto& UNUSED(dv)) INL { //
351  using Type = typename std::decay_t<decltype(v)>;
352  r += Type(v * 0.5_f * dt);
353  });
354 
356 }
357 
358 //-----------------------------------------------------------------------------------------------------------
359 // RungeKutta implementation
360 //-----------------------------------------------------------------------------------------------------------
361 
362 RungeKutta::RungeKutta(const SharedPtr<Storage>& storage, const RunSettings& settings)
363  : ITimeStepping(storage, settings) {
364  SPH_ASSERT(storage->getQuantityCnt() > 0); // quantities must already been emplaced
365  k1 = makeShared<Storage>(storage->clone(VisitorEnum::ALL_BUFFERS));
366  k2 = makeShared<Storage>(storage->clone(VisitorEnum::ALL_BUFFERS));
367  k3 = makeShared<Storage>(storage->clone(VisitorEnum::ALL_BUFFERS));
368  k4 = makeShared<Storage>(storage->clone(VisitorEnum::ALL_BUFFERS));
369 
370  storage->addDependent(k1);
371  storage->addDependent(k2);
372  storage->addDependent(k3);
373  storage->addDependent(k4);
374 
375  // clear derivatives before using them in step method
377 }
378 
379 RungeKutta::~RungeKutta() = default;
380 
382  Statistics& stats,
383  Storage& k,
384  const Float m,
385  const Float n) {
387  solver.integrate(k, stats);
388  iteratePair<VisitorEnum::FIRST_ORDER>(
389  k, *storage, [&](const QuantityId UNUSED(id), auto& kv, auto& kdv, auto& v, auto&) {
390  using Type = typename std::decay_t<decltype(kv)>::Type;
391  for (Size i = 0; i < v.size(); ++i) {
392  kv[i] += Type(kdv[i] * m * this->timeStep);
393  v[i] += Type(kdv[i] * n * this->timeStep);
394  }
395  });
396  iteratePair<VisitorEnum::SECOND_ORDER>(k,
397  *storage,
398  [&](const QuantityId UNUSED(id), auto& kv, auto& kdv, auto& kd2v, auto& v, auto& dv, auto&) {
399  using Type = typename std::decay_t<decltype(kv)>::Type;
400  for (Size i = 0; i < v.size(); ++i) {
401  kv[i] += Type(kdv[i] * m * this->timeStep);
402  kdv[i] += Type(kd2v[i] * m * this->timeStep);
403  v[i] += Type(kdv[i] * n * this->timeStep);
404  dv[i] += Type(kd2v[i] * n * this->timeStep);
405  }
406  });
407 }
408 
409 void RungeKutta::stepImpl(IScheduler& UNUSED(scheduler), ISolver& solver, Statistics& stats) {
414 
415  solver.integrate(*k1, stats);
416  integrateAndAdvance(solver, stats, *k1, 0.5_f, 1._f / 6._f);
417  // swap values of 1st order quantities and both values and 1st derivatives of 2nd order quantities
419 
421  // compute k2 derivatives based on values computes in previous integration
422  solver.integrate(*k2, stats);
424  integrateAndAdvance(solver, stats, *k2, 0.5_f, 1._f / 3._f);
426 
427  solver.integrate(*k3, stats);
428  integrateAndAdvance(solver, stats, *k3, 0.5_f, 1._f / 3._f);
430 
431  solver.integrate(*k4, stats);
432 
433  iteratePair<VisitorEnum::FIRST_ORDER>(
434  *storage, *k4, [this](const QuantityId UNUSED(id), auto& v, auto&, auto&, auto& kdv) {
435  using Type = typename std::decay_t<decltype(v)>::Type;
436  for (Size i = 0; i < v.size(); ++i) {
437  v[i] += Type(this->timeStep / 6._f * kdv[i]);
438  }
439  });
440  iteratePair<VisitorEnum::SECOND_ORDER>(*storage,
441  *k4,
442  [this](const QuantityId UNUSED(id), auto& v, auto& dv, auto&, auto&, auto& kdv, auto& kd2v) {
443  using Type = typename std::decay_t<decltype(v)>::Type;
444  for (Size i = 0; i < v.size(); ++i) {
445  dv[i] += Type(this->timeStep / 6._f * kd2v[i]);
446  v[i] += Type(this->timeStep / 6._f * kdv[i]);
447  }
448  });
449 }
450 
451 //-----------------------------------------------------------------------------------------------------------
452 // ModifiedMidpointMethod implementation
453 //-----------------------------------------------------------------------------------------------------------
454 
456  : ITimeStepping(storage, settings) {
458  mid = makeShared<Storage>(storage->clone(VisitorEnum::ALL_BUFFERS));
459 
460  // connect the storage in the other direction, as we call solver with mid
461  mid->addDependent(storage);
462 }
463 
465  const Float h = timeStep / n; // current substep
466 
467  solver.collide(*storage, stats, h);
468  // do first (half)step using current derivatives, save values to mid
469  stepPairSecondOrder(*mid,
470  *storage,
471  scheduler,
472  [h](auto& pr, auto& pv, const auto&, const auto& cr, const auto& cv, const auto& cdv) INL {
473  using Type = typename std::decay_t<decltype(cv)>;
474  pv = Type(cv + h * cdv);
475  pr = Type(cr + h * cv);
476  SPH_ASSERT(isReal(pv) && isReal(pr));
477  });
478  stepPairFirstOrder(*mid,
479  *storage,
480  scheduler,
481  [h](auto& px, const auto& UNUSED(pdx), const auto& cx, const auto& cdx) INL { //
482  using Type = typename std::decay_t<decltype(cx)>;
483  px = Type(cx + h * cdx);
484  SPH_ASSERT(isReal(px));
485  });
486 
487  mid->zeroHighestDerivatives();
488  // evaluate the derivatives, using the advanced values
489  solver.integrate(*mid, stats);
490 
491  // now mid is half-step ahead of the storage in both values and derivatives
492 
493  // do (n-1) steps, keeping mid half-step ahead of the storage
494  for (Size iter = 0; iter < n - 1; ++iter) {
495  solver.collide(*storage, stats, 2._f * h);
496  stepPairSecondOrder(*storage,
497  *mid,
498  scheduler,
499  [h](auto& pr,
500  auto& pv,
501  const auto& UNUSED(pdv),
502  const auto& UNUSED(cr),
503  const auto& cv,
504  const auto& cdv) INL {
505  using Type = typename std::decay_t<decltype(pr)>;
506  pv += Type(2._f * h * cdv);
507  pr += Type(2._f * h * cv);
508  SPH_ASSERT(isReal(pv) && isReal(pr));
509  });
510  stepPairFirstOrder(*storage,
511  *mid,
512  scheduler,
513  [h](auto& px, const auto& UNUSED(pdx), const auto& UNUSED(cx), const auto& cdx) INL { //
514  using Type = typename std::decay_t<decltype(px)>;
515  px += Type(2._f * h * cdx);
516  SPH_ASSERT(isReal(px));
517  });
519  mid->zeroHighestDerivatives();
520  solver.integrate(*mid, stats);
521  }
522 
523  // last step
524  solver.collide(*storage, stats, h);
525  stepPairSecondOrder(*storage,
526  *mid,
527  scheduler,
528  [h](auto& pr, auto& pv, const auto& UNUSED(pdv), auto& cr, const auto& cv, const auto& cdv) INL {
529  using Type = typename std::decay_t<decltype(pr)>;
530  pv = Type(0.5_f * (pv + cv + h * cdv));
531  pr = Type(0.5_f * (pr + cr + h * cv));
532  SPH_ASSERT(isReal(pv) && isReal(pr));
533  });
534  stepPairFirstOrder(*storage,
535  *mid,
536  scheduler,
537  [h](auto& px, const auto& UNUSED(pdx), const auto& cx, const auto& cdx) INL {
538  using Type = typename std::decay_t<decltype(px)>;
539  px = Type(0.5_f * (px + cx + h * cdx));
540  SPH_ASSERT(isReal(px));
541  });
542 }
543 
544 //-----------------------------------------------------------------------------------------------------------
545 // BulirschStoer implementation
546 //-----------------------------------------------------------------------------------------------------------
547 
548 constexpr Size BS_SIZE = 9;
549 const StaticArray<Size, BS_SIZE> BS_STEPS = { 2, 4, 6, 8, 10, 12, 14, 16, 18 };
550 
551 template <typename T, Size Dim1, Size Dim2>
553 
555  : ITimeStepping(storage, settings) {
557 
558  /*const Float safe1 = 0.25_f;
559  const Float safe2 = 0.7_f;*/
560 
561  // compute the work coefficients A_i
563  A[0] = BS_STEPS[0] + 1;
564  for (Size i = 0; i < BS_SIZE; ++i) {
565  A[i + 1] = A[i] + BS_STEPS[i + 1];
566  }
567 
568  // compute the correction factors alpha(k, q)
570 
571 #ifdef SPH_DEBUG
572  for (auto& row : alpha) {
573  row.fill(NAN);
574  }
575 #endif
576 
577  for (Size q = 0; q < BS_SIZE; ++q) {
578  alpha[q][q] = 1._f;
579 
580  for (Size k = 0; k < q; ++k) {
581  alpha[k][q] = (A[k + 1] - A[q + 1]) / std::pow(eps, (2 * k + 1) * (A[q + 1] - A[0] + 1));
582  }
583  }
584 
585  // determine the optimal row number of convergence
586  Size rowNumber = 0;
587  (void)rowNumber;
588  for (Size i = 1; i < BS_SIZE; ++i) {
589  SPH_ASSERT(isReal(alpha[i - 1][i]));
590  if (A[i + 1] > A[i] * alpha[i - 1][i]) {
591  rowNumber = i;
592  }
593  }
594  SPH_ASSERT(rowNumber > 0._f);
595 }
596 
597 void BulirschStoer::stepImpl(IScheduler& UNUSED(scheduler), ISolver& solver, Statistics& stats) {
598  (void)solver;
599  (void)stats;
600 }
601 
INLINE bool isReal(const AntisymmetricTensor &t)
#define SPH_ASSERT(x,...)
Definition: Assert.h:94
NAMESPACE_SPH_BEGIN
Definition: BarnesHut.cpp:13
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.
Functions for iterating over individual quantities in Storage.
#define VERBOSE_LOG
Helper macro, creating.
Definition: Logger.h:242
constexpr INLINE T sqr(const T &f) noexcept
Return a squared value.
Definition: MathUtils.h:67
constexpr INLINE Float pow(const Float v)
Power for floats.
#define UNUSED(x)
Definition: Object.h:37
#define NAMESPACE_SPH_END
Definition: Object.h:12
#define INL
Definition: Object.h:32
Tool to measure time spent in functions and profile the code.
#define PROFILE_SCOPE(name)
Definition: Profiler.h:175
QuantityId
Unique IDs of basic quantities of SPH particles.
Definition: QuantityIds.h:19
Interface for executing tasks (potentially) asynchronously.
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.
@ TIMESTEP_VALUE
Current value of timestep.
@ TIMESTEP_CRITERION
Criterion that currently limits the timestep.
@ TIMESTEP_ELAPSED
Wallclock time spend on computing last timestep.
Criteria for computing the time step.
CriterionId
@ INITIAL_VALUE
Timestep is not computed, using given initial value.
constexpr Size BS_SIZE
const StaticArray< Size, BS_SIZE > BS_STEPS
Algorithms for temporal evolution of the physical model.
virtual void stepImpl(IScheduler &scheduler, ISolver &solver, Statistics &stats) override
BulirschStoer(const SharedPtr< Storage > &storage, const RunSettings &settings)
virtual void stepImpl(IScheduler &scheduler, ISolver &solver, Statistics &stats) override
Interface that allows unified implementation of sequential and parallelized versions of algorithms.
Definition: Scheduler.h:27
Base class for all solvers.
Definition: ISolver.h:20
virtual void integrate(Storage &storage, Statistics &stats)=0
Computes derivatives of all time-dependent quantities.
virtual void collide(Storage &UNUSED(storage), Statistics &UNUSED(stats), const Float UNUSED(dt))
Detects the collisions and computes new positions of particles.
Definition: ISolver.h:54
virtual TimeStep compute(IScheduler &scheduler, Storage &storage, Float maxStep, Statistics &stats)=0
Computes the value of the time step.
Base object providing integration in time for all quantities.
Definition: TimeStepping.h:46
Float timeStep
Current time step.
Definition: TimeStepping.h:52
SharedPtr< Storage > storage
Main storage holding all the particles in the run.
Definition: TimeStepping.h:49
virtual void stepImpl(IScheduler &scheduler, ISolver &solver, Statistics &stats)=0
AutoPtr< ITimeStepCriterion > criterion
Criterion used to compute the time step.
Definition: TimeStepping.h:58
~ITimeStepping() override
Float maxTimeStep
Maximal allowed time step.
Definition: TimeStepping.h:55
void step(IScheduler &scheduler, ISolver &solver, Statistics &stats)
ITimeStepping(const SharedPtr< Storage > &storage, const RunSettings &settings)
Constructs the timestepping, using timestep criteria from parameters in settings.
virtual void stepImpl(IScheduler &scheduler, ISolver &solver, Statistics &stats) override
ModifiedMidpointMethod(const SharedPtr< Storage > &storage, const RunSettings &settings)
virtual void stepImpl(IScheduler &scheduler, ISolver &solver, Statistics &stats) override
virtual void stepImpl(IScheduler &scheduler, ISolver &solver, Statistics &stats) override
void makePredictions(IScheduler &scheduler)
void makeCorrections(IScheduler &scheduler)
PredictorCorrector(const SharedPtr< Storage > &storage, const RunSettings &settings)
~PredictorCorrector() override
virtual void stepImpl(IScheduler &scheduler, ISolver &solver, Statistics &stats) override
void integrateAndAdvance(ISolver &solver, Statistics &stats, Storage &k, const Float m, const Float n)
~RungeKutta() override
RungeKutta(const SharedPtr< Storage > &storage, const RunSettings &settings)
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
Array with fixed number of allocated elements.
Definition: StaticArray.h:19
void fill(const T &value)
Assigns a value to all constructed elements of the array.
Definition: StaticArray.h:121
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
Outcome isValid(const Flags< ValidFlag > flags=ValidFlag::COMPLETE) const
Checks whether the storage is in valid state.
Definition: Storage.cpp:609
void addDependent(const WeakPtr< Storage > &other)
Registers a dependent storage.
Definition: Storage.cpp:339
void swap(Storage &other, const Flags< VisitorEnum > flags)
Swap quantities or given subset of quantities between two storages.
Definition: Storage.cpp:602
Size getParticleCnt() const
Returns the number of particles.
Definition: Storage.cpp:445
Size getQuantityCnt() const
Returns the number of stored quantities.
Definition: Storage.cpp:441
void zeroHighestDerivatives()
Sets all highest-level derivatives of quantities to zero.
Definition: Storage.cpp:556
Storage clone(const Flags< VisitorEnum > buffers) const
Clones specified buffers of the storage.
Definition: Storage.cpp:563
Basic time-measuring tool. Starts automatically when constructed.
Definition: Timer.h:27
int64_t elapsed(const TimerUnit unit) const
Returns elapsed time in timer units. Does not reset the timer.
Definition: Timer.cpp:55
Creating code components based on values from settings.
@ TIMESTEPPING_MAX_TIMESTEP
@ TIMESTEPPING_INITIAL_TIMESTEP
@ TIMESTEPPING_MIDPOINT_COUNT
Number of sub-steps in the modified midpoint method.
@ TIMESTEPPING_BS_ACCURACY
Required relative accuracy of the Bulirsch-Stoer integrator.
Provides a convenient way to construct objects from settings.
Definition: Factory.h:46
AutoPtr< ITimeStepCriterion > getTimeStepCriterion(const RunSettings &settings)
Definition: Factory.cpp:146
Overload of std::swap for Sph::Array.
Definition: Array.h:578
Float value
Value of the time step in code units (currently SI).
CriterionId id
Criterion applied to compute the time step;.