warp-lang 1.7.0__py3-none-win_amd64.whl → 1.7.1__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 (46) hide show
  1. warp/autograd.py +12 -2
  2. warp/bin/warp-clang.dll +0 -0
  3. warp/bin/warp.dll +0 -0
  4. warp/build.py +1 -1
  5. warp/builtins.py +11 -10
  6. warp/codegen.py +17 -5
  7. warp/config.py +1 -1
  8. warp/context.py +6 -0
  9. warp/examples/benchmarks/benchmark_cloth.py +1 -1
  10. warp/examples/distributed/example_jacobi_mpi.py +507 -0
  11. warp/fem/field/field.py +11 -1
  12. warp/fem/field/nodal_field.py +36 -22
  13. warp/fem/geometry/adaptive_nanogrid.py +7 -3
  14. warp/fem/geometry/trimesh.py +4 -12
  15. warp/jax_experimental/custom_call.py +14 -2
  16. warp/jax_experimental/ffi.py +5 -1
  17. warp/native/tile.h +11 -11
  18. warp/native/warp.cu +1 -1
  19. warp/render/render_opengl.py +19 -17
  20. warp/render/render_usd.py +93 -3
  21. warp/sim/collide.py +11 -9
  22. warp/sim/inertia.py +189 -156
  23. warp/sim/integrator_euler.py +3 -0
  24. warp/sim/integrator_xpbd.py +3 -0
  25. warp/sim/model.py +29 -12
  26. warp/sim/render.py +4 -0
  27. warp/stubs.py +1 -1
  28. warp/tests/assets/torus.usda +1 -1
  29. warp/tests/sim/test_collision.py +237 -206
  30. warp/tests/sim/test_inertia.py +161 -0
  31. warp/tests/sim/{flaky_test_sim_grad.py → test_sim_grad.py} +4 -0
  32. warp/tests/sim/test_xpbd.py +399 -0
  33. warp/tests/test_codegen.py +24 -3
  34. warp/tests/test_examples.py +16 -6
  35. warp/tests/test_fem.py +75 -10
  36. warp/tests/test_mat.py +370 -103
  37. warp/tests/test_quat.py +321 -137
  38. warp/tests/test_vec.py +320 -174
  39. warp/tests/tile/test_tile_load.py +97 -0
  40. warp/tests/unittest_suites.py +2 -5
  41. warp/types.py +65 -8
  42. {warp_lang-1.7.0.dist-info → warp_lang-1.7.1.dist-info}/METADATA +21 -9
  43. {warp_lang-1.7.0.dist-info → warp_lang-1.7.1.dist-info}/RECORD +46 -43
  44. {warp_lang-1.7.0.dist-info → warp_lang-1.7.1.dist-info}/WHEEL +1 -1
  45. {warp_lang-1.7.0.dist-info → warp_lang-1.7.1.dist-info}/licenses/LICENSE.md +0 -26
  46. {warp_lang-1.7.0.dist-info → warp_lang-1.7.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,399 @@
1
+ # SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2
+ # SPDX-License-Identifier: Apache-2.0
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ from warp.sim.model import PARTICLE_FLAG_ACTIVE
17
+ from warp.tests.unittest_utils import *
18
+
19
+ # fmt: off
20
+ CLOTH_POINTS = [
21
+ (-50.0000000, 0.0000000, -50.0000000),
22
+ (-38.8888893, 11.1111107, -50.0000000),
23
+ (-27.7777786, 22.2222214, -50.0000000),
24
+ (-16.6666679, 33.3333321, -50.0000000),
25
+ (-5.5555558, 44.4444427, -50.0000000),
26
+ (5.5555558, 55.5555573, -50.0000000),
27
+ (16.6666679, 66.6666641, -50.0000000),
28
+ (27.7777786, 77.7777786, -50.0000000),
29
+ (38.8888893, 88.8888855, -50.0000000),
30
+ (50.0000000, 100.0000000, -50.0000000),
31
+ (-50.0000000, 0.0000000, -38.8888893),
32
+ (-38.8888893, 11.1111107, -38.8888893),
33
+ (-27.7777786, 22.2222214, -38.8888893),
34
+ (-16.6666679, 33.3333321, -38.8888893),
35
+ (-5.5555558, 44.4444427, -38.8888893),
36
+ (5.5555558, 55.5555573, -38.8888893),
37
+ (16.6666679, 66.6666641, -38.8888893),
38
+ (27.7777786, 77.7777786, -38.8888893),
39
+ (38.8888893, 88.8888855, -38.8888893),
40
+ (50.0000000, 100.0000000, -38.8888893),
41
+ (-50.0000000, 0.0000000, -27.7777786),
42
+ (-38.8888893, 11.1111107, -27.7777786),
43
+ (-27.7777786, 22.2222214, -27.7777786),
44
+ (-16.6666679, 33.3333321, -27.7777786),
45
+ (-5.5555558, 44.4444427, -27.7777786),
46
+ (5.5555558, 55.5555573, -27.7777786),
47
+ (16.6666679, 66.6666641, -27.7777786),
48
+ (27.7777786, 77.7777786, -27.7777786),
49
+ (38.8888893, 88.8888855, -27.7777786),
50
+ (50.0000000, 100.0000000, -27.7777786),
51
+ (-50.0000000, 0.0000000, -16.6666679),
52
+ (-38.8888893, 11.1111107, -16.6666679),
53
+ (-27.7777786, 22.2222214, -16.6666679),
54
+ (-16.6666679, 33.3333321, -16.6666679),
55
+ (-5.5555558, 44.4444427, -16.6666679),
56
+ (5.5555558, 55.5555573, -16.6666679),
57
+ (16.6666679, 66.6666641, -16.6666679),
58
+ (27.7777786, 77.7777786, -16.6666679),
59
+ (38.8888893, 88.8888855, -16.6666679),
60
+ (50.0000000, 100.0000000, -16.6666679),
61
+ (-50.0000000, 0.0000000, -5.5555558),
62
+ (-38.8888893, 11.1111107, -5.5555558),
63
+ (-27.7777786, 22.2222214, -5.5555558),
64
+ (-16.6666679, 33.3333321, -5.5555558),
65
+ (-5.5555558, 44.4444427, -5.5555558),
66
+ (5.5555558, 55.5555573, -5.5555558),
67
+ (16.6666679, 66.6666641, -5.5555558),
68
+ (27.7777786, 77.7777786, -5.5555558),
69
+ (38.8888893, 88.8888855, -5.5555558),
70
+ (50.0000000, 100.0000000, -5.5555558),
71
+ (-50.0000000, 0.0000000, 5.5555558),
72
+ (-38.8888893, 11.1111107, 5.5555558),
73
+ (-27.7777786, 22.2222214, 5.5555558),
74
+ (-16.6666679, 33.3333321, 5.5555558),
75
+ (-5.5555558, 44.4444427, 5.5555558),
76
+ (5.5555558, 55.5555573, 5.5555558),
77
+ (16.6666679, 66.6666641, 5.5555558),
78
+ (27.7777786, 77.7777786, 5.5555558),
79
+ (38.8888893, 88.8888855, 5.5555558),
80
+ (50.0000000, 100.0000000, 5.5555558),
81
+ (-50.0000000, 0.0000000, 16.6666679),
82
+ (-38.8888893, 11.1111107, 16.6666679),
83
+ (-27.7777786, 22.2222214, 16.6666679),
84
+ (-16.6666679, 33.3333321, 16.6666679),
85
+ (-5.5555558, 44.4444427, 16.6666679),
86
+ (5.5555558, 55.5555573, 16.6666679),
87
+ (16.6666679, 66.6666641, 16.6666679),
88
+ (27.7777786, 77.7777786, 16.6666679),
89
+ (38.8888893, 88.8888855, 16.6666679),
90
+ (50.0000000, 100.0000000, 16.6666679),
91
+ (-50.0000000, 0.0000000, 27.7777786),
92
+ (-38.8888893, 11.1111107, 27.7777786),
93
+ (-27.7777786, 22.2222214, 27.7777786),
94
+ (-16.6666679, 33.3333321, 27.7777786),
95
+ (-5.5555558, 44.4444427, 27.7777786),
96
+ (5.5555558, 55.5555573, 27.7777786),
97
+ (16.6666679, 66.6666641, 27.7777786),
98
+ (27.7777786, 77.7777786, 27.7777786),
99
+ (38.8888893, 88.8888855, 27.7777786),
100
+ (50.0000000, 100.0000000, 27.7777786),
101
+ (-50.0000000, 0.0000000, 38.8888893),
102
+ (-38.8888893, 11.1111107, 38.8888893),
103
+ (-27.7777786, 22.2222214, 38.8888893),
104
+ (-16.6666679, 33.3333321, 38.8888893),
105
+ (-5.5555558, 44.4444427, 38.8888893),
106
+ (5.5555558, 55.5555573, 38.8888893),
107
+ (16.6666679, 66.6666641, 38.8888893),
108
+ (27.7777786, 77.7777786, 38.8888893),
109
+ (38.8888893, 88.8888855, 38.8888893),
110
+ (50.0000000, 100.0000000, 38.8888893),
111
+ (-50.0000000, 0.0000000, 50.0000000),
112
+ (-38.8888893, 11.1111107, 50.0000000),
113
+ (-27.7777786, 22.2222214, 50.0000000),
114
+ (-16.6666679, 33.3333321, 50.0000000),
115
+ (-5.5555558, 44.4444427, 50.0000000),
116
+ (5.5555558, 55.5555573, 50.0000000),
117
+ (16.6666679, 66.6666641, 50.0000000),
118
+ (27.7777786, 77.7777786, 50.0000000),
119
+ (38.8888893, 88.8888855, 50.0000000),
120
+ (50.0000000, 100.0000000, 50.0000000),
121
+ ]
122
+
123
+ CLOTH_FACES = [
124
+ 1, 12, 2,
125
+ 1, 11, 12,
126
+ 2, 12, 3,
127
+ 12, 13, 3,
128
+ 3, 14, 4,
129
+ 3, 13, 14,
130
+ 4, 14, 5,
131
+ 14, 15, 5,
132
+ 5, 16, 6,
133
+ 5, 15, 16,
134
+ 6, 16, 7,
135
+ 16, 17, 7,
136
+ 7, 18, 8,
137
+ 7, 17, 18,
138
+ 8, 18, 9,
139
+ 18, 19, 9,
140
+ 9, 20, 10,
141
+ 9, 19, 20,
142
+ 11, 21, 12,
143
+ 21, 22, 12,
144
+ 12, 23, 13,
145
+ 12, 22, 23,
146
+ 13, 23, 14,
147
+ 23, 24, 14,
148
+ 14, 25, 15,
149
+ 14, 24, 25,
150
+ 15, 25, 16,
151
+ 25, 26, 16,
152
+ 16, 27, 17,
153
+ 16, 26, 27,
154
+ 17, 27, 18,
155
+ 27, 28, 18,
156
+ 18, 29, 19,
157
+ 18, 28, 29,
158
+ 19, 29, 20,
159
+ 29, 30, 20,
160
+ 21, 32, 22,
161
+ 21, 31, 32,
162
+ 22, 32, 23,
163
+ 32, 33, 23,
164
+ 23, 34, 24,
165
+ 23, 33, 34,
166
+ 24, 34, 25,
167
+ 34, 35, 25,
168
+ 25, 36, 26,
169
+ 25, 35, 36,
170
+ 26, 36, 27,
171
+ 36, 37, 27,
172
+ 27, 38, 28,
173
+ 27, 37, 38,
174
+ 28, 38, 29,
175
+ 38, 39, 29,
176
+ 29, 40, 30,
177
+ 29, 39, 40,
178
+ 31, 41, 32,
179
+ 41, 42, 32,
180
+ 32, 43, 33,
181
+ 32, 42, 43,
182
+ 33, 43, 34,
183
+ 43, 44, 34,
184
+ 34, 45, 35,
185
+ 34, 44, 45,
186
+ 35, 45, 36,
187
+ 45, 46, 36,
188
+ 36, 47, 37,
189
+ 36, 46, 47,
190
+ 37, 47, 38,
191
+ 47, 48, 38,
192
+ 38, 49, 39,
193
+ 38, 48, 49,
194
+ 39, 49, 40,
195
+ 49, 50, 40,
196
+ 41, 52, 42,
197
+ 41, 51, 52,
198
+ 42, 52, 43,
199
+ 52, 53, 43,
200
+ 43, 54, 44,
201
+ 43, 53, 54,
202
+ 44, 54, 45,
203
+ 54, 55, 45,
204
+ 45, 56, 46,
205
+ 45, 55, 56,
206
+ 46, 56, 47,
207
+ 56, 57, 47,
208
+ 47, 58, 48,
209
+ 47, 57, 58,
210
+ 48, 58, 49,
211
+ 58, 59, 49,
212
+ 49, 60, 50,
213
+ 49, 59, 60,
214
+ 51, 61, 52,
215
+ 61, 62, 52,
216
+ 52, 63, 53,
217
+ 52, 62, 63,
218
+ 53, 63, 54,
219
+ 63, 64, 54,
220
+ 54, 65, 55,
221
+ 54, 64, 65,
222
+ 55, 65, 56,
223
+ 65, 66, 56,
224
+ 56, 67, 57,
225
+ 56, 66, 67,
226
+ 57, 67, 58,
227
+ 67, 68, 58,
228
+ 58, 69, 59,
229
+ 58, 68, 69,
230
+ 59, 69, 60,
231
+ 69, 70, 60,
232
+ 61, 72, 62,
233
+ 61, 71, 72,
234
+ 62, 72, 63,
235
+ 72, 73, 63,
236
+ 63, 74, 64,
237
+ 63, 73, 74,
238
+ 64, 74, 65,
239
+ 74, 75, 65,
240
+ 65, 76, 66,
241
+ 65, 75, 76,
242
+ 66, 76, 67,
243
+ 76, 77, 67,
244
+ 67, 78, 68,
245
+ 67, 77, 78,
246
+ 68, 78, 69,
247
+ 78, 79, 69,
248
+ 69, 80, 70,
249
+ 69, 79, 80,
250
+ 71, 81, 72,
251
+ 81, 82, 72,
252
+ 72, 83, 73,
253
+ 72, 82, 83,
254
+ 73, 83, 74,
255
+ 83, 84, 74,
256
+ 74, 85, 75,
257
+ 74, 84, 85,
258
+ 75, 85, 76,
259
+ 85, 86, 76,
260
+ 76, 87, 77,
261
+ 76, 86, 87,
262
+ 77, 87, 78,
263
+ 87, 88, 78,
264
+ 78, 89, 79,
265
+ 78, 88, 89,
266
+ 79, 89, 80,
267
+ 89, 90, 80,
268
+ 81, 92, 82,
269
+ 81, 91, 92,
270
+ 82, 92, 83,
271
+ 92, 93, 83,
272
+ 83, 94, 84,
273
+ 83, 93, 94,
274
+ 84, 94, 85,
275
+ 94, 95, 85,
276
+ 85, 96, 86,
277
+ 85, 95, 96,
278
+ 86, 96, 87,
279
+ 96, 97, 87,
280
+ 87, 98, 88,
281
+ 87, 97, 98,
282
+ 88, 98, 89,
283
+ 98, 99, 89,
284
+ 89, 100, 90,
285
+ 89, 99, 100
286
+ ]
287
+
288
+ # fmt: on
289
+ class XPBDClothSim:
290
+ def __init__(self, device, use_cuda_graph=False):
291
+ self.frame_dt = 1 / 60
292
+ self.num_test_frames = 100
293
+ self.num_substeps = 20
294
+ self.iterations = 2
295
+ self.dt = self.frame_dt / self.num_substeps
296
+ self.device = device
297
+ self.use_cuda_graph = self.device.is_cuda and use_cuda_graph
298
+ self.builder = wp.sim.ModelBuilder()
299
+
300
+ def set_free_falling_experiment(self):
301
+ self.input_scale_factor = 1.0
302
+ self.renderer_scale_factor = 0.01
303
+ vertices = [wp.vec3(v) * self.input_scale_factor for v in CLOTH_POINTS]
304
+ faces_flatten = [fv - 1 for fv in CLOTH_FACES]
305
+
306
+ self.builder.add_cloth_mesh(
307
+ vertices=vertices,
308
+ indices=faces_flatten,
309
+ scale=0.05,
310
+ density=10,
311
+ pos=wp.vec3(0.0, 4.0, 0.0),
312
+ rot=wp.quat_identity(),
313
+ vel=wp.vec3(0.0, 0.0, 0.0),
314
+ edge_ke=1.0e2,
315
+ add_springs=True,
316
+ spring_ke=1.0e3,
317
+ spring_kd=0.0,
318
+ )
319
+ self.fixed_particles = []
320
+ self.num_test_frames = 30
321
+
322
+ def finalize(self, ground=True):
323
+ self.model = self.builder.finalize(device=self.device)
324
+ self.model.ground = ground
325
+ self.model.gravity = wp.vec3(0, -10.0, 0)
326
+ self.model.soft_contact_ke = 1.0e4
327
+ self.model.soft_contact_kd = 1.0e2
328
+
329
+ self.set_points_fixed(self.model, self.fixed_particles)
330
+
331
+ self.integrator = wp.sim.XPBDIntegrator(self.iterations)
332
+ self.state0 = self.model.state()
333
+ self.state1 = self.model.state()
334
+
335
+ self.init_pos = np.array(self.state0.particle_q.numpy(), copy=True)
336
+
337
+ self.graph = None
338
+ if self.use_cuda_graph:
339
+ with wp.ScopedCapture(device=self.device, force_module_load=False) as capture:
340
+ self.simulate()
341
+ self.graph = capture.graph
342
+
343
+ def simulate(self):
344
+ for _step in range(self.num_substeps * self.num_test_frames):
345
+ self.integrator.simulate(self.model, self.state0, self.state1, self.dt, None)
346
+ (self.state0, self.state1) = (self.state1, self.state0)
347
+
348
+ def run(self):
349
+ if self.graph:
350
+ wp.capture_launch(self.graph)
351
+ else:
352
+ self.simulate()
353
+
354
+ def set_points_fixed(self, model, fixed_particles):
355
+ if len(fixed_particles):
356
+ flags = model.particle_flags.numpy()
357
+ for fixed_v_id in fixed_particles:
358
+ flags[fixed_v_id] = wp.uint32(int(flags[fixed_v_id]) & ~int(PARTICLE_FLAG_ACTIVE))
359
+
360
+ model.particle_flags = wp.array(flags, device=model.device)
361
+
362
+
363
+ def test_xpbd_free_falling(test, device):
364
+ example = XPBDClothSim(device)
365
+ example.set_free_falling_experiment()
366
+ example.finalize(ground=False)
367
+ initial_pos = example.state0.particle_q.numpy().copy()
368
+
369
+ example.run()
370
+
371
+ # examine that the simulation does not explode
372
+ final_pos = example.state0.particle_q.numpy()
373
+ test.assertTrue((final_pos < 1e5).all())
374
+ # examine that the simulation have moved
375
+ test.assertTrue((example.init_pos != final_pos).any())
376
+
377
+ gravity = np.array(example.model.gravity)
378
+ diff = final_pos - initial_pos
379
+ vertical_translation_norm = diff @ gravity[..., None] / (np.linalg.norm(gravity) ** 2)
380
+ # ensure it's free-falling
381
+ test.assertTrue((np.abs(vertical_translation_norm - 0.5 * np.linalg.norm(gravity) * (example.dt**2)) < 2e-1).all())
382
+ horizontal_move = diff - (vertical_translation_norm * gravity)
383
+ # ensure its horizontal translation is minimal
384
+ test.assertTrue((np.abs(horizontal_move) < 1e-1).all())
385
+
386
+
387
+ devices = get_test_devices(mode="basic")
388
+
389
+
390
+ class TestXPBD(unittest.TestCase):
391
+ pass
392
+
393
+
394
+ add_function_test(TestXPBD, "test_xpbd_free_falling", test_xpbd_free_falling, devices=devices)
395
+
396
+
397
+ if __name__ == "__main__":
398
+ wp.clear_kernel_cache()
399
+ unittest.main(verbosity=2)
@@ -482,7 +482,7 @@ def test_error_unmatched_arguments(test, device):
482
482
  kernel = wp.Kernel(func=kernel_2_fn)
483
483
  with test.assertRaisesRegex(
484
484
  RuntimeError,
485
- r"Input types must be exactly the same, got \[\"vector\(length=2, dtype=<class 'warp.types.float32'>\)\", \"vector\(length=2, dtype=<class 'warp.types.float16'>\)\"\]",
485
+ r"Input types must be exactly the same, got \['vec2f', 'vector\(length=2, dtype=float16\)'\]",
486
486
  ):
487
487
  wp.launch(kernel, dim=1, device=device)
488
488
 
@@ -672,6 +672,27 @@ def test_while_condition_eval():
672
672
  it.valid = False
673
673
 
674
674
 
675
+ @wp.kernel
676
+ def conditional_return_or_sum(result: wp.array(dtype=wp.int32)):
677
+ tid = wp.tid()
678
+
679
+ if tid < 256:
680
+ return
681
+
682
+ wp.atomic_add(result, 0, 1)
683
+
684
+
685
+ def test_codegen_return_in_kernel(test, device):
686
+ result = wp.zeros(1, dtype=wp.int32, device=device)
687
+
688
+ grid_size = 1024
689
+
690
+ # On CUDA devices, this becomes a grid-stride loop
691
+ wp.launch(conditional_return_or_sum, dim=grid_size, inputs=[result], block_dim=256, max_blocks=1, device=device)
692
+
693
+ test.assertEqual(result.numpy()[0], grid_size - 256)
694
+
695
+
675
696
  class TestCodeGen(unittest.TestCase):
676
697
  pass
677
698
 
@@ -803,8 +824,8 @@ add_function_test(
803
824
  add_kernel_test(TestCodeGen, name="test_call_syntax", kernel=test_call_syntax, dim=1, devices=devices)
804
825
  add_kernel_test(TestCodeGen, name="test_shadow_builtin", kernel=test_shadow_builtin, dim=1, devices=devices)
805
826
  add_kernel_test(TestCodeGen, name="test_while_condition_eval", kernel=test_while_condition_eval, dim=1, devices=devices)
806
-
827
+ add_function_test(TestCodeGen, "test_codegen_return_in_kernel", test_codegen_return_in_kernel, devices=devices)
807
828
 
808
829
  if __name__ == "__main__":
809
830
  wp.clear_kernel_cache()
810
- unittest.main(verbosity=2, failfast=True)
831
+ unittest.main(verbosity=2)
@@ -36,6 +36,7 @@ Use "test_timeout" to override the default test timeout threshold of 600 seconds
36
36
  """
37
37
 
38
38
  import os
39
+ import platform
39
40
  import subprocess
40
41
  import sys
41
42
  import unittest
@@ -239,12 +240,21 @@ add_example_test(
239
240
  devices=test_devices,
240
241
  test_options={"usd_required": True, "headless": True},
241
242
  )
242
- add_example_test(
243
- TestCoreExamples,
244
- name="core.example_raymarch",
245
- devices=test_devices,
246
- test_options={"height": 512, "width": 1024, "headless": True},
247
- )
243
+ if platform.system() == "Windows":
244
+ # Skip GPU testing because of obscure NVRTC bug with illegal memory access
245
+ add_example_test(
246
+ TestCoreExamples,
247
+ name="core.example_raymarch",
248
+ devices=[wp.get_device("cpu")],
249
+ test_options={"height": 512, "width": 1024, "headless": True},
250
+ )
251
+ else:
252
+ add_example_test(
253
+ TestCoreExamples,
254
+ name="core.example_raymarch",
255
+ devices=test_devices,
256
+ test_options={"height": 512, "width": 1024, "headless": True},
257
+ )
248
258
  add_example_test(
249
259
  TestCoreExamples,
250
260
  name="core.example_sample_mesh",
warp/tests/test_fem.py CHANGED
@@ -14,6 +14,7 @@
14
14
  # limitations under the License.
15
15
 
16
16
  import math
17
+ import platform
17
18
  import unittest
18
19
  from typing import Any
19
20
 
@@ -475,6 +476,22 @@ def _test_geo_cells(
475
476
  wp.atomic_add(cell_measures, s.element_index, fem.measure(domain, s) * s.qp_weight)
476
477
 
477
478
 
479
+ @fem.integrand(kernel_options={"enable_backward": False})
480
+ def _test_cell_lookup(
481
+ s: fem.Sample,
482
+ domain: fem.Domain,
483
+ ):
484
+ pos = domain(s)
485
+
486
+ s_guess = fem.lookup(domain, pos, s)
487
+ wp.expect_eq(s_guess.element_index, s.element_index)
488
+ wp.expect_near(domain(s_guess), pos, 0.001)
489
+
490
+ s_noguess = fem.lookup(domain, pos)
491
+ wp.expect_eq(s_noguess.element_index, s.element_index)
492
+ wp.expect_near(domain(s_noguess), pos, 0.001)
493
+
494
+
478
495
  @fem.integrand(kernel_options={"enable_backward": False, "max_unroll": 1})
479
496
  def _test_geo_sides(
480
497
  s: fem.Sample,
@@ -527,7 +544,7 @@ def _test_side_normals(
527
544
  wp.expect_near(F_cross[k], nor[k], 0.0001)
528
545
 
529
546
 
530
- def _launch_test_geometry_kernel(geo: fem.Geometry, device):
547
+ def _launch_test_geometry_kernel(geo: fem.Geometry, device, test_cell_lookup: bool = True):
531
548
  cell_measures = wp.zeros(dtype=float, device=device, shape=geo.cell_count())
532
549
  cell_quadrature = fem.RegularQuadrature(fem.Cells(geo), order=2)
533
550
 
@@ -540,6 +557,12 @@ def _launch_test_geometry_kernel(geo: fem.Geometry, device):
540
557
  quadrature=cell_quadrature,
541
558
  values={"cell_measures": cell_measures},
542
559
  )
560
+ if test_cell_lookup:
561
+ fem.interpolate(
562
+ _test_cell_lookup,
563
+ quadrature=cell_quadrature,
564
+ )
565
+
543
566
  fem.interpolate(
544
567
  _test_geo_sides,
545
568
  quadrature=side_quadrature,
@@ -577,7 +600,7 @@ def test_triangle_mesh(test, device):
577
600
  with wp.ScopedDevice(device):
578
601
  positions, tri_vidx = _gen_trimesh(N, N)
579
602
 
580
- geo = fem.Trimesh2D(tri_vertex_indices=tri_vidx, positions=positions)
603
+ geo = fem.Trimesh2D(tri_vertex_indices=tri_vidx, positions=positions, build_bvh=True)
581
604
 
582
605
  test.assertEqual(geo.cell_count(), 2 * (N) ** 2)
583
606
  test.assertEqual(geo.vertex_count(), (N + 1) ** 2)
@@ -595,7 +618,7 @@ def test_triangle_mesh(test, device):
595
618
  positions = np.hstack((positions, np.ones((positions.shape[0], 1))))
596
619
  positions = wp.array(positions, device=device, dtype=wp.vec3)
597
620
 
598
- geo = fem.Trimesh3D(tri_vertex_indices=tri_vidx, positions=positions)
621
+ geo = fem.Trimesh3D(tri_vertex_indices=tri_vidx, positions=positions, build_bvh=True)
599
622
 
600
623
  test.assertEqual(geo.cell_count(), 2 * (N) ** 2)
601
624
  test.assertEqual(geo.vertex_count(), (N + 1) ** 2)
@@ -621,7 +644,7 @@ def test_quad_mesh(test, device):
621
644
  test.assertEqual(geo.side_count(), 2 * (N + 1) * N)
622
645
  test.assertEqual(geo.boundary_side_count(), 4 * N)
623
646
 
624
- side_measures, cell_measures = _launch_test_geometry_kernel(geo, device)
647
+ side_measures, cell_measures = _launch_test_geometry_kernel(geo, device, test_cell_lookup=False)
625
648
 
626
649
  assert_np_equal(side_measures.numpy(), np.full(side_measures.shape, 1.0 / (N)), tol=1.0e-4)
627
650
  assert_np_equal(cell_measures.numpy(), np.full(cell_measures.shape, 1.0 / (N**2)), tol=1.0e-4)
@@ -639,7 +662,7 @@ def test_quad_mesh(test, device):
639
662
  test.assertEqual(geo.side_count(), 2 * (N + 1) * N)
640
663
  test.assertEqual(geo.boundary_side_count(), 4 * N)
641
664
 
642
- side_measures, cell_measures = _launch_test_geometry_kernel(geo, device)
665
+ side_measures, cell_measures = _launch_test_geometry_kernel(geo, device, test_cell_lookup=False)
643
666
 
644
667
  assert_np_equal(side_measures.numpy(), np.full(side_measures.shape, 1.0 / (N)), tol=1.0e-4)
645
668
  assert_np_equal(cell_measures.numpy(), np.full(cell_measures.shape, 1.0 / (N**2)), tol=1.0e-4)
@@ -668,7 +691,7 @@ def test_tet_mesh(test, device):
668
691
  with wp.ScopedDevice(device):
669
692
  positions, tet_vidx = _gen_tetmesh(N, N, N)
670
693
 
671
- geo = fem.Tetmesh(tet_vertex_indices=tet_vidx, positions=positions)
694
+ geo = fem.Tetmesh(tet_vertex_indices=tet_vidx, positions=positions, build_bvh=True)
672
695
 
673
696
  test.assertEqual(geo.cell_count(), 5 * (N) ** 3)
674
697
  test.assertEqual(geo.vertex_count(), (N + 1) ** 3)
@@ -696,7 +719,7 @@ def test_hex_mesh(test, device):
696
719
  test.assertEqual(geo.boundary_side_count(), 6 * N * N)
697
720
  test.assertEqual(geo.edge_count(), 3 * N * (N + 1) ** 2)
698
721
 
699
- side_measures, cell_measures = _launch_test_geometry_kernel(geo, device)
722
+ side_measures, cell_measures = _launch_test_geometry_kernel(geo, device, test_cell_lookup=False)
700
723
 
701
724
  assert_np_equal(side_measures.numpy(), np.full(side_measures.shape, 1.0 / (N**2)), tol=1.0e-4)
702
725
  assert_np_equal(cell_measures.numpy(), np.full(cell_measures.shape, 1.0 / (N**3)), tol=1.0e-4)
@@ -732,6 +755,9 @@ def _refinement_field(x: wp.vec3):
732
755
  def test_adaptive_nanogrid(test, device):
733
756
  # 3 res-1 voxels, 8 res-0 voxels
734
757
 
758
+ if platform.system() == "Windows" or (device.is_cuda and wp.context.runtime.toolkit_version[0] == 11):
759
+ test.skipTest("Skipping test due to NVRTC bug on CUDA 11 and Windows")
760
+
735
761
  res0 = wp.array(
736
762
  [
737
763
  [2, 2, 0],
@@ -756,7 +782,6 @@ def test_adaptive_nanogrid(test, device):
756
782
  dtype=int,
757
783
  device=device,
758
784
  )
759
-
760
785
  grid0 = wp.Volume.allocate_by_voxels(res0, 0.5, device=device)
761
786
  grid1 = wp.Volume.allocate_by_voxels(res1, 1.0, device=device)
762
787
  geo = fem.adaptive_nanogrid_from_hierarchy([grid0, grid1])
@@ -819,7 +844,7 @@ def test_deformed_geometry(test, device):
819
844
  test.assertEqual(geo.side_count(), 6 * (N + 1) * N**2 + (N**3) * 4)
820
845
  test.assertEqual(geo.boundary_side_count(), 12 * N * N)
821
846
 
822
- side_measures, cell_measures = _launch_test_geometry_kernel(deformed_geo, wp.get_device())
847
+ side_measures, cell_measures = _launch_test_geometry_kernel(deformed_geo, device, test_cell_lookup=False)
823
848
 
824
849
  test.assertAlmostEqual(
825
850
  np.sum(cell_measures.numpy()), scale**3, places=4, msg=f"cell_measures = {cell_measures.numpy()}"
@@ -853,6 +878,45 @@ def test_deformed_geometry(test, device):
853
878
  ],
854
879
  )
855
880
 
881
+ # Test with Trimesh3d (different space and cell dimensions)
882
+ positions, tri_vidx = _gen_trimesh(N, N)
883
+ positions = positions.numpy()
884
+ positions = np.hstack((positions, np.ones((positions.shape[0], 1))))
885
+ positions = wp.array(positions, device=device, dtype=wp.vec3)
886
+
887
+ geo = fem.Trimesh3D(tri_vertex_indices=tri_vidx, positions=positions)
888
+
889
+ vector_space = fem.make_polynomial_space(geo, dtype=wp.vec3, degree=1)
890
+ pos_field = vector_space.make_field()
891
+ fem.interpolate(
892
+ _rigid_deformation_field,
893
+ dest=pos_field,
894
+ values={"translation": translation, "rotation": rotation, "scale": scale},
895
+ )
896
+
897
+ deformed_geo = pos_field.make_deformed_geometry()
898
+
899
+ @wp.kernel
900
+ def _test_deformed_geometry_normal(geo_arg: geo.CellArg, def_arg: deformed_geo.CellArg, rotation: wp.vec3):
901
+ i = wp.tid()
902
+
903
+ s = make_free_sample(i, Coords(0.5, 0.5, 0.0))
904
+ geo_n = geo.cell_normal(geo_arg, s)
905
+ def_n = deformed_geo.cell_normal(def_arg, s)
906
+
907
+ q = wp.quat_from_axis_angle(wp.normalize(rotation), wp.length(rotation))
908
+ wp.expect_near(wp.quat_rotate(q, geo_n), def_n, 0.001)
909
+
910
+ wp.launch(
911
+ _test_deformed_geometry_normal,
912
+ dim=geo.cell_count(),
913
+ inputs=[
914
+ geo.cell_arg_value(wp.get_device()),
915
+ deformed_geo.cell_arg_value(wp.get_device()),
916
+ rotation,
917
+ ],
918
+ )
919
+
856
920
  wp.synchronize()
857
921
 
858
922
 
@@ -1847,7 +1911,7 @@ def test_vector_spaces(test, device):
1847
1911
 
1848
1912
  @wp.kernel
1849
1913
  def test_qr_eigenvalues():
1850
- tol = 1.0e-8
1914
+ tol = 5.0e-7
1851
1915
 
1852
1916
  # zero
1853
1917
  Zero = wp.mat33(0.0)
@@ -1984,6 +2048,7 @@ class TestFemUtilities(unittest.TestCase):
1984
2048
 
1985
2049
 
1986
2050
  add_kernel_test(TestFemUtilities, test_qr_eigenvalues, dim=1, devices=devices)
2051
+
1987
2052
  add_kernel_test(TestFemUtilities, test_qr_inverse, dim=100, devices=devices)
1988
2053
  add_function_test(TestFemUtilities, "test_array_axpy", test_array_axpy)
1989
2054