SPH
Controller.cpp
Go to the documentation of this file.
1 #include "gui/Controller.h"
2 #include "gui/Factory.h"
3 #include "gui/MainLoop.h"
4 #include "gui/Project.h"
5 #include "gui/Utils.h"
6 #include "gui/objects/Camera.h"
8 #include "gui/objects/Movie.h"
11 #include "gui/windows/RunPage.h"
12 #include "run/Node.h"
13 #include "run/jobs/IoJobs.h"
14 #include "system/Profiler.h"
15 #include "system/Statistics.h"
16 #include "system/Timer.h"
17 #include "thread/CheckFunction.h"
18 #include "thread/Pool.h"
19 #include <wx/app.h>
20 #include <wx/checkbox.h>
21 #include <wx/dcmemory.h>
22 #include <wx/msgdlg.h>
23 
25 
26 Controller::Controller(wxWindow* parent)
27  : project(Project::getInstance()) {
28 
29  // create objects for drawing particles
30  vis.initialize(project);
31 
32  // create associated page
33  GuiSettings& gui = project.getGuiSettings();
34  page = alignedNew<RunPage>(parent, this, gui);
35 
36  this->startRenderThread();
37 }
38 
40  this->quit(true);
41 }
42 
44  return page;
45 }
46 
47 Controller::Vis::Vis() {
48  bitmap = makeAuto<wxBitmap>();
49  needsRefresh = false;
50  refreshPending = false;
51  redrawOnNextTimeStep = false;
52 }
53 
54 void Controller::Vis::initialize(const Project& project) {
55  const GuiSettings& gui = project.getGuiSettings();
56 
57  renderer = Factory::getRenderer(gui);
59  colorizer = Factory::getColorizer(project, id);
60  timer = makeAuto<Timer>(gui.get<int>(GuiSettingsId::VIEW_MAX_FRAMERATE), TimerFlags::START_EXPIRED);
61  const Pixel size(gui.get<int>(GuiSettingsId::VIEW_WIDTH), gui.get<int>(GuiSettingsId::VIEW_HEIGHT));
62  camera = Factory::getCamera(gui, size);
63 }
64 
65 bool Controller::Vis::isInitialized() {
66  return renderer && stats && colorizer && camera;
67 }
68 
69 void Controller::Vis::refresh() {
70  needsRefresh = true;
71  renderThreadVar.notify_one();
72 }
73 
74 void Controller::start(SharedPtr<INode> run, const RunSettings& globals) {
76  // sanity check that we don't override ALL the settings; increase if necessary
77  SPH_ASSERT(globals.size() < 15);
78 
79  // stop the current one
80  this->stop(true);
81 
82  // update the status
83  status = RunStatus::RUNNING;
84  sph.shouldContinue = true;
85 
86  // create and start the run
87  sph.globals = globals;
88  sph.run = std::move(run);
89  this->startRunThread();
90 }
91 
92 void Controller::open(const Path& path, const bool sequence) {
94  SPH_ASSERT(!path.empty());
95  sph.path = path;
96  page->showTimeLine(true);
97 
98  if (sequence) {
99  this->start(makeNode<FileSequenceJob>("loader", path), EMPTY_SETTINGS);
100  } else {
101  this->start(makeNode<LoadFileJob>(path), EMPTY_SETTINGS);
102  }
103 }
104 
107  switch (status) {
108  case RunStatus::RUNNING:
109  case RunStatus::QUITTING:
110  // already running or shutting down, do nothing
111  return;
112  case RunStatus::PAUSED:
113  // unpause
114  continueVar.notify_one();
115  break;
116  case RunStatus::STOPPED:
117  // wait till previous run finishes
118  if (sph.thread.joinable()) {
119  sph.thread.join();
120  }
121  // start new simulation
122  this->startRunThread();
123  }
124  status = RunStatus::RUNNING;
125 }
126 
129  status = RunStatus::PAUSED;
130 }
131 
132 void Controller::stop(const bool waitForFinish) {
134 
135  sph.shouldContinue = false;
136 
137  // notify continue CV to unpause run (if it's paused), otherwise we would get deadlock
138  continueVar.notify_one();
139 
140  if (waitForFinish && sph.thread.joinable()) {
141  sph.thread.join();
142  SPH_ASSERT(status == RunStatus::STOPPED);
143  }
144 }
145 
147  return status;
148 }
149 
150 void Controller::saveState(const Path& path) {
152  auto dump = [path](const Storage& storage, const Statistics& stats) {
153  const Optional<IoEnum> type = getIoEnum(path.extension().native());
154  if (!type) {
155  wxMessageBox("Unknown type of file '" + path.native() + "'", "Fail", wxOK | wxCENTRE);
156  return;
157  }
158  RunSettings settings;
159  settings.set(RunSettingsId::RUN_OUTPUT_TYPE, type.value());
161  settings.set(RunSettingsId::RUN_OUTPUT_PATH, std::string(""));
166  settings.set(RunSettingsId::RUN_OUTPUT_QUANTITIES, flags);
167 
168  AutoPtr<IOutput> output = Factory::getOutput(settings);
169  Expected<Path> result = output->dump(storage, stats);
170  if (!result) {
171  wxMessageBox("Cannot save the file.\n\n" + result.error(), "Fail", wxOK | wxCENTRE);
172  }
173  };
174 
175  if (status == RunStatus::RUNNING) {
176  // cannot directly access the storage during the run, execute it on the time step
177  sph.onTimeStepCallbacks->push(dump);
178  } else if (sph.storage) {
179  // if not running, we can safely save the storage from main thread
180  BusyCursor wait(page->GetGrandParent());
181  dump(*sph.storage, *vis.stats);
182  }
183 }
184 
185 void Controller::quit(const bool waitForFinish) {
187 
188  // set status so that other threads know to quit
189  status = RunStatus::QUITTING;
190  sph.shouldContinue = false;
191 
192  // unpause run
193  continueVar.notify_one();
194 
195  // wait for the run to finish
196  if (waitForFinish) {
197  if (sph.thread.joinable()) {
198  sph.thread.join();
199  }
200 
201  vis.renderer->cancelRender();
202  {
203  std::unique_lock<std::mutex> renderLock(vis.renderThreadMutex);
204  vis.renderThreadVar.notify_one();
205  }
206 
207  if (vis.renderThread.joinable()) {
208  vis.renderThread.join();
209  }
210  }
211 }
212 
213 void Controller::setAutoZoom(const bool enable) {
215  GuiSettings& gui = project.getGuiSettings();
216  if (gui.get<bool>(GuiSettingsId::CAMERA_AUTOSETUP) == enable) {
217  return;
218  }
220  wxWindow* window = wxWindow::FindWindowByLabel("Auto-zoom", page.get());
221  SPH_ASSERT(window != nullptr);
222  wxCheckBox* checkbox = dynamic_cast<wxCheckBox*>(window);
223  checkbox->SetValue(enable);
224 }
225 
226 void Controller::onSetUp(const Storage& storage, Statistics& stats) {
227  sph.storage = &storage;
228  this->update(storage, stats);
229 }
230 
231 void Controller::onStart(const IJob& job) {
232  const std::string className = job.className();
233  const std::string instanceName = job.instanceName();
234  this->safePageCall([className, instanceName](RunPage* page) { page->newPhase(className, instanceName); });
235 }
236 
237 
238 void Controller::onEnd(const Storage& storage, const Statistics& stats) {
239  if (!storage.empty()) {
240  sph.storage = &storage;
241 
242  if (sph.shouldContinue) {
243  // If not continuing, we might be already waiting for next run, i.e. we cannot block main thread
244  // and wait for signal. If the update is necessary, we have to introduce additional flag
245  // (sph.runPending)
246  this->update(storage, stats);
247  }
248  }
249 
250  Statistics endStats = stats;
251  endStats.set(StatisticsId::RELATIVE_PROGRESS, 1._f);
252 
253  this->safePageCall([endStats](RunPage* page) {
254  page->setProgress(endStats);
255  page->onRunEnd();
256  });
257 }
258 
259 void Controller::onTimeStep(const Storage& storage, Statistics& stats) {
260  // SPH_ASSERT(std::this_thread::get_id() == sph.thread.get_id()); - can be actually called from worker
261  // thread, but that should not matter, as long as there is not a concurrent access from different thread
262 
263  if (status == RunStatus::QUITTING) {
264  return;
265  }
266 
267  Timer timer;
268 
269  // update run progress
270  this->safePageCall([stats](RunPage* page) {
272  page->setProgress(stats);
273  });
274 
275  if (storage.empty()) {
276  return;
277  }
278 
279  // update the data in all window controls (can be done from any thread)
280  page->onTimeStep(storage, stats);
281 
282  // executed all waiting callbacks (before redrawing as it is used to change renderers)
283  if (!sph.onTimeStepCallbacks->empty()) {
284  MEASURE_SCOPE("onTimeStep - plots");
285  auto onTimeStepProxy = sph.onTimeStepCallbacks.lock();
286  for (auto& func : onTimeStepProxy.get()) {
287  func(storage, stats);
288  }
289  onTimeStepProxy->clear();
290  }
291 
292  // update the data for rendering
293  const GuiSettings& gui = project.getGuiSettings();
294  const bool doRedraw = vis.redrawOnNextTimeStep || gui.get<bool>(GuiSettingsId::REFRESH_ON_TIMESTEP);
295  if (doRedraw && vis.timer->isExpired()) {
296  this->redraw(storage, stats);
297  vis.timer->restart();
298  vis.redrawOnNextTimeStep = false;
299 
300  executeOnMainThread([this] {
301  // update particle probe - has to be done after we redraw the image as it initializes
302  // the colorizer
303  this->setSelectedParticle(vis.selectedParticle);
304  });
305  }
306 
307  // pause if we are supposed to
308  if (status == RunStatus::PAUSED) {
309  std::unique_lock<std::mutex> lock(continueMutex);
310  continueVar.wait(lock);
311  }
312 
314 }
315 
317  return project.getGuiSettings();
318 }
319 
320 void Controller::update(const Storage& storage, const Statistics& stats) {
322 
323  std::unique_lock<std::mutex> lock(updateMutex);
324  executeOnMainThread([this, &storage] { //
325  std::unique_lock<std::mutex> lock(updateMutex);
326  page->runStarted(storage, sph.path);
327 
328  // fill the combobox with available colorizer
329  Array<SharedPtr<IColorizer>> list = this->getColorizerList(storage);
330  if (!vis.colorizer->hasData(storage)) {
331  this->setColorizer(list.front());
332  }
333  page->setColorizerList(std::move(list));
334  updateVar.notify_one();
335  });
336  updateVar.wait(lock);
337 
338  // draw initial positions of particles
339  this->redraw(storage, stats);
340 
341  // set up animation object
342 }
343 
344 bool Controller::shouldAbortRun() const {
345  return !sph.shouldContinue;
346 }
347 
348 bool Controller::isRunning() const {
349  return status == RunStatus::RUNNING || status == RunStatus::PAUSED;
350 }
351 
353  static Array<ExtColorizerId> colorizerIds = {
364  //
368  //
375  //
386  //
390  //
400  //
402  };
403 
404  return colorizerIds.clone();
405 }
406 
408  const GuiSettings& gui = project.getGuiSettings();
410  Array<ExtColorizerId> colorizerIds = getColorizerIds();
411  Array<SharedPtr<IColorizer>> colorizers;
412  for (ExtColorizerId id : colorizerIds) {
413  SharedPtr<IColorizer> colorizer = Factory::getColorizer(project, id);
414  if (!colorizer->hasData(storage)) {
415  continue;
416  }
417  if (id == defaultId) {
418  colorizers.insert(0, colorizer);
419  } else {
420  colorizers.push(colorizer);
421  }
422  }
423  return colorizers;
424 }
425 
426 const wxBitmap& Controller::getRenderedBitmap() const {
428  vis.refreshPending = false;
429  return *vis.bitmap;
430 }
431 
433  SPH_ASSERT(vis.colorizer != nullptr);
434  return vis.colorizer;
435 }
436 
438  std::unique_lock<std::mutex> cameraLock(vis.cameraMutex);
439  return vis.camera->clone();
440 }
441 
444 
445  if (!vis.colorizer->isInitialized()) {
446  // we have to wait for redraw to get data from storage
447  return NOTHING;
448  }
449 
450  std::unique_lock<std::mutex> cameraLock(vis.cameraMutex);
451  AutoPtr<ICamera> camera = vis.camera->clone();
452  cameraLock.unlock();
453 
454  const GuiSettings& gui = project.getGuiSettings();
455  const float radius = float(gui.get<Float>(GuiSettingsId::PARTICLE_RADIUS));
456  const Optional<CameraRay> ray = camera->unproject(Coords(position));
457  if (!ray) {
458  return NOTHING;
459  }
460 
461  const float cutoff = camera->getCutoff().valueOr(0.f);
462  const Vector rayDir = getNormalized(ray->target - ray->origin);
463  const Vector camDir = camera->getFrame().row(2);
464 
465  struct {
466  float t = -std::numeric_limits<float>::lowest();
467  Size idx = -1;
468  bool wasHitOutside = true;
469  } first;
470 
471  for (Size i = 0; i < vis.positions.size(); ++i) {
472  Optional<ProjectedPoint> p = camera->project(vis.positions[i]);
473  if (!p) {
474  // particle not visible by the camera
475  continue;
476  }
477  if (cutoff != 0._f && abs(dot(camDir, vis.positions[i])) > cutoff) {
478  // particle cut off by projection
481  continue;
482  }
483 
484  const Vector r = vis.positions[i] - ray->origin;
485  const float t = float(dot(r, rayDir));
486  const Vector projected = r - t * rayDir;
488  const float radiusSqr = float(sqr(vis.positions[i][H] * radius));
489  const float distanceSqr = float(getSqrLength(projected));
490  if (distanceSqr < radiusSqr * sqr(1._f + toleranceEps)) {
491  const bool wasHitOutside = distanceSqr > radiusSqr;
492  // hit candidate, check if it's closer or current candidate was hit outside the actual radius
493  if (t < first.t || (first.wasHitOutside && !wasHitOutside)) {
494  // update the current candidate
495  first.idx = i;
496  first.t = t;
497  first.wasHitOutside = wasHitOutside;
498  }
499  }
500  }
501  if (int(first.idx) == -1) {
502  // not a single candidate found
503  return NOTHING;
504  } else {
505  return first.idx;
506  }
507 }
508 
511  vis.colorizer = newColorizer;
512  if (!this->tryRedraw()) {
513  this->redrawOnNextTimeStep();
514  }
515 
516  // update particle probe with the new colorizer
517  this->setSelectedParticle(vis.selectedParticle);
518 }
519 
521  // CHECK_FUNCTION(CheckFunction::MAIN_THREAD);
522 
523  auto func = [this, renderer = std::move(newRenderer)](
524  const Storage& storage, const Statistics& UNUSED(stats)) mutable {
525  SPH_ASSERT(sph.run);
526  std::unique_lock<std::mutex> renderLock(vis.renderThreadMutex);
527  vis.renderer = std::move(renderer);
528  vis.colorizer->initialize(storage, RefEnum::STRONG);
529  vis.renderer->initialize(storage, *vis.colorizer, *vis.camera);
530  vis.refresh();
531  };
532 
533  vis.renderer->cancelRender();
534  if (status != RunStatus::RUNNING) {
535  // if no simulation is running, it's safe to switch renderers and access storage directly
536  func(*sph.storage, *vis.stats);
537  } else {
538  // if running, we have to switch renderers on next timestep
539  sph.onTimeStepCallbacks->push(std::move(func));
540  }
541 }
542 
545  vis.selectedParticle = particleIdx;
546 
548  if (particleIdx && vis.colorizer->isInitialized()) {
549  const Rgba color = vis.colorizer->evalColor(particleIdx.value());
550  Optional<Particle> particle = vis.colorizer->getParticle(particleIdx.value());
551  if (particle) {
552  // add position to the particle data
553  particle->addValue(QuantityId::POSITION, vis.positions[particleIdx.value()]);
554  page->setSelectedParticle(particle.value(), color);
555  return;
556  }
557  }
558 
559  page->deselectParticle();
560 }
561 
564 
565  project.setPalette(vis.colorizer->name(), palette);
566  vis.colorizer->setPalette(palette);
567  this->tryRedraw();
568 }
569 
571  return vis.selectedParticle;
572 }
573 
576  return *sph.storage;
577 }
578 
579 void Controller::redraw(const Storage& storage, const Statistics& stats) {
581 
582  vis.renderer->cancelRender();
583  std::unique_lock<std::mutex> renderLock(vis.renderThreadMutex);
584 
585  vis.stats = makeAuto<Statistics>(stats);
586  vis.positions = copyable(storage.getValue<Vector>(QuantityId::POSITION));
587 
588  // initialize the currently selected colorizer; we create a local copy as vis.colorizer might be changed
589  // in setColorizer before renderer->initialize is called
590  SPH_ASSERT(vis.isInitialized());
591  SharedPtr<IColorizer> colorizer = vis.colorizer;
592  colorizer->initialize(storage, RefEnum::STRONG);
593 
594  // setup camera
595  SPH_ASSERT(vis.camera);
596  vis.cameraMutex.lock();
597  if (project.getGuiSettings().get<bool>(GuiSettingsId::CAMERA_AUTOSETUP)) {
598  vis.camera->autoSetup(storage);
600  }
601  AutoPtr<ICamera> camera = vis.camera->clone();
602  vis.cameraMutex.unlock();
603 
604  // update the renderer with new data
605  vis.renderer->initialize(storage, *colorizer, *camera);
606 
607  // notify the render thread that new data are available
608  vis.refresh();
609 }
610 
613  if (status != RunStatus::RUNNING && sph.storage && !sph.storage->empty()) {
614  vis.renderer->cancelRender();
615  std::unique_lock<std::mutex> renderLock(vis.renderThreadMutex);
616  vis.colorizer->initialize(*sph.storage, RefEnum::STRONG);
617 
618  vis.cameraMutex.lock();
619  // vis.camera->initialize(sph.storage);
620  AutoPtr<ICamera> camera = vis.camera->clone();
621  vis.cameraMutex.unlock();
622  vis.renderer->initialize(*sph.storage, *vis.colorizer, *camera);
623  vis.timer->restart();
624  vis.refresh();
625 
626  return true;
627  } else {
628  vis.renderer->cancelRender();
629  vis.refresh();
630  return false;
631  }
632 }
633 
635  vis.redrawOnNextTimeStep = true;
636 }
637 
639  // invalidate camera, render will be restarted on next timestep
640  vis.renderer->cancelRender();
641  std::unique_lock<std::mutex> lock(vis.cameraMutex);
642  vis.camera = std::move(camera);
643  vis.refresh();
644 
645  // save the current fov to settings
647  if (const Optional<float> wtp = vis.camera->getWorldToPixel()) {
648  const Pixel imageSize = vis.camera->getSize();
649  const Float fov = imageSize.y / wtp.value();
651  }
652 }
653 
654 void Controller::safePageCall(Function<void(RunPage*)> func) {
655  executeOnMainThread([func, this] {
656  wxWeakRef<RunPage> weakPage = page.get();
657  if (weakPage) {
658  func(weakPage);
659  }
660  });
661 }
662 
663 void Controller::startRunThread() {
664  sph.thread = std::thread([this] {
665  sph.shouldContinue = true;
666 
667  try {
668  // run the simulation
669  sph.run->run(sph.globals, *this);
670 
671  } catch (const std::exception& e) {
672  executeOnMainThread([desc = std::string(e.what())] { //
673  wxMessageBox(
674  std::string("Error encountered during the run: \n") + desc, "Fail", wxOK | wxCENTRE);
675  });
676  }
677 
678  // set status to finished (if not already quitting)
679  if (status != RunStatus::QUITTING) {
680  status = RunStatus::STOPPED;
681  }
682  });
683 }
684 
685 void Controller::startRenderThread() {
686 
687  class RenderOutput : public IRenderOutput {
688  private:
689  Vis& vis;
690  wxWeakRef<RunPage> page;
691 
692  public:
693  RenderOutput(Vis& vis, wxWeakRef<RunPage> page)
694  : vis(vis)
695  , page(page) {}
696 
697  virtual void update(Bitmap<Rgba>&& bitmap, Array<Label>&& labels, const bool isFinal) override {
698  this->update(bitmap, std::move(labels), isFinal);
699  }
700 
701  virtual void update(const Bitmap<Rgba>& bitmap,
702  Array<Label>&& labels,
703  const bool UNUSED(isFinal)) override {
704  SPH_ASSERT(!bitmap.empty());
705  if (vis.refreshPending) {
706  return;
707  }
708 
710  AutoPtr<wxBitmap> newBitmap = makeAuto<wxBitmap>();
711  toWxBitmap(bitmap, *newBitmap);
712 
713  // Capture page as weak ref as we need to check it first, this might not exit anymore!
714  auto callback = [&vis = vis,
715  page = page,
716  bitmap = std::move(newBitmap),
717  labels = std::move(labels)]() mutable {
718  if (!page) {
719  // page has already closed, nothing to render
720  return;
721  }
722  vis.refreshPending = true;
723  vis.bitmap = std::move(bitmap);
724 
725  if (!labels.empty()) {
726  wxMemoryDC dc(*vis.bitmap);
727  printLabels(dc, labels);
728  dc.SelectObject(wxNullBitmap);
729  }
730 
731  page->refresh();
732  };
733 
734  executeOnMainThread(std::move(callback));
735  }
736  };
737 
738  vis.renderThread = std::thread([this] {
739  RenderOutput output(vis, page.get());
740  while (status != RunStatus::QUITTING) {
741 
742  // wait till render data are available
743  std::unique_lock<std::mutex> renderLock(vis.renderThreadMutex);
744  vis.renderThreadVar.wait(renderLock, [this] { //
745  return vis.needsRefresh.load() || status == RunStatus::QUITTING;
746  });
747  vis.needsRefresh = false;
748 
749  if (!vis.isInitialized() || status == RunStatus::QUITTING) {
750  // no simulation running, go back to sleep
751  continue;
752  }
753 
754  const wxSize canvasSize = page->getCanvasSize();
755  RenderParams params;
756  params.particles.selected = vis.selectedParticle;
757 
758  // initialize all parameters from GUI settings
759  params.initialize(project.getGuiSettings());
760 
761  vis.cameraMutex.lock();
762  params.camera = vis.camera->clone();
763  vis.cameraMutex.unlock();
764 
765  const Pixel size = Pixel(canvasSize.x, canvasSize.y);
766  params.camera->resize(size);
767 
768  vis.renderer->render(params, *vis.stats, output);
769  }
770  });
771 }
772 
INLINE CopyableArray< T, TAllocator, TCounter > copyable(const Array< T, TAllocator, TCounter > &array)
Definition: Array.h:558
#define SPH_ASSERT(x,...)
Definition: Assert.h:94
NAMESPACE_SPH_BEGIN
Definition: BarnesHut.cpp:13
NAMESPACE_SPH_BEGIN void toWxBitmap(const Bitmap< Rgba > &bitmap, wxBitmap &wx)
Definition: Bitmap.cpp:12
Defines projection transforming 3D particles onto 2D screen.
Helper functions to check the internal consistency of the code.
@ NO_THROW
Function cannot throw exceptions.
@ MAIN_THREAD
Function can only be executed from main thread.
#define CHECK_FUNCTION(flags)
Definition: CheckFunction.h:40
Object converting quantity values of particles into colors.
ColorizerId
Special colorizers that do not directly correspond to quantities.
Definition: Colorizer.h:136
@ TOTAL_STRESS
Total stress (sigma = S - pI)
@ FLAG
Particles of different bodies are colored differently.
@ COROTATING_VELOCITY
Velocities with a respect to the rotating body.
@ RADIUS
Radii/smoothing lenghts of particles.
@ SUMMED_DENSITY
Density computed from particle masses by direct summation of neighbours.
@ DENSITY_PERTURBATION
Relative difference of density and initial density (rho/rho0 - 1)
@ COMPONENT_ID
Color assigned to each component (group of connected particles)
@ VELOCITY
Particle velocities.
@ YIELD_REDUCTION
Reduction of stress tensor due to yielding (1 - f_vonMises)
@ PARTICLE_ID
Each particle drawn with different color.
@ TOTAL_ENERGY
Sum of kinetic and internal energy for given particle.
@ DAMAGE_ACTIVATION
Ratio of the stress and the activation strain.
@ BOUNDARY
Shows boundary particles.
@ AGGREGATE_ID
Color assigned to each aggregate.
@ TEMPERATURE
Temperature, computed from internal energy.
@ ACCELERATION
Acceleration of particles.
@ BEAUTY
Attempts to show the real-world look.
@ MATERIAL_ID
Particles with different materials are colored differently.
@ UVW
Shows UV mapping, u-coordinate in red and v-coordinate in blur.
Array< ExtColorizerId > getColorizerIds()
Returns IDs of all colorizers available in the application.
Definition: Controller.cpp:352
RunStatus
Status of the code.
Definition: Controller.h:33
@ STOPPED
Run has been stopped by the user.
@ RUNNING
Simulation in progress.
@ QUITTING
quit has been called, waiting for threads to finish
@ PAUSED
Run is paused, can be continued or stopped.
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
NAMESPACE_SPH_BEGIN void executeOnMainThread(const Function< void()> &function)
Posts a callback to be executed on main thread.
Definition: MainLoop.cpp:8
Posting events to be executed on main thread.
constexpr INLINE T sqr(const T &f) noexcept
Return a squared value.
Definition: MathUtils.h:67
INLINE auto abs(const T &f)
Definition: MathUtils.h:276
Renderer visualizing the surface as triangle mesh.
Periodically saves rendered images to disk.
#define UNUSED(x)
Definition: Object.h:37
#define NAMESPACE_SPH_END
Definition: Object.h:12
const NothingType NOTHING
Definition: Optional.h:16
@ VELOCITY
Current velocities of particles, always a vector quantity.
@ DAMAGE
Damage, reducing the pressure and deviatoric stress.
@ POSITION
Positions of particles, always a vector quantity.
@ ENERGY
Specific internal energy, always a scalar quantity.
@ SMOOTHING_LENGTH
Smoothing lenghts of particles.
@ DENSITY
Density, always a scalar quantity.
@ MASS
Particle masses, always a scalar quantity.
Renderer drawing individual particles as dots.
Simple thread pool with fixed number of threads.
Tool to measure time spent in functions and profile the code.
#define MEASURE_SCOPE(name)
Definition: Profiler.h:70
@ BULK_DENSITY
Bulk density, may be lower than the material density.
@ AV_ALPHA
Coefficient alpha of the artificial viscosity. Coefficient beta is always 2*alpha.
@ VELOCITY_DIVERGENCE
Velocity divergence.
@ STRAIN_RATE_CORRECTION_TENSOR
Correction tensor used to improve conservation of total angular momentum.
@ DEVIATORIC_STRESS
Deviatoric stress tensor, always a traceless tensor.
@ PRESSURE
Pressure, affected by yielding and fragmentation model, always a scalar quantity.
@ AV_BALSARA
Balsara factor.
@ MOMENT_OF_INERTIA
Moment of inertia of particles, analogy of particle masses for rotation.
@ VELOCITY_GRADIENT
Velocity gradient.
@ DAMAGE
Damage.
@ POSITION
Positions (velocities, accelerations) of particles, always a vector quantity,.
@ ENERGY
Specific internal energy, always a scalar quantity.
@ VELOCITY_LAPLACIAN
@ VELOCITY_ROTATION
Velocity rotation.
@ DENSITY
Density, always a scalar quantity.
@ MASS
Paricles masses, always a scalar quantity.
@ NEIGHBOUR_CNT
Number of neighbouring particles (in radius h * kernel.radius)
@ SOUND_SPEED
Sound speed, always a scalar quantity.
@ AV_STRESS
Artificial stress by Monaghan .
@ VIBRATIONAL_VELOCITY
Vibrational particle velocity, used by the block model of acoustic fluidization.
@ VELOCITY_GRADIENT_OF_DIVERGENCE
Statistics gathered and periodically displayed during the run.
@ POSTPROCESS_EVAL_TIME
Wallclock spent on data dump, particle visualization, etc.
Measuring time intervals and executing periodic events.
@ START_EXPIRED
Creates expired timer, calling elapsed immediately after creating will return the timer interval.
void printLabels(wxDC &dc, ArrayView< const IRenderOutput::Label > labels)
Definition: Utils.cpp:186
Random utility functions for drawing stuff to DC.
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
INLINE Vector getNormalized(const Vector &v)
Definition: Vector.h:590
@ H
Definition: Vector.h:25
INLINE Vector row(const Size idx) const
Definition: AffineMatrix.h:44
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
void insert(const TCounter position, U &&value)
Inserts a new element to given position in the array.
Definition: Array.h:345
INLINE T & front() noexcept
Definition: Array.h:166
Array clone() const
Performs a deep copy of all elements of the array.
Definition: Array.h:147
bool empty() const
Definition: Bitmap.h:76
bool isRunning() const
Returns true if a simulation is running.
Definition: Controller.cpp:348
Controller(wxWindow *parent)
Initialize the controller.
Definition: Controller.cpp:26
void setRenderer(AutoPtr< IRenderer > &&newRenderer)
Sets a new renderer used to draw particles.
Definition: Controller.cpp:520
void setAutoZoom(const bool enable)
Enables or disables auto-zoom during the simulation.
Definition: Controller.cpp:213
RawPtr< RunPage > getPage() const
Definition: Controller.cpp:43
AutoPtr< ICamera > getCurrentCamera() const
Returns the camera currently used for the rendering.
Definition: Controller.cpp:437
SharedPtr< INode > run
Root node of the simulation.
Definition: Controller.h:55
void quit(const bool waitForFinish=false)
Closes down the model, clears all allocated resources. Must be called only once.
Definition: Controller.cpp:185
Array< SharedPtr< IColorizer > > getColorizerList(const Storage &storage) const
Definition: Controller.cpp:407
void saveState(const Path &path)
Saves the state of the current run to the disk.
Definition: Controller.cpp:150
const wxBitmap & getRenderedBitmap() const
Renders a bitmap of current view.
Definition: Controller.cpp:426
void restart()
Starts the simulation with current setup.
Definition: Controller.cpp:105
SharedPtr< IColorizer > getCurrentColorizer() const
Returns the colorizer currently used for rendering into the window.
Definition: Controller.cpp:432
RunStatus getStatus() const
Returns the current status of the run.
Definition: Controller.cpp:146
Path path
Path to the loaded file, if used.
Definition: Controller.h:62
void open(const Path &path, const bool sequence=false)
Opens a simulation snapshot from given file.
Definition: Controller.cpp:92
void stop(const bool waitForFinish=false)
Stops the current simulation.
Definition: Controller.cpp:132
void redrawOnNextTimeStep()
Redraws the image on the following timestep.
Definition: Controller.cpp:634
void setPaletteOverride(const Palette palette)
Modifies the color palette for current colorizer.
Definition: Controller.cpp:562
Optional< Size > getIntersectedParticle(const Pixel position, const float toleranceEps)
Returns the particle under given image position, or NOTHING if such particle exists.
Definition: Controller.cpp:442
void setSelectedParticle(const Optional< Size > &particleIdx)
Sets a selected particle or changes the current selection.
Definition: Controller.cpp:543
void pause()
Pause the current simulation.
Definition: Controller.cpp:127
void start(SharedPtr< INode > run, const RunSettings &globals)
Sets up and starts a new simulation.
Definition: Controller.cpp:74
void refresh(AutoPtr< ICamera > &&camera)
Re-renders the particles with given camera.
Definition: Controller.cpp:638
Optional< Size > getSelectedParticle() const
Definition: Controller.cpp:570
RunSettings globals
Definition: Controller.h:57
void update(const Storage &storage, const Statistics &stats)
Updates the colorizer list, reset the camera and the renderer, etc.
Definition: Controller.cpp:320
bool tryRedraw()
If possible, redraws the particles with data from storage.
Definition: Controller.cpp:611
RawPtr< const Storage > storage
Definition: Controller.h:59
GuiSettings & getParams()
Returns the settings object.
Definition: Controller.cpp:316
void setColorizer(const SharedPtr< IColorizer > &newColorizer)
Sets a new colorizer to be displayed.
Definition: Controller.cpp:509
const Storage & getStorage() const
Definition: Controller.cpp:574
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
Helper type allowing to "derive" from enum class.
Definition: ExtendedEnum.h:24
INLINE TValue get(const GuiSettingsId id) const
Definition: Settings.h:245
INLINE GuiSettings & set(const GuiSettingsId id, const TValue &value)
Definition: Settings.h:250
virtual Optional< float > getCutoff() const =0
Returns the clipping distance from plane passing through origin, perpendicular to camera direction.
virtual AffineMatrix getFrame() const =0
Returns the transformation matrix converting camera space to world space.
virtual Optional< ProjectedPoint > project(const Vector &r) const =0
Returns projected position of particle on the image.
virtual AutoPtr< ICamera > clone() const =0
virtual void resize(const Pixel newSize)=0
Changes the image size.
virtual Optional< CameraRay > unproject(const Coords &coords) const =0
Returns a ray in particle coordinates corresponding to given coordinates in the image plane.
virtual void initialize(const Storage &storage, const RefEnum ref)=0
Initialize the colorizer before by getting necessary quantities from storage.
virtual bool hasData(const Storage &storage) const =0
Checks if the storage constains all data necessary to initialize the colorizer.
Base class for all object performing an operation in a simulation hierarchy.
Definition: Job.h:96
virtual std::string instanceName() const
Unique name representing this job.
Definition: Job.h:110
virtual std::string className() const =0
Name representing the type of the job (e.e. "SPH").
virtual Expected< Path > dump(const Storage &storage, const Statistics &stats)=0
Saves data from particle storage into the file.
Wrapper of type value of which may or may not be present.
Definition: Optional.h:23
INLINE Type & value()
Returns the reference to the stored value.
Definition: Optional.h:172
INLINE Type valueOr(const TOther &other) const
Returns the stored value if the object has been initialized, otherwise returns provided parameter.
Definition: Optional.h:188
Represents a color palette, used for mapping arbitrary number to a color.
Definition: Palette.h:25
Object representing a path on a filesystem.
Definition: Path.h:17
std::string native() const
Returns the native version of the path.
Definition: Path.cpp:71
bool empty() const
Checks if the path is empty.
Definition: Path.cpp:10
Path extension() const
Returns the extension of the filename.
Definition: Path.cpp:59
GuiSettings & getGuiSettings()
Definition: Project.h:51
void setPalette(const std::string &name, const Palette &palette)
Definition: Project.h:37
INLINE T * get() const
Definition: RawPtr.h:67
Definition: Color.h:8
Main frame of the application.
Definition: RunPage.h:44
void deselectParticle()
Definition: RunPage.cpp:936
void setColorizerList(Array< SharedPtr< IColorizer >> &&colorizers)
Definition: RunPage.cpp:919
void setProgress(const Statistics &stats)
Definition: RunPage.cpp:826
void newPhase(const std::string &className, const std::string &instanceName)
Definition: RunPage.cpp:836
void runStarted(const Storage &storage, const Path &path)
Definition: RunPage.cpp:857
void showTimeLine(const bool show)
Definition: RunPage.cpp:844
void onTimeStep(const Storage &storage, const Statistics &stats)
Definition: RunPage.cpp:876
void setSelectedParticle(const Particle &particle, const Rgba color)
Definition: RunPage.cpp:931
void onRunEnd()
Definition: RunPage.cpp:912
Settings & set(const TEnum idx, TValue &&value, std::enable_if_t<!std::is_enum< std::decay_t< TValue >>::value, int >=0)
Saves a value into the settings.
Definition: Settings.h:226
Size size() const
Returns the number of entries in the settings.
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
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
Optional< IoEnum > getIoEnum(const std::string &ext)
Returns the file type from file extension.
Definition: Settings.cpp:367
const EmptySettingsTag EMPTY_SETTINGS
Definition: Settings.h:32
@ RUN_OUTPUT_QUANTITIES
List of quantities to write to text output. Binary output always stores all quantitites.
@ RUN_OUTPUT_PATH
Path where all output files (dumps, logs, ...) will be written.
@ RUN_OUTPUT_TYPE
Selected format of the output file, see IoEnum.
@ RUN_OUTPUT_NAME
File name of the output file (including extension), where d is a placeholder for output number.
@ PARTICLE_RADIUS
Displayed radius of particle in units of smoothing length.
@ CAMERA_ORTHO_FOV
View field of view (zoom). Special value 0 means the field of view is computed from the bounding box.
AutoPtr< IOutput > getOutput(const RunSettings &settings)
Definition: Factory.cpp:563
AutoPtr< IColorizer > getColorizer(const Project &project, const ExtColorizerId id)
Definition: Factory.cpp:198
AutoPtr< IRenderer > getRenderer(const GuiSettings &settings)
Definition: Factory.cpp:58
AutoPtr< ICamera > getCamera(const GuiSettings &settings, const Pixel size)
Definition: Factory.cpp:28
Vector position(const Float a, const Float e, const Float u)
Computes the position on the elliptic trajectory.
Definition: TwoBody.cpp:82
Definition: Point.h:115
Definition: Point.h:101
Parameters of the rendered image.
Definition: IRenderer.h:60
Optional< Size > selected
Highlighted particle (only for interactive view).
Definition: IRenderer.h:86
struct RenderParams::@33 particles
Parameters of the particle renderer.
AutoPtr< ICamera > camera
Camera used for rendering.
Definition: IRenderer.h:63
void initialize(const GuiSettings &gui)
Sets up parameters using values stored in settings.
Definition: IRenderer.cpp:11