iMSTK
Interactive Medical Simulation Toolkit
Fluid.hpp
1 /*
2 ** This file is part of the Interactive Medical Simulation Toolkit (iMSTK)
3 ** iMSTK is distributed under the Apache License, Version 2.0.
4 ** See accompanying NOTICE for details.
5 */
6 
7 #include "imstkPointSet.h"
8 #include "imstkRenderMaterial.h"
9 #include "imstkScene.h"
10 #include "imstkSphObject.h"
11 #include "imstkSphModel.h"
12 #include "imstkVisualModel.h"
13 
14 using namespace imstk;
15 
19 std::shared_ptr<VecDataArray<double, 3>>
20 generateSphereShapeFluid(const double particleRadius)
21 {
22  const double sphereRadius = 2.0;
23  const Vec3d sphereCenter(0, 1, 0);
24 
25  const double sphereRadiusSqr = sphereRadius * sphereRadius;
26  const double spacing = 2.0 * particleRadius;
27  const int N = static_cast<int>(2.0 * sphereRadius / spacing); // Maximum number of particles in each dimension
28  const Vec3d lcorner = sphereCenter - Vec3d(sphereRadius, sphereRadius, sphereRadius); // Cannot use auto here, due to Eigen bug
29 
30  std::shared_ptr<VecDataArray<double, 3>> particles = std::make_shared<VecDataArray<double, 3>>();
31  particles->reserve(N * N * N);
32 
33  for (int i = 0; i < N; ++i)
34  {
35  for (int j = 0; j < N; ++j)
36  {
37  for (int k = 0; k < N; ++k)
38  {
39  Vec3d ppos = lcorner + Vec3d(spacing * static_cast<double>(i), spacing * static_cast<double>(j), spacing * static_cast<double>(k));
40  Vec3d cx = ppos - sphereCenter;
41  if (cx.squaredNorm() < sphereRadiusSqr)
42  {
43  particles->push_back(ppos);
44  }
45  }
46  }
47  }
48 
49  return particles;
50 }
51 
55 std::shared_ptr<VecDataArray<double, 3>>
56 generateBoxShapeFluid(const double particleRadius)
57 {
58  const double boxWidth = 4.0;
59  const Vec3d boxLowerCorner(-2, -3, -2);
60 
61  const double spacing = 2.0 * particleRadius;
62  const int N = static_cast<int>(boxWidth / spacing);
63 
64  std::shared_ptr<VecDataArray<double, 3>> particles = std::make_shared<VecDataArray<double, 3>>();
65  particles->reserve(N * N * N);
66 
67  for (int i = 0; i < N; ++i)
68  {
69  for (int j = 0; j < N; ++j)
70  {
71  for (int k = 0; k < N; ++k)
72  {
73  Vec3d ppos = boxLowerCorner + Vec3d(spacing * static_cast<double>(i), spacing * static_cast<double>(j), spacing * static_cast<double>(k));
74  particles->push_back(ppos);
75  }
76  }
77  }
78 
79  return particles;
80 }
81 
82 #if SCENE_ID == 3
83 std::shared_ptr<VecDataArray<double, 3>> getBunny(); // Defined in Bunny.cpp
84 #endif
85 std::shared_ptr<VecDataArray<double, 3>>
89 generateBunnyShapeFluid(const double particleRadius)
90 {
91  LOG_IF(FATAL, (std::abs(particleRadius - 0.08) > 1e-6)) << "Particle radius for this scene must be 0.08";
92  std::shared_ptr<VecDataArray<double, 3>> particles = std::make_shared<VecDataArray<double, 3>>();
93 #if SCENE_ID == 3
94  particles = getBunny();
95 #endif
96  return particles;
97 }
98 
102 std::shared_ptr<VecDataArray<double, 3>>
103 generatePipeFluid(const double particleRadius)
104 {
105  const double pipeRadius = 1.0;
106  const double pipeLength = 5.0;
107  const Vec3d lcorner(-5.0, 5.0, 0.0);
108  const Vec3d pipeLeftCenter = lcorner + Vec3d(0.0, pipeRadius, pipeRadius);
109 
110  const double spacing = 2.0 * particleRadius;
111  const int N_width = static_cast<int>(2.0 * pipeRadius / spacing); // Maximum number of particles in width dimension
112  const int N_length = static_cast<int>(pipeLength / spacing); // Maximum number of particles in length dimension
113 
114  imstkNew<VecDataArray<double, 3>> particlesPtr;
115  VecDataArray<double, 3>& particles = *particlesPtr.get();
116  particles.reserve(N_width * N_width * N_length);
117 
118  for (int i = 0; i < N_length; ++i)
119  {
120  for (int j = 0; j < N_width; ++j)
121  {
122  for (int k = 0; k < N_width; ++k)
123  {
124  Vec3d ppos = lcorner + Vec3d(spacing * static_cast<double>(i), spacing * static_cast<double>(j), spacing * static_cast<double>(k));
125  //const double cx = ppos.x() - pipeBottomCenter.x();
126  //const double cy = ppos.y() - pipeBottomCenter.y();
127  Vec3d cx = ppos - Vec3d(spacing * static_cast<double>(i), 0.0, 0.0) - pipeLeftCenter;
128  if (cx.squaredNorm() < pipeRadius)
129  {
130  particles.push_back(ppos);
131  }
132  }
133  }
134  }
135 
136  return particlesPtr;
137 }
138 
139 std::shared_ptr<VecDataArray<double, 3>>
140 initializeNonZeroVelocities(const int numParticles)
141 {
142  imstkNew<VecDataArray<double, 3>> initVelocitiesPtr(numParticles);
143  initVelocitiesPtr->fill(Vec3d(10.0, 0.0, 0.0));
144  return initVelocitiesPtr;
145 }
146 
147 std::shared_ptr<SphObject>
148 generateFluid(const double particleRadius)
149 {
150  std::shared_ptr<VecDataArray<double, 3>> particles = std::make_shared<VecDataArray<double, 3>>();
151  switch (SCENE_ID)
152  {
153  case 1:
154  particles = generateSphereShapeFluid(particleRadius);
155  break;
156  case 2:
157  particles = generateBoxShapeFluid(particleRadius);
158  break;
159  case 3:
160  particles = generateBunnyShapeFluid(particleRadius);
161  break;
162  default:
163  LOG(FATAL) << "Invalid scene index";
164  }
165 
166  LOG(INFO) << "Number of particles: " << particles->size();
167 
168  // Create a geometry object
169  imstkNew<PointSet> geometry;
170  geometry->initialize(particles);
171 
172  // Create a fluids object
173  imstkNew<SphObject> fluidObj("SPHSphere");
174 
175  // Create a visual model
176  imstkNew<VisualModel> visualModel;
177  visualModel->setGeometry(geometry);
178  imstkNew<RenderMaterial> material;
179  material->setDisplayMode(RenderMaterial::DisplayMode::Fluid);
180  //material->setDisplayMode(RenderMaterial::DisplayMode::Points);
182  {
183  material->setPointSize(0.1);
184  }
185  else
186  {
187  material->setPointSize(20.0);
188  material->setRenderPointsAsSpheres(true);
189  material->setColor(Color::Orange);
190  }
191  visualModel->setRenderMaterial(material);
192 
193  // Create a physics model
194  imstkNew<SphModel> sphModel;
195  sphModel->setModelGeometry(geometry);
196 
197  // Configure model
198  imstkNew<SphModelConfig> sphParams(particleRadius);
199  sphParams->m_bNormalizeDensity = true;
200  if (SCENE_ID == 2) // highly viscous fluid
201  {
202  sphParams->m_kernelOverParticleRadiusRatio = 6.0;
203  sphParams->m_surfaceTensionStiffness = 5.0;
204  }
205 
206  if (SCENE_ID == 3) // bunny-shaped fluid
207  {
208  sphParams->m_frictionBoundary = 0.3;
209  }
210 
211  sphModel->configure(sphParams);
212  sphModel->setTimeStepSizeType(TimeSteppingType::RealTime);
213 
214  // Add the component models
215  fluidObj->addVisualModel(visualModel);
216  fluidObj->setCollidingGeometry(geometry);
217  fluidObj->setDynamicalModel(sphModel);
218  fluidObj->setPhysicsGeometry(geometry);
219 
220  return fluidObj;
221 }
void initialize(std::shared_ptr< VecDataArray< double, 3 >> positions)
Initializes the data structure given vertex positions.
void configure(const std::shared_ptr< SphModelConfig > &params)
Set simulation parameters.
Definition: imstkSphModel.h:90
Renders a set of points using a screen-space fluid renderer.
virtual void setTimeStepSizeType(const TimeSteppingType type)
Get/Set the type of approach used to update the time step size after every frame. ...
Compound Geometry.
void reserve(const int size) override
Allocates extra capacity, for the number of values, conservative reallocate.
void push_back(const ValueType &val)
Append the data array to hold the new value, resizes if neccesary.
const std::shared_ptr< T > & get() const
Returns const ref to STL smart pointer.
Definition: imstkNew.h:56
std::shared_ptr<T> obj = std::make_shared<T>(); equivalent, convenience class for STL shared allocati...
Definition: imstkNew.h:29
void setModelGeometry(std::shared_ptr< Geometry > geometry)
Sets the model geometry.
DisplayMode getDisplayMode() const
Get/Set display mode.
void setRenderMaterial(std::shared_ptr< RenderMaterial > renderMaterial)
Set/Get render material.