SPH
IRun.cpp
Go to the documentation of this file.
1 #include "run/IRun.h"
2 #include "io/LogWriter.h"
3 #include "io/Logger.h"
4 #include "io/Output.h"
5 #include "physics/Integrals.h"
6 #include "quantities/IMaterial.h"
7 #include "run/Trigger.h"
8 #include "sph/Diagnostics.h"
10 #include "system/Factory.h"
11 #include "system/Statistics.h"
12 #include "system/Timer.h"
13 #include "thread/Pool.h"
14 #include "timestepping/ISolver.h"
16 
18 
20 private:
21  Float wallclockDuraction;
22  Size timestepCnt;
23 
24 public:
25  EndingCondition(const Float wallclockDuraction, const Size timestepCnt)
26  : wallclockDuraction(wallclockDuraction)
27  , timestepCnt(timestepCnt) {}
28 
29  bool operator()(const Timer& timer, const Size timestep) {
30  if (wallclockDuraction > 0._f && timer.elapsed(TimerUnit::MILLISECOND) > wallclockDuraction) {
31  return true;
32  }
33  if (timestepCnt > 0 && timestep >= timestepCnt) {
34  return true;
35  }
36  return false;
37  }
38 };
39 
41 #ifndef SPH_DEBUG
42  SPH_ASSERT(false, "Invalid configuration, asserts should be only enabled in debug builds");
43 #endif
44 
45  // setup the default scheduler, this can be overriden in \ref setUp if needed
47 }
48 
49 IRun::~IRun() = default;
50 
52 private:
54 
55  RawPtr<IRunCallbacks> callbacks;
56  SharedPtr<ILogger> logger;
57 
58 public:
60  RawPtr<IRunCallbacks> callbacks,
61  SharedPtr<ILogger> logger,
62  const Float period)
63  : PeriodicTrigger(period, 0._f)
64  , diagnostics(diagnostics)
65  , callbacks(callbacks)
66  , logger(logger) {}
67 
68  virtual AutoPtr<ITrigger> action(Storage& storage, Statistics& stats) {
69  logger->write("Running simulation diagnostics");
70  bool passed = true;
71  for (auto& diag : diagnostics) {
72  const DiagnosticsReport result = diag->check(storage, stats);
73  if (!result) {
74  logger->write(result.error().description);
75  passed = false;
76  }
77  }
78  if (passed) {
79  logger->write(" - no problems detected");
80  }
81  return nullptr;
82  }
83 };
84 
85 
87 public:
88  virtual void onSetUp(const Storage&, Statistics&) override {}
89 
90  virtual void onTimeStep(const Storage&, Statistics&) override {}
91 
92  virtual bool shouldAbortRun() const override {
93  return false;
94  }
95 };
96 
97 class IOutputTime : public Polymorphic {
98 public:
100 };
101 
103 private:
104  Float interval;
105  Float time;
106 
107 public:
108  LinearOutputTime(const RunSettings& settings) {
109  time = settings.get<Float>(RunSettingsId::RUN_START_TIME);
110  interval = settings.get<Float>(RunSettingsId::RUN_OUTPUT_INTERVAL);
111  }
112 
113  virtual Optional<Float> getNextTime() override {
114  Float result = time;
115  time += interval;
116  return result;
117  }
118 };
119 
121 private:
122  Float interval;
123  Float time;
124 
125 public:
127  time = settings.get<Float>(RunSettingsId::RUN_START_TIME);
128  interval = settings.get<Float>(RunSettingsId::RUN_OUTPUT_INTERVAL);
129  }
130 
131  virtual Optional<Float> getNextTime() override {
132  Float result = time;
133  if (time == 0) {
134  time += interval;
135  } else {
136  time *= 2;
137  }
138  return result;
139  }
140 };
141 
143 private:
144  Array<Float> times;
145 
146 public:
147  CustomOutputTime(const RunSettings& settings) {
148  const std::string list = settings.get<std::string>(RunSettingsId::RUN_OUTPUT_CUSTOM_TIMES);
149  Array<std::string> items = split(list, ',');
150  for (const std::string& item : items) {
151  try {
152  times.push(std::stof(item));
153  } catch (const std::invalid_argument&) {
154  throw InvalidSetup("Cannot convert '" + item + "' to a number");
155  }
156  }
157  if (!std::is_sorted(times.begin(), times.end())) {
158  throw InvalidSetup("Output times must be in ascending order");
159  }
160  }
161 
162  virtual Optional<Float> getNextTime() override {
163  if (!times.empty()) {
164  Float result = times.front();
165  times.remove(0);
166  return result;
167  } else {
168  return NOTHING;
169  }
170  }
171 };
172 
175  switch (spacing) {
177  return makeAuto<LinearOutputTime>(settings);
179  return makeAuto<LogarithmicOutputTime>(settings);
181  return makeAuto<CustomOutputTime>(settings);
182  default:
184  }
185 }
186 
188  NullRunCallbacks callbacks;
189  return this->run(input, callbacks);
190 }
191 
193  // setup verbose logging (before setUp to log IC's as well)
195  const Path file(settings.get<std::string>(RunSettingsId::RUN_VERBOSE_NAME));
196  const Path outputPath(settings.get<std::string>(RunSettingsId::RUN_OUTPUT_PATH));
197  setVerboseLogger(makeAuto<FileLogger>(outputPath / file, FileLogger::Options::ADD_TIMESTAMP));
198  } else {
199  setVerboseLogger(nullptr);
200  }
201 
202  // move the data to shared storage, needed for Timestepping
203  SharedPtr<Storage> storage = makeShared<Storage>(std::move(input));
204 
205  // make initial conditions
206  this->setUp(storage);
207 
208  // set uninitilized variables
209  setNullToDefaults(storage);
210 
211  // fetch parameters of run from settings
212  const Interval timeRange(
215  Optional<Float> nextOutput = outputTime->getNextTime();
216 
217  logger->write(
218  "Running ", settings.get<std::string>(RunSettingsId::RUN_NAME), " for ", timeRange.size(), " s");
219  Timer runTimer;
223 
224  Statistics stats;
225  stats.set(StatisticsId::RUN_TIME, timeRange.lower());
226  stats.set(StatisticsId::TIMESTEP_VALUE, initialDt);
227 
228  callbacks.onSetUp(*storage, stats);
229  Outcome result = SUCCESS;
230 
231  // run main loop
232  Size i = 0;
233  for (Float t = timeRange.lower(); t < timeRange.upper() && !condition(runTimer, i);
234  t += timeStepping->getTimeStep()) {
235  // save current statistics
236  stats.set(StatisticsId::RUN_TIME, t);
238  const Float progress = t / timeRange.upper();
239  SPH_ASSERT(progress >= 0._f && progress <= 1._f);
240  stats.set(StatisticsId::RELATIVE_PROGRESS, progress);
241  stats.set(StatisticsId::INDEX, (int)i);
242 
243  // dump output
244  if (output && nextOutput && t >= nextOutput.value()) {
245  Expected<Path> writtenFile = output->dump(*storage, stats);
246  if (!writtenFile) {
247  logger->write(writtenFile.error());
248  }
249  nextOutput = outputTime->getNextTime();
250  }
251 
252  // make time step
253  timeStepping->step(*scheduler, *solver, stats);
254 
255  // log stats
256  logWriter->write(*storage, stats);
257 
258  // triggers
259  for (auto iter = triggers.begin(); iter != triggers.end();) {
260  ITrigger& trig = **iter;
261  if (trig.condition(*storage, stats)) {
262  AutoPtr<ITrigger> newTrigger = trig.action(*storage, stats);
263  if (newTrigger) {
264  triggers.pushBack(std::move(newTrigger));
265  }
266  if (trig.type() == TriggerEnum::ONE_TIME) {
267  iter = triggers.erase(iter);
268  continue;
269  }
270  }
271  ++iter;
272  }
273 
274  // callbacks
275  callbacks.onTimeStep(*storage, stats);
276  if (callbacks.shouldAbortRun()) {
277  result = makeFailed("Aborted by user");
278  break;
279  }
280  i++;
281  }
282  logger->write("Run ended after ", runTimer.elapsed(TimerUnit::SECOND), "s.");
283  if (!result) {
284  logger->write(result.error());
285  }
286  // clear any user data set during the simulation
287  storage->setUserData(nullptr);
288 
289  this->tearDownInternal(*storage, stats);
290 
291  // move data back to parameter
292  input = std::move(*storage);
293  return stats;
294 }
295 
296 
298  SPH_ASSERT(storage != nullptr);
299  if (!scheduler) {
300  // default to global thread pool
302  }
303 
304  if (!solver) {
306  for (Size i = 0; i < storage->getMaterialCnt(); ++i) {
307  solver->create(*storage, storage->getMaterial(i));
308  }
309  }
310  if (!logger) {
312  }
313  if (!logWriter) {
315  }
316  if (!timeStepping) {
318  }
319  if (!output) {
321  }
322 }
323 
324 void IRun::tearDownInternal(const Storage& storage, const Statistics& stats) {
325  this->tearDown(storage, stats);
326 
327  triggers.clear();
328  output.reset();
329  logger.reset();
330  logWriter.reset();
332  solver.reset();
333  // keep storage so that we can access particle data after run ends
334 }
335 
336 class SimpleRun : public IRun {
337 public:
339  this->settings = settings;
340  }
341 
342 protected:
343  virtual void setUp(SharedPtr<Storage> UNUSED(storage)) override {}
344 
345  virtual void tearDown(const Storage& UNUSED(storage), const Statistics& UNUSED(stats)) override {}
346 };
347 
348 Outcome doRun(Storage& storage, const RunSettings& settings) {
349  try {
350  SimpleRun run(settings);
351  NullRunCallbacks callbacks;
352  run.run(storage, callbacks);
353  return SUCCESS;
354  } catch (const InvalidSetup& e) {
355  return makeFailed(e.what());
356  }
357 }
358 
#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
Boundary conditions.
Looking for problems in SPH simulation and reporting potential errors.
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.
Outcome doRun(Storage &storage, const RunSettings &settings)
Runs a simulation using provided storage as initial conditions.
Definition: IRun.cpp:348
AutoPtr< IOutputTime > getOutputTimes(const RunSettings &settings)
Definition: IRun.cpp:173
Basic interface defining a single run.
Base interface for all solvers.
Integrals of motion and other integral quantities.
void setVerboseLogger(AutoPtr< ILogger > &&logger)
Creates a global verbose logger.
Definition: Logger.cpp:121
Logging routines of the run.
#define UNUSED(x)
Definition: Object.h:37
#define NAMESPACE_SPH_END
Definition: Object.h:12
const NothingType NOTHING
Definition: Optional.h:16
const SuccessTag SUCCESS
Global constant for successful outcome.
Definition: Outcome.h:141
INLINE Outcome makeFailed(TArgs &&... args)
Constructs failed object with error message.
Definition: Outcome.h:157
Saving and loading particle data.
Simple thread pool with fixed number of threads.
Statistics gathered and periodically displayed during the run.
@ WALLCLOCK_TIME
Current wallclock duration of the simulation.
@ 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.
@ INDEX
Current number of time step, indexed from 0.
Array< std::string > split(const std::string &s, const char delimiter)
Splits a string into an array of string using given delimiter.
Algorithms for temporal evolution of the physical model.
Measuring time intervals and executing periodic events.
Triggers of auxiliary actions during the run.
@ ONE_TIME
Execute the trigger only once.
Object providing safe access to continuous memory of data.
Definition: ArrayView.h:17
INLINE Iterator< StorageType > end() noexcept
Definition: Array.h:462
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
INLINE T & front() noexcept
Definition: Array.h:166
INLINE bool empty() const noexcept
Definition: Array.h:201
INLINE Iterator< StorageType > begin() noexcept
Definition: Array.h:450
Wrapper of pointer that deletes the resource from destructor.
Definition: AutoPtr.h:15
INLINE void reset()
Definition: AutoPtr.h:87
Expected-like class that does not contain any value.
Definition: Outcome.h:44
INLINE const TError & error() const
Returns the error message.
Definition: Outcome.h:88
virtual Optional< Float > getNextTime() override
Definition: IRun.cpp:162
CustomOutputTime(const RunSettings &settings)
Definition: IRun.cpp:147
DiagnosticsTrigger(ArrayView< const AutoPtr< IDiagnostic >> diagnostics, RawPtr< IRunCallbacks > callbacks, SharedPtr< ILogger > logger, const Float period)
Definition: IRun.cpp:59
virtual AutoPtr< ITrigger > action(Storage &storage, Statistics &stats)
Action executed when the condition is fulfilled.
Definition: IRun.cpp:68
virtual const char * what() const noexcept
Definition: Exceptions.h:18
Wrapper of type that either contains a value of given type, or an error message.
Definition: Expected.h:25
const Error & error() const
Returns the error message.
Definition: Expected.h:94
@ ADD_TIMESTAMP
Adds a time of writing before each message.
virtual void write(const Storage &storage, const Statistics &stats)=0
Writes to the log using provided storage and statistics.
void write(TArgs &&... args)
Creates and logs a message by concatenating arguments.
Definition: Logger.h:37
virtual Optional< Float > getNextTime()=0
virtual Expected< Path > dump(const Storage &storage, const Statistics &stats)=0
Saves data from particle storage into the file.
Callbacks executed by the simulation to provide feedback to the user.
Definition: IRun.h:27
virtual bool shouldAbortRun() const =0
Returns whether current run should be aborted or not.
virtual void onSetUp(const Storage &storage, Statistics &stats)=0
Called right before the run starts, i.e. after initial conditions are set up.
virtual void onTimeStep(const Storage &storage, Statistics &stats)=0
Called every timestep.
Defines the interface for a run.
Definition: IRun.h:61
IRun()
Definition: IRun.cpp:40
SharedPtr< IScheduler > scheduler
Scheduler used for parallelization.
Definition: IRun.h:75
AutoPtr< ILogWriter > logWriter
Writes statistics into logger every timestep.
Definition: IRun.h:72
AutoPtr< ITimeStepping > timeStepping
Timestepping.
Definition: IRun.h:78
SharedPtr< ILogger > logger
Logging.
Definition: IRun.h:69
AutoPtr< IOutput > output
Data output.
Definition: IRun.h:66
void tearDownInternal(const Storage &storage, const Statistics &stats)
Definition: IRun.cpp:324
Statistics run(Storage &storage)
Runs the simulation.
Definition: IRun.cpp:187
virtual void setUp(SharedPtr< Storage > storage)=0
Prepares the run, creates logger, output, ...
List< AutoPtr< ITrigger > > triggers
Triggers.
Definition: IRun.h:84
AutoPtr< ISolver > solver
Solver.
Definition: IRun.h:81
void setNullToDefaults(SharedPtr< Storage > storage)
Definition: IRun.cpp:297
virtual void tearDown(const Storage &storage, const Statistics &stats)=0
Called after the run.
RunSettings settings
Definition: IRun.h:63
virtual void create(Storage &storage, IMaterial &material) const =0
Initializes all quantities needed by the solver in the storage.
INLINE Float getTimeStep() const
Definition: TimeStepping.h:76
void step(IScheduler &scheduler, ISolver &solver, Statistics &stats)
Interface for triggering generic actions during the run.
Definition: Trigger.h:19
virtual TriggerEnum type() const =0
Returns the type of the trigger.
virtual bool condition(const Storage &storage, const Statistics &stats)=0
Returns true if the trigger should be executed.
virtual AutoPtr< ITrigger > action(Storage &storage, Statistics &stats)=0
Action executed when the condition is fulfilled.
Object representing a 1D interval of real numbers.
Definition: Interval.h:17
INLINE Float lower() const
Returns lower bound of the interval.
Definition: Interval.h:74
INLINE Float upper() const
Returns upper bound of the interval.
Definition: Interval.h:79
INLINE Float size() const
Returns the size of the interval.
Definition: Interval.h:89
Thrown when components of the run are mutually incompatible.
Definition: Exceptions.h:24
LinearOutputTime(const RunSettings &settings)
Definition: IRun.cpp:108
virtual Optional< Float > getNextTime() override
Definition: IRun.cpp:113
ListIterator< T > end()
Returns a bidirectional iterator pointing to the one-past-last element of the list.
Definition: List.h:307
void clear()
Removes all elements from the list.
Definition: List.h:250
void pushBack(U &&value)
Adds a new element to the back of the list.
Definition: List.h:189
ListIterator< T > erase(const ListIterator< T > iter)
Removes an element given by the iterator.
Definition: List.h:229
ListIterator< T > begin()
Returns a bidirectional iterator pointing to the first element of the list.
Definition: List.h:295
LogarithmicOutputTime(const RunSettings &settings)
Definition: IRun.cpp:126
virtual Optional< Float > getNextTime() override
Definition: IRun.cpp:131
virtual void onSetUp(const Storage &, Statistics &) override
Called right before the run starts, i.e. after initial conditions are set up.
Definition: IRun.cpp:88
virtual bool shouldAbortRun() const override
Returns whether current run should be aborted or not.
Definition: IRun.cpp:92
virtual void onTimeStep(const Storage &, Statistics &) override
Called every timestep.
Definition: IRun.cpp:90
INLINE Type & value()
Returns the reference to the stored value.
Definition: Optional.h:172
Object representing a path on a filesystem.
Definition: Path.h:17
Trigger executing given action every period.
Definition: Trigger.h:37
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
INLINE void reset()
Definition: SharedPtr.h:227
SimpleRun(const RunSettings &settings)
Definition: IRun.cpp:338
virtual void tearDown(const Storage &UNUSED(storage), const Statistics &UNUSED(stats)) override
Definition: IRun.cpp:345
virtual void setUp(SharedPtr< Storage > UNUSED(storage)) override
Definition: IRun.cpp:343
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
Size getMaterialCnt() const
Return the number of materials in the storage.
Definition: Storage.cpp:437
void setUserData(SharedPtr< IStorageUserData > newData)
Stores new user data into the storage.
Definition: Storage.cpp:824
MaterialView getMaterial(const Size matIdx) const
Returns an object containing a reference to given material.
Definition: Storage.cpp:366
static SharedPtr< ThreadPool > getGlobalInstance()
Returns the global instance of the thread pool.
Definition: Pool.cpp:211
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.
OutputSpacing
Definition: Settings.h:918
@ CUSTOM
User-defined list of output times.
@ LINEAR
Constant time between consecutive output times.
@ LOGARITHMIC
Constant ratio between consecutive output times.
@ RUN_OUTPUT_INTERVAL
Time interval of dumping data to disk.
@ RUN_VERBOSE_NAME
Path of a file where the verbose log is printed.
@ RUN_OUTPUT_SPACING
Type of output spacing in time, see enum OutputSpacing.
@ RUN_OUTPUT_PATH
Path where all output files (dumps, logs, ...) will be written.
@ TIMESTEPPING_INITIAL_TIMESTEP
@ RUN_OUTPUT_CUSTOM_TIMES
List of comma-separated output times, used when RUN_OUTPUT_SPACING is set to CUSTOM.
@ RUN_NAME
User-specified name of the run, used in some output files.
@ RUN_VERBOSE_ENABLE
Enables verbose log of a simulation.
AutoPtr< IOutput > getOutput(const RunSettings &settings)
Definition: Factory.cpp:563
AutoPtr< ISolver > getSolver(IScheduler &scheduler, const RunSettings &settings)
Definition: Factory.cpp:278
AutoPtr< ITimeStepping > getTimeStepping(const RunSettings &settings, const SharedPtr< Storage > &storage)
Definition: Factory.cpp:125
AutoPtr< ILogWriter > getLogWriter(SharedPtr< ILogger > logger, const RunSettings &settings)
Definition: Factory.cpp:547
AutoPtr< ILogger > getLogger(const RunSettings &settings)
Definition: Factory.cpp:529
SharedPtr< IScheduler > getScheduler(const RunSettings &settings=RunSettings::getDefaults())
Definition: Factory.cpp:178
EndingCondition(const Float wallclockDuraction, const Size timestepCnt)
Definition: IRun.cpp:25
bool operator()(const Timer &timer, const Size timestep)
Definition: IRun.cpp:29
Base class for all polymorphic objects.
Definition: Object.h:88