iMSTK
Interactive Medical Simulation Toolkit
sphFluid.cs
1 using Imstk;
2 
3 public class PbdCloth
4 {
5  private static int SCENE_ID = 1;
6 
7  public static void Main(string[] args)
8  {
9  // Setup logger (write to file and stdout)
10  Logger.startLogger();
11 
12  double particleRadius = 0.1;
13 
14  // Override particle radius for scene3 because particles in this scene were pre-generated using particle radius 0.08
15  if (SCENE_ID == 3)
16  {
17  particleRadius = 0.08;
18  }
19 
20  Scene scene = new Scene("SPH Fluid");
21 
22  SphObject fluidObj = generateFluid(particleRadius);
23  CollidingObject[] solids = generateSolids(scene);
24  scene.addSceneObject(fluidObj);
25  for (int i = 0; i < solids.Length; i++)
26  {
27  scene.addSceneObject(solids[i]);
28  }
29 
30  // Collision between fluid and solid objects
31  scene.addInteraction(new SphObjectCollision(fluidObj, solids[0]));
32  scene.addInteraction(new SphObjectCollision(fluidObj, solids[1]));
33  scene.addInteraction(new SphObjectCollision(fluidObj, solids[2]));
34 
35 
36  // configure camera
37  scene.getActiveCamera().setPosition(-0.475, 8.116, -6.728);
38 
39  // configure light (white)
40  DirectionalLight whiteLight = new DirectionalLight();
41  whiteLight.setFocalPoint(new Vec3d(5.0, -8.0, -5.0));
42  whiteLight.setIntensity(1.5);
43  scene.addLight("whiteLight", whiteLight);
44 
45  // Run the simulation
46  {
47  // Setup a viewer to render
48  VTKViewer viewer = new VTKViewer("Viewer");
49  viewer.setActiveScene(scene);
50  viewer.setWindowTitle("SPH Fluid");
51  viewer.setSize(1920, 1080);
52 
53  // Setup a scene manager to advance the scene
54  SceneManager sceneManager = new SceneManager("Scene Manager");
55  sceneManager.setActiveScene(scene);
56  sceneManager.pause();
57 
58  SimulationManager driver = new SimulationManager();
59  driver.addModule(viewer);
60  driver.addModule(sceneManager);
61 
62  // Add mouse and keyboard controls to the viewer
63  {
64  MouseSceneControl mouseControl = new MouseSceneControl();
65  mouseControl.setDevice(viewer.getMouseDevice());
66  mouseControl.setSceneManager(sceneManager);
67  scene.addControl(mouseControl);
68 
69  KeyboardSceneControl keyControl = new KeyboardSceneControl();
70  keyControl.setDevice(viewer.getKeyboardDevice());
71  keyControl.setSceneManager(new SceneManagerWeakPtr(sceneManager));
72  keyControl.setModuleDriver(new ModuleDriverWeakPtr(driver));
73  scene.addControl(keyControl);
74  }
75 
76  driver.start();
77  }
78  }
79 
80  public static SphObject generateFluid(double particleRadius)
81  {
82  VecDataArray3d particles = new VecDataArray3d();
83  switch (SCENE_ID)
84  {
85  case 1:
86  particles = generateSphereShapeFluid(particleRadius);
87  break;
88  case 2:
89  particles = generateBoxShapeFluid(particleRadius);
90  break;
91  case 3:
92  // particles = generateBunnyShapeFluid(particleRadius);
93  return null;
94  break;
95  default:
96  return null;
97  }
98 
99 
100  // Create a geometry object
101  PointSet geometry = new PointSet();
102  geometry.initialize(particles);
103 
104  // Create a fluids object
105  SphObject fluidObj = new SphObject("Sphere");
106 
107  // Create a visual model
108  VisualModel visualModel = new VisualModel();
109  visualModel.setGeometry(geometry);
110  RenderMaterial material = new RenderMaterial();
111  material.setDisplayMode(RenderMaterial.DisplayMode.Fluid);
112  //material.setDisplayMode(RenderMaterial.DisplayMode.Points);
113  if (material.getDisplayMode() == RenderMaterial.DisplayMode.Fluid)
114  {
115  material.setPointSize(0.1f);
116  }
117  else
118  {
119  material.setPointSize(20.0f);
120  material.setRenderPointsAsSpheres(true);
121  material.setColor(Color.Orange);
122  }
123  visualModel.setRenderMaterial(material);
124 
125  // Create a physics model
126  SphModel sphModel = new SphModel();
127  sphModel.setModelGeometry(geometry);
128 
129  // Configure model
130  SphModelConfig sphParams = new SphModelConfig(particleRadius);
131  sphParams.m_bNormalizeDensity = true;
132  if (SCENE_ID == 2) // highly viscous fluid
133  {
134  sphParams.m_kernelOverParticleRadiusRatio = 6.0;
135  sphParams.m_surfaceTensionStiffness = 5.0;
136  }
137 
138  if (SCENE_ID == 3) // bunny-shaped fluid
139  {
140  sphParams.m_frictionBoundary = 0.3;
141  }
142 
143  sphModel.configure(sphParams);
144  sphModel.setTimeStepSizeType(TimeSteppingType.RealTime);
145 
146  // Add the component models
147  fluidObj.addVisualModel(visualModel);
148  fluidObj.setCollidingGeometry(geometry);
149  fluidObj.setDynamicalModel(sphModel);
150  fluidObj.setPhysicsGeometry(geometry);
151 
152  return fluidObj;
153  }
154 
158  public static VecDataArray3d generateSphereShapeFluid(double particleRadius)
159  {
160  double sphereRadius = 2.0;
161  Vec3d sphereCenter = new Vec3d(0, 1, 0);
162  double sphereRadiusSqr = sphereRadius * sphereRadius;
163  double spacing = 2.0 * particleRadius;
164  int N = (int)(2.0 * sphereRadius / spacing); // Maximum number of particles in each dimension
165  // Vec3d lcorner = sphereCenter - new Vec3d(sphereRadius, sphereRadius, sphereRadius); // Cannot use auto here, due to Eigen bug
166  Vec3d lcorner = new Vec3d(sphereCenter[0] - sphereRadius, sphereCenter[1] - sphereRadius, sphereCenter[2] - sphereRadius); // Cannot use auto here, due to Eigen bug
167 
168  VecDataArray3d particles = new VecDataArray3d();
169  particles.reserve(N * N * N);
170 
171  for (int i = 0; i < N; ++i)
172  {
173  for (int j = 0; j < N; ++j)
174  {
175  for (int k = 0; k < N; ++k)
176  {
177  Vec3d ppos = lcorner + new Vec3d(spacing * (double)(i), spacing * (double)(j), spacing * (double)(k));
178  Vec3d cx = ppos - sphereCenter;
179  double nrm = cx[0] * cx[0] + cx[1] * cx[1] + cx[2] * cx[2];
180  if (nrm < sphereRadiusSqr)
181  {
182  particles.push_back(ppos);
183  }
184  }
185  }
186  }
187 
188  return particles;
189  }
190 
194  public static VecDataArray3d generateBoxShapeFluid(double particleRadius)
195  {
196  double boxWidth = 4.0;
197  Vec3d boxLowerCorner = new Vec3d(-2, -3, -2);
198 
199  double spacing = 2.0 * particleRadius;
200  int N = (int)(boxWidth / spacing);
201 
202  VecDataArray3d particles = new VecDataArray3d();
203  particles.reserve(N * N * N);
204 
205  for (int i = 0; i < N; ++i)
206  {
207  for (int j = 0; j < N; ++j)
208  {
209  for (int k = 0; k < N; ++k)
210  {
211  Vec3d ppos = boxLowerCorner + new Vec3d(spacing * i, spacing * j, spacing * k);
212  particles.push_back(ppos);
213  }
214  }
215  }
216 
217  return particles;
218  }
219 
220  public static CollidingObject[] generateSolids(Scene scene)
221  {
222  switch (SCENE_ID)
223  {
224  case 1:
225  return generateSolidsScene1();
226  case 2:
227  return null; // To avoid warning
228  // return generateSolidsScene2();
229  case 3:
230  return null; // To avoid warning
231  // return generateSolidsScene3();
232  case 4:
233  return null; // To avoid warning
234  // return generateSolidsScene4(scene);
235  default:
236  return null; // To avoid warning
237  }
238  }
239 
243  public static CollidingObject[] generateSolidsScene1()
244  {
245  CollidingObject[] solids = new CollidingObject[3];
246 
247  {
248  Plane geometry = new Plane();
249  geometry.setWidth(40.0);
250  geometry.setPosition(0.0, -6.0, 0.0);
251  geometry.setNormal(new Vec3d(0.0, 1.0, -0.5));
252 
253  VisualModel visualModel = new VisualModel();
254  visualModel.setGeometry(geometry);
255  RenderMaterial material = new RenderMaterial();
256  material.setColor(Color.DarkGray);
257  visualModel.setRenderMaterial(material);
258 
259  CollidingObject obj = new CollidingObject("Floor");
260  obj.addVisualModel(visualModel);
261  obj.setCollidingGeometry(geometry);
262  solids[0] = obj;
263  }
264  {
265  Plane geometry = new Plane();
266  geometry.setWidth(40.0);
267  geometry.setPosition(0.0, -6.0, 0.0);
268  geometry.setNormal(new Vec3d(0.0, 1.0, 1.0));
269 
270  VisualModel visualModel = new VisualModel();
271  visualModel.setGeometry(geometry);
272  RenderMaterial material = new RenderMaterial();
273  material.setColor(Color.LightGray);
274  visualModel.setRenderMaterial(material);
275 
276  CollidingObject obj = new CollidingObject("Back Plane");
277  obj.addVisualModel(visualModel);
278  obj.setCollidingGeometry(geometry);
279  solids[1] = obj;
280  }
281  {
282  Sphere geometry = new Sphere();
283  geometry.setRadius(2.0);
284  geometry.setPosition(0.0, -6.0, 0.0);
285 
286  VisualModel visualModel = new VisualModel();
287  visualModel.setGeometry(geometry);
288  RenderMaterial material = new RenderMaterial();
289  material.setColor(Color.Red);
290  visualModel.setRenderMaterial(material);
291 
292  CollidingObject obj = new CollidingObject("Sphere on Floor");
293  obj.addVisualModel(visualModel);
294  obj.setCollidingGeometry(geometry);
295  solids[2] = obj;
296  }
297 
298  return solids;
299  }
300 }
lazy initialized singleton
static VecDataArray3d generateBoxShapeFluid(double particleRadius)
Generate a box-shape fluid object.
Definition: sphFluid.cs:194
static VecDataArray3d generateSphereShapeFluid(double particleRadius)
Generate a sphere-shape fluid object.
Definition: sphFluid.cs:158
static CollidingObject [] generateSolidsScene1()
Generate two planes and a solid sphere.
Definition: sphFluid.cs:243
TimeSteppingType
Type of the update of the state of the body.