Skip to content

Commit f04bcf4

Browse files
authored
[BUG FIX] Fix default visualization mode for emitter surface. (#1665)
* Fix default visualization mode for emitter surface * Fix PBD set velocity * Add runtime check for emitter visualisation mode * Add runtime check for MPM grid size * Add unit test for fluid emitter * Fix and improve example 'water_wheel.py'
1 parent d2a9ae0 commit f04bcf4

File tree

7 files changed

+115
-29
lines changed

7 files changed

+115
-29
lines changed

examples/coupling/water_wheel.py

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77

88
def main():
99
parser = argparse.ArgumentParser()
10+
parser.add_argument("--solver", type=str, default="sph", choices=("sph", "mpm"))
11+
parser.add_argument("--recon", action="store_true", default=False)
1012
parser.add_argument("-v", "--vis", action="store_true", default=False)
1113
args = parser.parse_args()
1214

@@ -20,8 +22,14 @@ def main():
2022
substeps=10,
2123
),
2224
mpm_options=gs.options.MPMOptions(
23-
lower_bound=(0.0, 0.0, 0.0),
24-
upper_bound=(1.0, 1.0, 1.5),
25+
lower_bound=(0.0, -1.5, 0.0),
26+
upper_bound=(1.0, 1.5, 4.0),
27+
),
28+
sph_options=gs.options.SPHOptions(
29+
particle_size=0.02,
30+
),
31+
pbd_options=gs.options.PBDOptions(
32+
particle_size=0.02,
2533
),
2634
viewer_options=gs.options.ViewerOptions(
2735
camera_pos=(5.5, 6.5, 3.2),
@@ -33,13 +41,10 @@ def main():
3341
rendered_envs_idx=[0],
3442
),
3543
show_viewer=args.vis,
36-
sph_options=gs.options.SPHOptions(
37-
particle_size=0.02,
38-
),
3944
)
4045

4146
plane = scene.add_entity(gs.morphs.Plane())
42-
wheel_0 = scene.add_entity(
47+
wheel = scene.add_entity(
4348
morph=gs.morphs.URDF(
4449
file="urdf/wheel/fancy_wheel.urdf",
4550
pos=(0.5, 0.25, 1.6),
@@ -50,17 +55,19 @@ def main():
5055
)
5156

5257
emitter = scene.add_emitter(
53-
material=gs.materials.SPH.Liquid(sampler="regular"),
58+
material=getattr(gs.materials, args.solver.upper()).Liquid(
59+
sampler="regular",
60+
),
5461
max_particles=100000,
5562
surface=gs.surfaces.Glass(
5663
color=(0.7, 0.85, 1.0, 0.7),
64+
vis_mode="recon" if args.recon else "particle",
5765
),
5866
)
59-
scene.build(n_envs=5)
67+
scene.build(n_envs=2)
6068

6169
horizon = 500
6270
for i in range(horizon):
63-
print(i)
6471
emitter.emit(
6572
pos=np.array([0.5, 1.0, 3.5]),
6673
direction=np.array([0.0, 0, -1.0]),

examples/pbd_liquid.py

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,24 +17,29 @@ def main():
1717
sim_options=gs.options.SimOptions(
1818
dt=2e-3,
1919
),
20-
viewer_options=gs.options.ViewerOptions(
21-
camera_pos=(3.5, 1.0, 2.5),
22-
camera_lookat=(0.0, 0.0, 0.5),
23-
camera_fov=40,
24-
),
25-
show_viewer=False,
2620
pbd_options=gs.options.PBDOptions(
2721
lower_bound=(0.0, 0.0, 0.0),
2822
upper_bound=(1.0, 1.0, 1.0),
2923
max_density_solver_iterations=10,
3024
max_viscosity_solver_iterations=1,
3125
),
26+
viewer_options=gs.options.ViewerOptions(
27+
camera_pos=(3.5, 1.0, 2.5),
28+
camera_lookat=(0.0, 0.0, 0.5),
29+
camera_fov=40,
30+
),
31+
show_viewer=args.vis,
3232
)
3333

3434
########################## entities ##########################
3535

3636
liquid = scene.add_entity(
37-
material=gs.materials.PBD.Liquid(rho=1.0, density_relaxation=1.0, viscosity_relaxation=0.0, sampler="regular"),
37+
material=gs.materials.PBD.Liquid(
38+
sampler="regular",
39+
rho=1.0,
40+
density_relaxation=1.0,
41+
viscosity_relaxation=0.0,
42+
),
3843
morph=gs.morphs.Box(lower=(0.2, 0.1, 0.1), upper=(0.4, 0.3, 0.5)),
3944
)
4045
scene.build(n_envs=5)

genesis/engine/entities/particle_entity.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -243,8 +243,8 @@ def sample(self):
243243

244244
if isinstance(self._morph, gs.options.morphs.Nowhere):
245245
origin = gu.nowhere()
246-
self._vverts = np.array([], dtype=gs.np_float)
247-
self._vfaces = np.array([], dtype=gs.np_float)
246+
self._vverts = np.zeros((0, 3), dtype=gs.np_float)
247+
self._vfaces = np.zeros((0, 3), dtype=gs.np_float)
248248
elif isinstance(self._morph, gs.options.morphs.MeshSet):
249249
for i in range(len(self._morph.files)):
250250
pos_i = np.asarray(self._morph.poss[i], dtype=gs.np_float)

genesis/engine/scene.py

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,7 @@ def add_entity(
333333
if surface.vis_mode is None:
334334
surface.vis_mode = "visual"
335335

336-
if surface.vis_mode not in ["visual", "collision", "sdf"]:
336+
if surface.vis_mode not in ("visual", "collision", "sdf"):
337337
gs.raise_exception(
338338
f"Unsupported `surface.vis_mode` for material {material}: '{surface.vis_mode}'. Expected one of: ['visual', 'collision', 'sdf']."
339339
)
@@ -352,7 +352,7 @@ def add_entity(
352352
if surface.vis_mode is None:
353353
surface.vis_mode = "particle"
354354

355-
if surface.vis_mode not in ["particle", "recon"]:
355+
if surface.vis_mode not in ("particle", "recon"):
356356
gs.raise_exception(
357357
f"Unsupported `surface.vis_mode` for material {material}: '{surface.vis_mode}'. Expected one of: ['particle', 'recon']."
358358
)
@@ -370,7 +370,7 @@ def add_entity(
370370
if surface.vis_mode is None:
371371
surface.vis_mode = "visual"
372372

373-
if surface.vis_mode not in ["visual", "particle", "recon"]:
373+
if surface.vis_mode not in ("visual", "particle", "recon"):
374374
gs.raise_exception(
375375
f"Unsupported `surface.vis_mode` for material {material}: '{surface.vis_mode}'. Expected one of: ['visual', 'particle', 'recon']."
376376
)
@@ -612,11 +612,13 @@ def add_emitter(
612612
Parameters
613613
----------
614614
material : gs.materials.Material
615-
The material of the fluid to be emitted. Must be an instance of `gs.materials.MPM.Base` or `gs.materials.SPH.Base`.
615+
The material of the fluid to be emitted. Must be an instance of `gs.materials.MPM.Base`,
616+
`gs.materials.SPH.Base`, `gs.materials.PBD.Particle` or `gs.materials.PBD.Liquid`.
616617
max_particles : int
617-
The maximum number of particles that can be emitted by the emitter. Particles will be recycled once this limit is reached.
618+
The maximum number of particles that can be emitted by the emitter. Particles will be recycled once this
619+
limit is reached.
618620
surface : gs.surfaces.Surface | None, optional
619-
The surface of the emitter. If None, use ``gs.surfaces.Default(color=(0.6, 0.8, 1.0, 1.0))``.
621+
The surface of the emitter. If None, use `gs.surfaces.Default(color=(0.6, 0.8, 1.0, 1.0))`.
620622
621623
Returns
622624
-------
@@ -631,12 +633,18 @@ def add_emitter(
631633
material, (gs.materials.MPM.Base, gs.materials.SPH.Base, gs.materials.PBD.Particle, gs.materials.PBD.Liquid)
632634
):
633635
gs.raise_exception(
634-
"Non-supported material for emitter. Supported materials are: `gs.materials.MPM.Base`, `gs.materials.SPH.Base`, `gs.materials.PBD.Particle`, `gs.materials.PBD.Liquid`."
636+
"Non-supported material for emitter. Supported materials are: `gs.materials.MPM.Base`, "
637+
"`gs.materials.SPH.Base`, `gs.materials.PBD.Particle`, `gs.materials.PBD.Liquid`."
635638
)
636639

637640
if surface is None:
638641
surface = gs.surfaces.Default(color=(0.6, 0.8, 1.0, 1.0))
639642

643+
if surface.vis_mode is None:
644+
surface.vis_mode = "particle"
645+
if surface.vis_mode == "visual":
646+
gs.raise_exception("surface.vis_mode='visual' is not supported for fluid emitters.")
647+
640648
emitter = Emitter(max_particles)
641649
entity = self.add_entity(
642650
morph=gs.morphs.Nowhere(n_particles=max_particles),

genesis/engine/solvers/mpm_solver.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
from typing import TYPE_CHECKING
2+
23
import numpy as np
34
import gstaichi as ti
45
import torch
56

67
import genesis as gs
7-
from genesis.options.solvers import MPMOptions
88
import genesis.utils.geom as gu
9+
import genesis.utils.sdf_decomp as sdf_decomp
910
from genesis.engine.boundaries import CubeBoundary
1011
from genesis.engine.entities import MPMEntity
1112
from genesis.engine.states.solvers import MPMSolverState
12-
import genesis.utils.sdf_decomp as sdf_decomp
13+
from genesis.options.solvers import MPMOptions
1314

1415
from .base_solver import Solver
1516

@@ -59,6 +60,11 @@ def __init__(self, scene: "Scene", sim: "Simulator", options: "MPMOptions"):
5960

6061
if sim.requires_grad:
6162
gs.raise_exception("Sparse grid is not supported in differentiable mode.")
63+
if np.prod(self._grid_res) > 1e9:
64+
gs.raise_exception(
65+
"Grid size larger than 1e9 not supported by MPM solver. Please reduce 'grid_density', or set tighter "
66+
"boundaries via 'lower_bound' / 'upper_bound'."
67+
)
6268

6369
# materials
6470
self._mats = list()
@@ -146,8 +152,8 @@ def init_particle_fields(self):
146152

147153
def init_grid_fields(self):
148154
grid_cell_state = ti.types.struct(
149-
vel_in=gs.ti_vec3, # input momentum/velocity
150155
mass=gs.ti_float, # mass
156+
vel_in=gs.ti_vec3, # input momentum/velocity
151157
vel_out=gs.ti_vec3, # output momentum/velocity
152158
)
153159

genesis/engine/solvers/pbd_solver.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -854,7 +854,7 @@ def _kernel_set_particles_vel(
854854
for i_p, i_b in ti.ndrange(n_particles, self._B):
855855
i_global = i_p + particle_start
856856
for k in ti.static(range(3)):
857-
self.particles[i_global, i_b].vel[k] = vel[i_p, k]
857+
self.particles[i_global, i_b].vel[k] = vel[i_b, i_p, k]
858858

859859
@ti.kernel
860860
def _kernel_set_particles_active(

tests/test_hybrid.py

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,3 +73,63 @@ def test_rigid_mpm_muscle(show_viewer):
7373

7474
with np.testing.assert_raises(AssertionError):
7575
assert_allclose(ball.get_pos(), ball_pos_init, atol=1e-2)
76+
77+
78+
@pytest.mark.required
79+
@pytest.mark.parametrize(
80+
"material_type",
81+
[
82+
gs.materials.PBD.Liquid,
83+
gs.materials.SPH.Liquid,
84+
gs.materials.MPM.Liquid,
85+
gs.materials.MPM.Sand,
86+
gs.materials.MPM.Snow,
87+
gs.materials.MPM.Elastic, # This makes little sense but nothing prevents doing this
88+
],
89+
)
90+
def test_fluid_emitter(material_type, show_viewer):
91+
scene = gs.Scene(
92+
sim_options=gs.options.SimOptions(
93+
dt=4e-3,
94+
substeps=10,
95+
),
96+
mpm_options=gs.options.MPMOptions(
97+
lower_bound=(0.0, -1.5, 0.0),
98+
upper_bound=(1.0, 1.5, 4.0),
99+
),
100+
sph_options=gs.options.SPHOptions(
101+
particle_size=0.02,
102+
),
103+
pbd_options=gs.options.PBDOptions(
104+
particle_size=0.02,
105+
),
106+
viewer_options=gs.options.ViewerOptions(
107+
camera_pos=(5.5, 6.5, 3.2),
108+
camera_lookat=(0.5, 1.5, 1.5),
109+
camera_fov=35,
110+
max_FPS=120,
111+
),
112+
vis_options=gs.options.VisOptions(
113+
rendered_envs_idx=[0],
114+
),
115+
show_viewer=show_viewer,
116+
)
117+
plane = scene.add_entity(gs.morphs.Plane())
118+
wheel = scene.add_entity(
119+
morph=gs.morphs.URDF(
120+
file="urdf/wheel/fancy_wheel.urdf",
121+
pos=(0.5, 0.25, 1.6),
122+
euler=(0, 0, 0),
123+
fixed=True,
124+
convexify=False,
125+
),
126+
)
127+
emitter = scene.add_emitter(
128+
material=material_type(),
129+
max_particles=100000,
130+
surface=gs.surfaces.Glass(
131+
color=(0.7, 0.85, 1.0, 0.7),
132+
),
133+
)
134+
scene.build(n_envs=2)
135+
scene.step()

0 commit comments

Comments
 (0)