warp-lang 1.4.1__py3-none-win_amd64.whl → 1.5.0__py3-none-win_amd64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of warp-lang might be problematic. Click here for more details.

Files changed (164) hide show
  1. warp/__init__.py +4 -0
  2. warp/autograd.py +43 -8
  3. warp/bin/warp-clang.dll +0 -0
  4. warp/bin/warp.dll +0 -0
  5. warp/build.py +21 -2
  6. warp/build_dll.py +23 -6
  7. warp/builtins.py +1920 -111
  8. warp/codegen.py +186 -62
  9. warp/config.py +2 -2
  10. warp/context.py +322 -73
  11. warp/examples/assets/pixel.jpg +0 -0
  12. warp/examples/benchmarks/benchmark_cloth_paddle.py +86 -0
  13. warp/examples/benchmarks/benchmark_gemm.py +121 -0
  14. warp/examples/benchmarks/benchmark_interop_paddle.py +158 -0
  15. warp/examples/benchmarks/benchmark_tile.py +179 -0
  16. warp/examples/core/example_dem.py +2 -1
  17. warp/examples/core/example_mesh_intersect.py +3 -3
  18. warp/examples/fem/example_adaptive_grid.py +37 -10
  19. warp/examples/fem/example_apic_fluid.py +3 -2
  20. warp/examples/fem/example_convection_diffusion_dg.py +4 -5
  21. warp/examples/fem/example_deformed_geometry.py +1 -1
  22. warp/examples/fem/example_diffusion_3d.py +47 -4
  23. warp/examples/fem/example_distortion_energy.py +220 -0
  24. warp/examples/fem/example_magnetostatics.py +127 -85
  25. warp/examples/fem/example_nonconforming_contact.py +5 -5
  26. warp/examples/fem/example_stokes.py +3 -1
  27. warp/examples/fem/example_streamlines.py +12 -19
  28. warp/examples/fem/utils.py +38 -15
  29. warp/examples/optim/example_walker.py +2 -2
  30. warp/examples/sim/example_cloth.py +2 -25
  31. warp/examples/sim/example_jacobian_ik.py +6 -2
  32. warp/examples/sim/example_quadruped.py +2 -1
  33. warp/examples/tile/example_tile_convolution.py +58 -0
  34. warp/examples/tile/example_tile_fft.py +47 -0
  35. warp/examples/tile/example_tile_filtering.py +105 -0
  36. warp/examples/tile/example_tile_matmul.py +79 -0
  37. warp/examples/tile/example_tile_mlp.py +375 -0
  38. warp/fem/__init__.py +8 -0
  39. warp/fem/cache.py +16 -12
  40. warp/fem/dirichlet.py +1 -1
  41. warp/fem/domain.py +44 -1
  42. warp/fem/field/__init__.py +1 -2
  43. warp/fem/field/field.py +31 -19
  44. warp/fem/field/nodal_field.py +101 -49
  45. warp/fem/field/virtual.py +794 -0
  46. warp/fem/geometry/__init__.py +2 -2
  47. warp/fem/geometry/deformed_geometry.py +3 -105
  48. warp/fem/geometry/element.py +13 -0
  49. warp/fem/geometry/geometry.py +165 -5
  50. warp/fem/geometry/grid_2d.py +3 -6
  51. warp/fem/geometry/grid_3d.py +31 -28
  52. warp/fem/geometry/hexmesh.py +3 -46
  53. warp/fem/geometry/nanogrid.py +3 -2
  54. warp/fem/geometry/{quadmesh_2d.py → quadmesh.py} +280 -159
  55. warp/fem/geometry/tetmesh.py +2 -43
  56. warp/fem/geometry/{trimesh_2d.py → trimesh.py} +354 -186
  57. warp/fem/integrate.py +683 -261
  58. warp/fem/linalg.py +404 -0
  59. warp/fem/operator.py +101 -18
  60. warp/fem/polynomial.py +5 -5
  61. warp/fem/quadrature/quadrature.py +45 -21
  62. warp/fem/space/__init__.py +45 -11
  63. warp/fem/space/basis_function_space.py +451 -0
  64. warp/fem/space/basis_space.py +58 -11
  65. warp/fem/space/function_space.py +146 -5
  66. warp/fem/space/grid_2d_function_space.py +80 -66
  67. warp/fem/space/grid_3d_function_space.py +113 -68
  68. warp/fem/space/hexmesh_function_space.py +96 -108
  69. warp/fem/space/nanogrid_function_space.py +62 -110
  70. warp/fem/space/quadmesh_function_space.py +208 -0
  71. warp/fem/space/shape/__init__.py +45 -7
  72. warp/fem/space/shape/cube_shape_function.py +328 -54
  73. warp/fem/space/shape/shape_function.py +10 -1
  74. warp/fem/space/shape/square_shape_function.py +328 -60
  75. warp/fem/space/shape/tet_shape_function.py +269 -19
  76. warp/fem/space/shape/triangle_shape_function.py +238 -19
  77. warp/fem/space/tetmesh_function_space.py +69 -37
  78. warp/fem/space/topology.py +38 -0
  79. warp/fem/space/trimesh_function_space.py +179 -0
  80. warp/fem/utils.py +6 -331
  81. warp/jax_experimental.py +3 -1
  82. warp/native/array.h +55 -40
  83. warp/native/builtin.h +124 -43
  84. warp/native/bvh.h +4 -0
  85. warp/native/coloring.cpp +600 -0
  86. warp/native/cuda_util.cpp +14 -0
  87. warp/native/cuda_util.h +2 -1
  88. warp/native/fabric.h +8 -0
  89. warp/native/hashgrid.h +4 -0
  90. warp/native/marching.cu +8 -0
  91. warp/native/mat.h +14 -3
  92. warp/native/mathdx.cpp +59 -0
  93. warp/native/mesh.h +4 -0
  94. warp/native/range.h +13 -1
  95. warp/native/reduce.cpp +9 -1
  96. warp/native/reduce.cu +7 -0
  97. warp/native/runlength_encode.cpp +9 -1
  98. warp/native/runlength_encode.cu +7 -1
  99. warp/native/scan.cpp +8 -0
  100. warp/native/scan.cu +8 -0
  101. warp/native/scan.h +8 -1
  102. warp/native/sparse.cpp +8 -0
  103. warp/native/sparse.cu +8 -0
  104. warp/native/temp_buffer.h +7 -0
  105. warp/native/tile.h +1857 -0
  106. warp/native/tile_gemm.h +341 -0
  107. warp/native/tile_reduce.h +210 -0
  108. warp/native/volume_builder.cu +8 -0
  109. warp/native/volume_builder.h +8 -0
  110. warp/native/warp.cpp +10 -2
  111. warp/native/warp.cu +369 -15
  112. warp/native/warp.h +12 -2
  113. warp/optim/adam.py +39 -4
  114. warp/paddle.py +29 -12
  115. warp/render/render_opengl.py +137 -65
  116. warp/sim/graph_coloring.py +292 -0
  117. warp/sim/integrator_euler.py +4 -2
  118. warp/sim/integrator_featherstone.py +115 -44
  119. warp/sim/integrator_vbd.py +6 -0
  120. warp/sim/model.py +90 -17
  121. warp/stubs.py +651 -85
  122. warp/tape.py +12 -7
  123. warp/tests/assets/pixel.npy +0 -0
  124. warp/tests/aux_test_instancing_gc.py +18 -0
  125. warp/tests/test_array.py +207 -48
  126. warp/tests/test_closest_point_edge_edge.py +8 -8
  127. warp/tests/test_codegen.py +120 -1
  128. warp/tests/test_codegen_instancing.py +30 -0
  129. warp/tests/test_collision.py +110 -0
  130. warp/tests/test_coloring.py +241 -0
  131. warp/tests/test_context.py +34 -0
  132. warp/tests/test_examples.py +18 -4
  133. warp/tests/test_fabricarray.py +33 -0
  134. warp/tests/test_fem.py +453 -113
  135. warp/tests/test_func.py +48 -1
  136. warp/tests/test_generics.py +52 -0
  137. warp/tests/test_iter.py +68 -0
  138. warp/tests/test_mat_scalar_ops.py +1 -1
  139. warp/tests/test_mesh_query_point.py +5 -4
  140. warp/tests/test_module_hashing.py +23 -0
  141. warp/tests/test_paddle.py +27 -87
  142. warp/tests/test_print.py +191 -1
  143. warp/tests/test_spatial.py +1 -1
  144. warp/tests/test_tile.py +700 -0
  145. warp/tests/test_tile_mathdx.py +144 -0
  146. warp/tests/test_tile_mlp.py +383 -0
  147. warp/tests/test_tile_reduce.py +374 -0
  148. warp/tests/test_tile_shared_memory.py +190 -0
  149. warp/tests/test_vbd.py +12 -20
  150. warp/tests/test_volume.py +43 -0
  151. warp/tests/unittest_suites.py +23 -2
  152. warp/tests/unittest_utils.py +4 -0
  153. warp/types.py +339 -73
  154. warp/utils.py +22 -1
  155. {warp_lang-1.4.1.dist-info → warp_lang-1.5.0.dist-info}/METADATA +33 -7
  156. {warp_lang-1.4.1.dist-info → warp_lang-1.5.0.dist-info}/RECORD +159 -132
  157. {warp_lang-1.4.1.dist-info → warp_lang-1.5.0.dist-info}/WHEEL +1 -1
  158. warp/fem/field/test.py +0 -180
  159. warp/fem/field/trial.py +0 -183
  160. warp/fem/space/collocated_function_space.py +0 -102
  161. warp/fem/space/quadmesh_2d_function_space.py +0 -261
  162. warp/fem/space/trimesh_2d_function_space.py +0 -153
  163. {warp_lang-1.4.1.dist-info → warp_lang-1.5.0.dist-info}/LICENSE.md +0 -0
  164. {warp_lang-1.4.1.dist-info → warp_lang-1.5.0.dist-info}/top_level.txt +0 -0
@@ -8,17 +8,18 @@
8
8
  ###########################################################################
9
9
  # Example Magnetostatics
10
10
  #
11
- # This example demonstrates solving an in-plane magnetostatics problem
12
- # using a curl-curl formulation
11
+ # This example demonstrates solving a 3d magnetostatics problem
12
+ # (a copper coil with radial current around a cylindrical iron core)
13
+ # using a curl-curl formulation and H(curl)-conforming function space
13
14
  #
14
15
  # 1/mu Curl B + j = 0
15
16
  # Div. B = 0
16
17
  #
17
- # solved over field A such that B = Curl A, A = (0, 0, a_z),
18
- # and a_z = 0 on the domain boundary
18
+ # solved over field A such that B = Curl A,
19
+ # and Direchlet homogeneous essential boundary conditions
19
20
  #
20
- # This example also illustrates using an ImplictField to warp a square mesh
21
- # to a circular domain
21
+ # This example also illustrates using an ImplictField to warp a grid mesh
22
+ # to a cylindrical domain
22
23
  ###########################################################################
23
24
 
24
25
  import numpy as np
@@ -27,138 +28,179 @@ import warp as wp
27
28
  import warp.examples.fem.utils as fem_example_utils
28
29
  import warp.fem as fem
29
30
 
30
- # Vacuum and copper magnetic permeabilities
31
- MU_0 = wp.constant(np.pi * 4.0e-7)
32
- MU_C = wp.constant(1.25e-6)
31
+ # Physics constants
32
+ MU_0 = wp.constant(np.pi * 4.0e-7) # Vacuum magnetic permeability
33
+ MU_c = wp.constant(1.25e-6) # Copper magnetic permeability
34
+ MU_i = wp.constant(6.0e-3) # Iron magnetic permeability
33
35
 
34
36
 
35
37
  @wp.func
36
- def square_to_disk(x: wp.vec2):
38
+ def cube_to_cylinder(x: wp.vec3):
37
39
  # mapping from unit square to unit disk
38
- return wp.normalize(x) * wp.max(wp.abs(x))
40
+ pos_xz = wp.vec3(x[0], 0.0, x[2])
41
+ return wp.max(wp.abs(pos_xz)) * wp.normalize(pos_xz) + wp.vec3(0.0, x[1], 0.0)
39
42
 
40
43
 
41
44
  @wp.func
42
- def square_to_disk_grad(x: wp.vec2):
45
+ def cube_to_cylinder_grad(x: wp.vec3):
43
46
  # gradient of mapping from unit square to unit disk
44
- if x == wp.vec2(0.0):
45
- return wp.mat22(0.0)
47
+ pos_xz = wp.vec3(x[0], 0.0, x[2])
48
+ if pos_xz == wp.vec3(0.0):
49
+ grad = wp.mat33(0.0)
50
+ else:
51
+ dir_xz = wp.normalize(pos_xz)
52
+ dir_grad = (wp.identity(n=3, dtype=float) - wp.outer(dir_xz, dir_xz)) / wp.length(pos_xz)
53
+
54
+ abs_xz = wp.abs(pos_xz)
55
+ xinf_grad = wp.select(
56
+ abs_xz[0] > abs_xz[2], wp.vec3(0.0, 0.0, wp.sign(pos_xz[2])), wp.vec(wp.sign(pos_xz[0]), 0.0, 0.0)
57
+ )
58
+ grad = dir_grad * wp.max(abs_xz) + wp.outer(dir_xz, xinf_grad)
46
59
 
47
- d = wp.normalize(x)
48
- d_grad = (wp.identity(n=2, dtype=float) - wp.outer(d, d)) / wp.length(x)
60
+ grad[1, 1] = 1.0
61
+ return grad
49
62
 
50
- ax = wp.abs(x)
51
- xinf = wp.max(ax)
52
63
 
53
- xinf_grad = wp.select(ax[0] > ax[1], wp.vec2(0.0, wp.sign(x[1])), wp.vec(wp.sign(x[0]), 0.0))
64
+ @wp.func
65
+ def permeability_field(
66
+ pos: wp.vec3,
67
+ core_radius: float,
68
+ core_height: float,
69
+ coil_internal_radius: float,
70
+ coil_external_radius: float,
71
+ coil_height: float,
72
+ ):
73
+ x = wp.abs(pos[0])
74
+ y = wp.abs(pos[1])
75
+ z = wp.abs(pos[2])
54
76
 
55
- return d_grad * xinf + wp.outer(d, xinf_grad)
77
+ r = wp.sqrt(x * x + z * z)
56
78
 
79
+ if r <= core_radius:
80
+ return wp.select(y < core_height, MU_0, MU_i)
57
81
 
58
- @wp.func
59
- def permeability_field(pos: wp.vec2, coil_height: float, coil_internal_radius: float, coil_external_radius: float):
60
- # space-varying permeability
82
+ if r >= coil_internal_radius and r <= coil_external_radius:
83
+ return wp.select(y < coil_height, MU_0, MU_c)
61
84
 
62
- x = wp.abs(pos[0])
63
- y = wp.abs(pos[1])
64
- return wp.select(
65
- y < coil_height and x > coil_internal_radius and x < coil_external_radius,
66
- MU_0,
67
- MU_C,
68
- )
85
+ return MU_0
69
86
 
70
87
 
71
88
  @wp.func
72
89
  def current_field(
73
- pos: wp.vec2, coil_height: float, coil_internal_radius: float, coil_external_radius: float, current: float
90
+ pos: wp.vec3,
91
+ current: float,
92
+ coil_internal_radius: float,
93
+ coil_external_radius: float,
94
+ coil_height: float,
74
95
  ):
75
- # space-varying current direction along z axis (0, +1 or -1)
76
- x = wp.abs(pos[0])
96
+ x = pos[0]
77
97
  y = wp.abs(pos[1])
78
- return (
79
- wp.select(
80
- y < coil_height and x > coil_internal_radius and x < coil_external_radius,
81
- 0.0,
82
- wp.sign(pos[0]),
83
- )
84
- * current
85
- )
98
+ z = pos[2]
86
99
 
100
+ r = wp.sqrt(x * x + z * z)
87
101
 
88
- @fem.integrand
89
- def curl_z(u: fem.Field, s: fem.Sample):
90
- # projection of curl((0, 0, u)) over z axis
91
- du = fem.grad(u, s)
92
- return wp.vec2(du[1], -du[0])
102
+ return wp.select(
103
+ y < coil_height and r >= coil_internal_radius and r <= coil_external_radius,
104
+ wp.vec3(0.0),
105
+ wp.vec3(z, 0.0, -x) * current / r,
106
+ )
93
107
 
94
108
 
95
109
  @fem.integrand
96
110
  def curl_curl_form(s: fem.Sample, domain: fem.Domain, u: fem.Field, v: fem.Field, mu: fem.Field):
97
- return wp.dot(curl_z(u, s), curl_z(v, s)) / mu(s)
111
+ return wp.dot(fem.curl(u, s), fem.curl(v, s)) / mu(s)
98
112
 
99
113
 
100
114
  @fem.integrand
101
115
  def mass_form(s: fem.Sample, domain: fem.Domain, v: fem.Field, u: fem.Field):
102
- return u(s) * v(s)
116
+ return wp.dot(u(s), v(s))
117
+
118
+
119
+ @fem.integrand
120
+ def curl_expr(s: fem.Sample, u: fem.Field):
121
+ return fem.curl(u, s)
103
122
 
104
123
 
105
124
  class Example:
106
- def __init__(self, quiet=False, degree=2, resolution=32, domain_radius=2.0, current=1.0e6):
125
+ def __init__(self, quiet=False, mesh: str = "grid", resolution=32, domain_radius=2.0, current=1.0e6):
107
126
  # We mesh the unit disk by first meshing the unit square, then building a deformed geometry
108
127
  # from an implicit mapping field
109
- square_geo = fem.Grid2D(
110
- bounds_lo=wp.vec2(-domain_radius, -domain_radius),
111
- bounds_hi=wp.vec2(domain_radius, domain_radius),
112
- res=wp.vec2i(resolution, resolution),
113
- )
114
128
 
115
- def_field = fem.ImplicitField(domain=fem.Cells(square_geo), func=square_to_disk, grad_func=square_to_disk_grad)
116
- disk_geo = def_field.make_deformed_geometry(relative=False)
129
+ if mesh == "hex":
130
+ positions, hex_vidx = fem_example_utils.gen_hexmesh(
131
+ bounds_lo=wp.vec3(-domain_radius, -domain_radius, -domain_radius),
132
+ bounds_hi=wp.vec3(domain_radius, domain_radius, domain_radius),
133
+ res=wp.vec3i(resolution, resolution, resolution),
134
+ )
135
+ cube_geo = fem.Hexmesh(hex_vertex_indices=hex_vidx, positions=positions)
136
+ elif mesh == "tet":
137
+ positions, tet_vidx = fem_example_utils.gen_tetmesh(
138
+ bounds_lo=wp.vec3(-domain_radius, -domain_radius, -domain_radius),
139
+ bounds_hi=wp.vec3(domain_radius, domain_radius, domain_radius),
140
+ res=wp.vec3i(resolution, resolution, resolution),
141
+ )
142
+ cube_geo = fem.Tetmesh(tet_vertex_indices=tet_vidx, positions=positions)
143
+ elif mesh == "nano":
144
+ vol = fem_example_utils.gen_volume(
145
+ bounds_lo=wp.vec3(-domain_radius, -domain_radius, -domain_radius),
146
+ bounds_hi=wp.vec3(domain_radius, domain_radius, domain_radius),
147
+ res=wp.vec3i(resolution, resolution, resolution),
148
+ )
149
+ cube_geo = fem.Nanogrid(grid=vol)
150
+ else:
151
+ cube_geo = fem.Grid3D(
152
+ bounds_lo=wp.vec3(-domain_radius, -domain_radius, -domain_radius),
153
+ bounds_hi=wp.vec3(domain_radius, domain_radius, domain_radius),
154
+ res=wp.vec3i(resolution, resolution, resolution),
155
+ )
156
+
157
+ def_field = fem.ImplicitField(
158
+ domain=fem.Cells(cube_geo), func=cube_to_cylinder, grad_func=cube_to_cylinder_grad
159
+ )
160
+ sim_geo = def_field.make_deformed_geometry(relative=False)
117
161
 
118
- coil_config = {"coil_height": 1.0, "coil_internal_radius": 0.1, "coil_external_radius": 0.3}
162
+ coil_config = {"coil_height": 0.25, "coil_internal_radius": 0.3, "coil_external_radius": 0.4}
163
+ core_config = {"core_height": 1.0, "core_radius": 0.2}
119
164
 
120
- domain = fem.Cells(disk_geo)
121
- self._permeability_field = fem.ImplicitField(domain, func=permeability_field, values=coil_config)
165
+ domain = fem.Cells(sim_geo)
166
+ self._permeability_field = fem.ImplicitField(
167
+ domain, func=permeability_field, values=dict(**coil_config, **core_config)
168
+ )
122
169
  self._current_field = fem.ImplicitField(domain, func=current_field, values=dict(current=current, **coil_config))
123
170
 
124
- z_space = fem.make_polynomial_space(disk_geo, degree=degree, element_basis=fem.ElementBasis.LAGRANGE)
125
- xy_space = fem.make_polynomial_space(
126
- disk_geo, degree=degree, element_basis=fem.ElementBasis.LAGRANGE, dtype=wp.vec2
171
+ A_space = fem.make_polynomial_space(
172
+ sim_geo, degree=1, element_basis=fem.ElementBasis.NEDELEC_FIRST_KIND, dtype=wp.vec3
127
173
  )
174
+ self.A_field = A_space.make_field()
128
175
 
129
- self.A_field = z_space.make_field()
130
- self.B_field = xy_space.make_field()
176
+ B_space = fem.make_polynomial_space(sim_geo, degree=1, element_basis=fem.ElementBasis.LAGRANGE, dtype=wp.vec3)
177
+ self.B_field = B_space.make_field()
131
178
 
132
179
  self.renderer = fem_example_utils.Plot()
133
180
 
134
181
  def step(self):
135
- z_space = self.A_field.space
136
- disk_geo = z_space.geometry
182
+ A_space = self.A_field.space
183
+ sim_geo = A_space.geometry
137
184
 
138
- u = fem.make_trial(space=z_space)
139
- v = fem.make_test(space=z_space)
140
- lhs = fem.integrate(curl_curl_form, fields={"u": u, "v": v, "mu": self._permeability_field})
141
- rhs = fem.integrate(mass_form, fields={"v": v, "u": self._current_field})
185
+ u = fem.make_trial(space=A_space)
186
+ v = fem.make_test(space=A_space)
187
+ lhs = fem.integrate(curl_curl_form, fields={"u": u, "v": v, "mu": self._permeability_field}, output_dtype=float)
188
+ rhs = fem.integrate(mass_form, fields={"v": v, "u": self._current_field}, output_dtype=float)
142
189
 
143
190
  # Dirichlet BC
144
- boundary = fem.BoundarySides(disk_geo)
145
- u_bd = fem.make_trial(space=z_space, domain=boundary)
146
- v_bd = fem.make_test(space=z_space, domain=boundary)
147
- dirichlet_bd_proj = fem.integrate(mass_form, fields={"u": u_bd, "v": v_bd}, nodal=True)
191
+ boundary = fem.BoundarySides(sim_geo)
192
+ u_bd = fem.make_trial(space=A_space, domain=boundary)
193
+ v_bd = fem.make_test(space=A_space, domain=boundary)
194
+ dirichlet_bd_proj = fem.integrate(mass_form, fields={"u": u_bd, "v": v_bd}, nodal=True, output_dtype=float)
148
195
  fem.project_linear_system(lhs, rhs, dirichlet_bd_proj)
149
196
 
150
- x = wp.zeros_like(rhs)
151
- fem_example_utils.bsr_cg(lhs, b=rhs, x=x, tol=1.0e-8, quiet=False)
152
-
153
- # make sure result is exactly zero outside of circle
154
- wp.sparse.bsr_mv(dirichlet_bd_proj, x=x, y=x, alpha=-1.0, beta=1.0)
155
- wp.utils.array_cast(in_array=x, out_array=self.A_field.dof_values)
197
+ # solve using Conjugate Residual (numerically rhs may not be in image of lhs)
198
+ fem_example_utils.bsr_cg(lhs, b=rhs, x=self.A_field.dof_values, method="cr", max_iters=250, quiet=False)
156
199
 
157
200
  # compute B as curl(A)
158
- fem.interpolate(curl_z, dest=self.B_field, fields={"u": self.A_field})
201
+ fem.interpolate(curl_expr, dest=self.B_field, fields={"u": self.A_field})
159
202
 
160
203
  def render(self):
161
- self.renderer.add_field("A", self.A_field)
162
204
  self.renderer.add_field("B", self.B_field)
163
205
 
164
206
 
@@ -170,7 +212,7 @@ if __name__ == "__main__":
170
212
  parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter)
171
213
  parser.add_argument("--device", type=str, default=None, help="Override the default Warp device.")
172
214
  parser.add_argument("--resolution", type=int, default=32, help="Grid resolution.")
173
- parser.add_argument("--degree", type=int, default=2, help="Polynomial degree of shape functions.")
215
+ parser.add_argument("--mesh", type=str, default="grid", choices=["tet", "hex", "grid", "nano"], help="Mesh type.")
174
216
  parser.add_argument("--radius", type=float, default=2.0, help="Radius of simulation domain.")
175
217
  parser.add_argument(
176
218
  "--headless",
@@ -182,9 +224,9 @@ if __name__ == "__main__":
182
224
  args = parser.parse_known_args()[0]
183
225
 
184
226
  with wp.ScopedDevice(args.device):
185
- example = Example(quiet=args.quiet, degree=args.degree, resolution=args.resolution, domain_radius=args.radius)
227
+ example = Example(quiet=args.quiet, mesh=args.mesh, resolution=args.resolution, domain_radius=args.radius)
186
228
  example.step()
187
229
  example.render()
188
230
 
189
231
  if not args.headless:
190
- example.renderer.plot({"A": {"contours": {"levels": 30}}, "B": {"streamlines": {"density": 1.0}}})
232
+ example.renderer.plot({"B": {"streamlines": {"density": 1.0}}})
@@ -210,11 +210,11 @@ class Example:
210
210
 
211
211
  # Add boundary stress from other solid field
212
212
  other_stress_field = fem.field.field.NonconformingField(boundary, other_stress_field)
213
- fem.utils.array_axpy(
214
- y=u_rhs,
215
- x=fem.integrate(
216
- boundary_stress_form, fields={"u": u_bd_test, "tau": other_stress_field}, output_dtype=wp.vec2d
217
- ),
213
+ fem.integrate(
214
+ boundary_stress_form,
215
+ fields={"u": u_bd_test, "tau": other_stress_field},
216
+ output=u_rhs,
217
+ add=True,
218
218
  )
219
219
 
220
220
  # Enforce boundary conditions
@@ -200,4 +200,6 @@ if __name__ == "__main__":
200
200
  example.render()
201
201
 
202
202
  if not args.headless:
203
- example.renderer.plot(options={"velocity": {"streamlines": {}}, "pressure": {"contours": {}}})
203
+ example.renderer.plot(
204
+ options={"velocity": {"streamlines": {}}, "pressure": {"contours": {}}}, backend="matplotlib"
205
+ )
@@ -82,7 +82,7 @@ def mass_form(
82
82
  u: fem.Field,
83
83
  v: fem.Field,
84
84
  ):
85
- return u(s) * v(s)
85
+ return wp.dot(u(s), v(s))
86
86
 
87
87
 
88
88
  @fem.integrand
@@ -199,7 +199,7 @@ class Example:
199
199
  domain=self._inflow, order=self._degree, family=fem.Polynomial.GAUSS_LEGENDRE
200
200
  )
201
201
  n_streamlines = streamline_spawn.total_point_count()
202
- spawn_points = wp.array(dtype=wp.vec3, shape=n_streamlines)
202
+ spawn_points = wp.empty(dtype=wp.vec3, shape=n_streamlines)
203
203
 
204
204
  jitter_amount = self._streamline_dx / self._degree
205
205
  fem.interpolate(
@@ -212,8 +212,8 @@ class Example:
212
212
  # to populate the per-point data
213
213
 
214
214
  point_count = self._streamline_point_count
215
- points = wp.array(dtype=wp.vec3, shape=(n_streamlines, point_count))
216
- speed = wp.array(dtype=float, shape=(n_streamlines, point_count))
215
+ points = wp.empty(dtype=wp.vec3, shape=(n_streamlines, point_count))
216
+ speed = wp.empty(dtype=float, shape=(n_streamlines, point_count))
217
217
 
218
218
  fem.interpolate(
219
219
  gen_streamlines,
@@ -235,7 +235,7 @@ class Example:
235
235
  def render(self):
236
236
  # self.renderer.add_field("solution", self.pressure_field)
237
237
  self.plot.add_field("pressure", self.pressure_field)
238
- self.plot.add_field("velocity", self.velocity_field)
238
+ # self.plot.add_field("velocity", self.velocity_field)
239
239
 
240
240
  if self.renderer is not None:
241
241
  streamline_count = self._points.shape[0]
@@ -259,10 +259,11 @@ class Example:
259
259
  self.renderer.end_frame()
260
260
 
261
261
  def _generate_incompressible_flow(self):
262
- # Function spaces for velocity, scalars and pressure (Pk / Pk / Pk-1)
263
- u_space = fem.make_polynomial_space(geo=self._geo, degree=self._degree, dtype=wp.vec3)
264
- s_space = fem.make_polynomial_space(geo=self._geo, degree=self._degree, dtype=float)
265
- p_space = fem.make_polynomial_space(geo=self._geo, degree=self._degree - 1, dtype=float)
262
+ # Function spaces for velocity and pressure (RT1 / P0)
263
+ u_space = fem.make_polynomial_space(
264
+ geo=self._geo, element_basis=fem.ElementBasis.RAVIART_THOMAS, degree=1, dtype=wp.vec3
265
+ )
266
+ p_space = fem.make_polynomial_space(geo=self._geo, degree=0, dtype=float)
266
267
 
267
268
  self.pressure_field = p_space.make_field()
268
269
  self.velocity_field = u_space.make_field()
@@ -288,8 +289,8 @@ class Example:
288
289
  fem.interpolate(inflow_velocity, dest=fem.make_restriction(self.velocity_field, domain=self._inflow))
289
290
 
290
291
  # (Diagonal) mass matrix
291
- rho_test = fem.make_test(s_space)
292
- rho_trial = fem.make_trial(s_space)
292
+ rho_test = fem.make_test(u_space)
293
+ rho_trial = fem.make_trial(u_space)
293
294
  inv_mass_matrix = fem.integrate(
294
295
  mass_form, fields={"u": rho_trial, "v": rho_test}, nodal=True, output_dtype=float
295
296
  )
@@ -341,11 +342,3 @@ if __name__ == "__main__":
341
342
 
342
343
  example.step()
343
344
  example.render()
344
-
345
- if not args.headless:
346
- example.plot.plot(
347
- {
348
- "velocity": {"streamlines": {"density": 2}},
349
- "pressure": {"contours": {}},
350
- }
351
- )
@@ -31,7 +31,7 @@ def gen_trimesh(res, bounds_lo: Optional[wp.vec2] = None, bounds_hi: Optional[wp
31
31
  Args:
32
32
  res: Resolution of the grid along each dimension
33
33
  bounds_lo: Position of the lower bound of the axis-aligned grid
34
- bounds_up: Position of the upper bound of the axis-aligned grid
34
+ bounds_hi: Position of the upper bound of the axis-aligned grid
35
35
 
36
36
  Returns:
37
37
  Tuple of ndarrays: (Vertex positions, Triangle vertex indices)
@@ -62,7 +62,7 @@ def gen_tetmesh(res, bounds_lo: Optional[wp.vec3] = None, bounds_hi: Optional[wp
62
62
  Args:
63
63
  res: Resolution of the grid along each dimension
64
64
  bounds_lo: Position of the lower bound of the axis-aligned grid
65
- bounds_up: Position of the upper bound of the axis-aligned grid
65
+ bounds_hi: Position of the upper bound of the axis-aligned grid
66
66
 
67
67
  Returns:
68
68
  Tuple of ndarrays: (Vertex positions, Tetrahedron vertex indices)
@@ -95,7 +95,7 @@ def gen_quadmesh(res, bounds_lo: Optional[wp.vec2] = None, bounds_hi: Optional[w
95
95
  Args:
96
96
  res: Resolution of the grid along each dimension
97
97
  bounds_lo: Position of the lower bound of the axis-aligned grid
98
- bounds_up: Position of the upper bound of the axis-aligned grid
98
+ bounds_hi: Position of the upper bound of the axis-aligned grid
99
99
 
100
100
  Returns:
101
101
  Tuple of ndarrays: (Vertex positions, Triangle vertex indices)
@@ -125,7 +125,7 @@ def gen_hexmesh(res, bounds_lo: Optional[wp.vec3] = None, bounds_hi: Optional[wp
125
125
  Args:
126
126
  res: Resolution of the grid along each dimension
127
127
  bounds_lo: Position of the lower bound of the axis-aligned grid
128
- bounds_up: Position of the upper bound of the axis-aligned grid
128
+ bounds_hi: Position of the upper bound of the axis-aligned grid
129
129
 
130
130
  Returns:
131
131
  Tuple of ndarrays: (Vertex positions, Triangle vertex indices)
@@ -158,7 +158,7 @@ def gen_volume(res, bounds_lo: Optional[wp.vec3] = None, bounds_hi: Optional[wp.
158
158
  Args:
159
159
  res: Resolution of the grid along each dimension
160
160
  bounds_lo: Position of the lower bound of the axis-aligned grid
161
- bounds_up: Position of the upper bound of the axis-aligned grid
161
+ bounds_hi: Position of the upper bound of the axis-aligned grid
162
162
  device: Cuda device on which to allocate the grid
163
163
  """
164
164
 
@@ -575,6 +575,7 @@ class Plot:
575
575
 
576
576
  def _plot_pyvista(self, options: Dict[str, Any]):
577
577
  import pyvista
578
+ import pyvista.themes
578
579
 
579
580
  grids = {}
580
581
  scales = {}
@@ -702,7 +703,7 @@ class Plot:
702
703
  subplot_rows = options.get("rows", 1)
703
704
  subplot_shape = (subplot_rows, (len(grids) + subplot_rows - 1) // subplot_rows)
704
705
 
705
- plotter = pyvista.Plotter(shape=subplot_shape)
706
+ plotter = pyvista.Plotter(shape=subplot_shape, theme=pyvista.themes.DocumentProTheme())
706
707
  plotter.link_views()
707
708
  plotter.add_camera_orientation_widget()
708
709
  for index, (name, grid) in enumerate(grids.items()):
@@ -717,7 +718,7 @@ class Plot:
717
718
  plotter.view_xy()
718
719
  else:
719
720
  plotter.add_mesh(marker)
720
- elif field.space.dimension == 3:
721
+ elif field.space.geometry.cell_dimension == 3:
721
722
  plotter.add_mesh_clip_plane(grid, show_edges=True, clim=value_range, assign_to_axis="z")
722
723
  else:
723
724
  plotter.add_mesh(grid, show_edges=True, clim=value_range)
@@ -809,6 +810,8 @@ class Plot:
809
810
  if "arrows" in args or "streamlines" in args:
810
811
  plot_opts["glyph_scale"] = args.get("arrows", {}).get("glyph_scale", 1.0)
811
812
  plot_fn = _plot_quivers_3d
813
+ elif field.space.geometry.cell_dimension == 2:
814
+ plot_fn = _plot_surface
812
815
  else:
813
816
  plot_fn = _plot_3d_scatter
814
817
  plot_3d = True
@@ -856,23 +859,43 @@ def _field_triangulation(field):
856
859
 
857
860
 
858
861
  def _plot_surface(field, axes, **kwargs):
859
- Z = _value_or_magnitude(field.dof_values.numpy())
862
+ from matplotlib.cm import get_cmap
863
+ from matplotlib.colors import Normalize
860
864
 
861
- if "clim" in kwargs:
862
- axes.set_zlim(*kwargs["clim"])
865
+ C = _value_or_magnitude(field.dof_values.numpy())
866
+
867
+ positions = field.space.node_positions().numpy().T
868
+ if field.space.dimension == 3:
869
+ X, Y, Z = positions
870
+ else:
871
+ X, Y = positions
872
+ Z = C
873
+ axes.set_zlim(kwargs["clim"])
863
874
 
864
875
  if hasattr(field.space, "node_grid"):
865
876
  X, Y = field.space.node_grid()
866
- Z = Z.reshape(X.shape)
867
- return axes.plot_surface(X, Y, Z, linewidth=0.1, antialiased=False, **kwargs)
877
+ C = C.reshape(X.shape)
878
+ return axes.plot_surface(X, Y, C, linewidth=0.1, antialiased=False, **kwargs)
868
879
 
869
880
  if hasattr(field.space, "node_triangulation"):
870
881
  triangulation = _field_triangulation(field)
871
- return axes.plot_trisurf(triangulation, Z, linewidth=0.1, antialiased=False, **kwargs)
882
+
883
+ if field.space.dimension == 3:
884
+ plot = axes.plot_trisurf(triangulation, Z, linewidth=0.1, antialiased=False)
885
+ # change colors -- recompute color map manually
886
+ vmin, vmax = kwargs["clim"]
887
+ norm = Normalize(vmin=vmin, vmax=vmax)
888
+ values = np.mean(C[triangulation.triangles], axis=1)
889
+ colors = get_cmap(kwargs["cmap"])(norm(values))
890
+ plot.set_norm(norm)
891
+ plot.set_fc(colors)
892
+ else:
893
+ plot = axes.plot_trisurf(triangulation, C, linewidth=0.1, antialiased=False, **kwargs)
894
+
895
+ return plot
872
896
 
873
897
  # scatter
874
- X, Y = field.space.node_positions().numpy().T
875
- return axes.scatter(X, Y, Z, c=Z, **kwargs)
898
+ return axes.scatter(X, Y, Z, c=C, **kwargs)
876
899
 
877
900
 
878
901
  def _plot_displaced_tri_mesh(field, axes, **kwargs):
@@ -21,7 +21,7 @@ import math
21
21
  import os
22
22
 
23
23
  import numpy as np
24
- from pxr import Usd, UsdGeom
24
+ from pxr import Gf, Usd, UsdGeom
25
25
 
26
26
  import warp as wp
27
27
  import warp.examples
@@ -93,7 +93,7 @@ class Example:
93
93
  geom = UsdGeom.Mesh(asset_stage.GetPrimAtPath("/root/bear"))
94
94
  points = geom.GetPointsAttr().Get()
95
95
 
96
- xform = geom.ComputeLocalToWorldTransform(0.0)
96
+ xform = Gf.Matrix4f(geom.ComputeLocalToWorldTransform(0.0))
97
97
  for i in range(len(points)):
98
98
  points[i] = xform.Transform(points[i])
99
99
 
@@ -26,29 +26,6 @@ import warp.sim
26
26
  import warp.sim.render
27
27
 
28
28
 
29
- def color_lattice_grid(num_x, num_y):
30
- colors = []
31
- for _i in range(4):
32
- colors.append([])
33
-
34
- for xi in range(num_x + 1):
35
- for yi in range(num_y + 1):
36
- vId = xi * (num_y + 1) + yi
37
-
38
- a = 1 if xi % 2 else 0
39
- b = 1 if yi % 2 else 0
40
-
41
- c = a * 2 + b
42
-
43
- colors[c].append(vId)
44
-
45
- colors_wp = []
46
- for i_color in range(len(colors)):
47
- colors_wp.append(wp.array(colors[i_color], dtype=wp.int32))
48
-
49
- return colors_wp
50
-
51
-
52
29
  class IntegratorType(Enum):
53
30
  EULER = "euler"
54
31
  XPBD = "xpbd"
@@ -122,6 +99,8 @@ class Example:
122
99
  tri_ke=1e4,
123
100
  tri_ka=1e4,
124
101
  tri_kd=1e-5,
102
+ edge_ke=100,
103
+ color_particles=True,
125
104
  )
126
105
 
127
106
  usd_stage = Usd.Stage.Open(os.path.join(warp.examples.get_asset_directory(), "bunny.usd"))
@@ -154,8 +133,6 @@ class Example:
154
133
  self.integrator = wp.sim.XPBDIntegrator(iterations=1)
155
134
  else:
156
135
  self.integrator = wp.sim.VBDIntegrator(self.model, iterations=1)
157
- # we need to give VBD coloring information
158
- self.model.particle_coloring = color_lattice_grid(width, height)
159
136
 
160
137
  self.state_0 = self.model.state()
161
138
  self.state_1 = self.model.state()
@@ -41,6 +41,8 @@ def compute_endeffector_position(
41
41
 
42
42
  class Example:
43
43
  def __init__(self, stage_path="example_jacobian_ik.usd", num_envs=10):
44
+ rng = np.random.default_rng(42)
45
+
44
46
  builder = wp.sim.ModelBuilder()
45
47
 
46
48
  self.num_envs = num_envs
@@ -81,7 +83,7 @@ class Example:
81
83
  )
82
84
  self.target_origin.append((i * 2.0, 4.0, 0.0))
83
85
  # joint initial positions
84
- builder.joint_q[-3:] = np.random.uniform(-0.5, 0.5, size=3)
86
+ builder.joint_q[-3:] = rng.uniform(-0.5, 0.5, size=3)
85
87
  self.target_origin = np.array(self.target_origin)
86
88
 
87
89
  # finalize model
@@ -207,6 +209,8 @@ if __name__ == "__main__":
207
209
 
208
210
  args = parser.parse_known_args()[0]
209
211
 
212
+ rng = np.random.default_rng(42)
213
+
210
214
  with wp.ScopedDevice(args.device):
211
215
  example = Example(stage_path=args.stage_path, num_envs=args.num_envs)
212
216
 
@@ -218,7 +222,7 @@ if __name__ == "__main__":
218
222
  for _ in range(args.num_rollouts):
219
223
  # select new random target points for all envs
220
224
  example.targets = example.target_origin.copy()
221
- example.targets[:, 1:] += np.random.uniform(-0.5, 0.5, size=(example.num_envs, 2))
225
+ example.targets[:, 1:] += rng.uniform(-0.5, 0.5, size=(example.num_envs, 2))
222
226
 
223
227
  for iter in range(args.train_iters):
224
228
  example.step()
@@ -115,10 +115,11 @@ class Example:
115
115
 
116
116
  self.model.joint_attach_ke = 16000.0
117
117
  self.model.joint_attach_kd = 200.0
118
+ self.use_tile_gemm = False
118
119
 
119
120
  # self.integrator = wp.sim.XPBDIntegrator()
120
121
  # self.integrator = wp.sim.SemiImplicitIntegrator()
121
- self.integrator = wp.sim.FeatherstoneIntegrator(self.model)
122
+ self.integrator = wp.sim.FeatherstoneIntegrator(self.model, use_tile_gemm=self.use_tile_gemm)
122
123
 
123
124
  if stage_path:
124
125
  self.renderer = wp.sim.render.SimRenderer(self.model, stage_path)