warp-lang 1.2.2__py3-none-win_amd64.whl → 1.3.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 (194) hide show
  1. warp/__init__.py +8 -6
  2. warp/autograd.py +823 -0
  3. warp/bin/warp-clang.dll +0 -0
  4. warp/bin/warp.dll +0 -0
  5. warp/build.py +6 -2
  6. warp/builtins.py +1412 -888
  7. warp/codegen.py +503 -166
  8. warp/config.py +48 -18
  9. warp/context.py +400 -198
  10. warp/dlpack.py +8 -0
  11. warp/examples/assets/bunny.usd +0 -0
  12. warp/examples/benchmarks/benchmark_cloth_warp.py +1 -1
  13. warp/examples/benchmarks/benchmark_interop_torch.py +158 -0
  14. warp/examples/benchmarks/benchmark_launches.py +1 -1
  15. warp/examples/core/example_cupy.py +78 -0
  16. warp/examples/fem/example_apic_fluid.py +17 -36
  17. warp/examples/fem/example_burgers.py +9 -18
  18. warp/examples/fem/example_convection_diffusion.py +7 -17
  19. warp/examples/fem/example_convection_diffusion_dg.py +27 -47
  20. warp/examples/fem/example_deformed_geometry.py +11 -22
  21. warp/examples/fem/example_diffusion.py +7 -18
  22. warp/examples/fem/example_diffusion_3d.py +24 -28
  23. warp/examples/fem/example_diffusion_mgpu.py +7 -14
  24. warp/examples/fem/example_magnetostatics.py +190 -0
  25. warp/examples/fem/example_mixed_elasticity.py +111 -80
  26. warp/examples/fem/example_navier_stokes.py +30 -34
  27. warp/examples/fem/example_nonconforming_contact.py +290 -0
  28. warp/examples/fem/example_stokes.py +17 -32
  29. warp/examples/fem/example_stokes_transfer.py +12 -21
  30. warp/examples/fem/example_streamlines.py +350 -0
  31. warp/examples/fem/utils.py +936 -0
  32. warp/fabric.py +5 -2
  33. warp/fem/__init__.py +13 -3
  34. warp/fem/cache.py +161 -11
  35. warp/fem/dirichlet.py +37 -28
  36. warp/fem/domain.py +105 -14
  37. warp/fem/field/__init__.py +14 -3
  38. warp/fem/field/field.py +454 -11
  39. warp/fem/field/nodal_field.py +33 -18
  40. warp/fem/geometry/deformed_geometry.py +50 -15
  41. warp/fem/geometry/hexmesh.py +12 -24
  42. warp/fem/geometry/nanogrid.py +106 -31
  43. warp/fem/geometry/quadmesh_2d.py +6 -11
  44. warp/fem/geometry/tetmesh.py +103 -61
  45. warp/fem/geometry/trimesh_2d.py +98 -47
  46. warp/fem/integrate.py +231 -186
  47. warp/fem/operator.py +14 -9
  48. warp/fem/quadrature/pic_quadrature.py +35 -9
  49. warp/fem/quadrature/quadrature.py +119 -32
  50. warp/fem/space/basis_space.py +98 -22
  51. warp/fem/space/collocated_function_space.py +3 -1
  52. warp/fem/space/function_space.py +7 -2
  53. warp/fem/space/grid_2d_function_space.py +3 -3
  54. warp/fem/space/grid_3d_function_space.py +4 -4
  55. warp/fem/space/hexmesh_function_space.py +3 -2
  56. warp/fem/space/nanogrid_function_space.py +12 -14
  57. warp/fem/space/partition.py +45 -47
  58. warp/fem/space/restriction.py +19 -16
  59. warp/fem/space/shape/cube_shape_function.py +91 -3
  60. warp/fem/space/shape/shape_function.py +7 -0
  61. warp/fem/space/shape/square_shape_function.py +32 -0
  62. warp/fem/space/shape/tet_shape_function.py +11 -7
  63. warp/fem/space/shape/triangle_shape_function.py +10 -1
  64. warp/fem/space/topology.py +116 -42
  65. warp/fem/types.py +8 -1
  66. warp/fem/utils.py +301 -83
  67. warp/native/array.h +16 -0
  68. warp/native/builtin.h +0 -15
  69. warp/native/cuda_util.cpp +14 -6
  70. warp/native/exports.h +1348 -1308
  71. warp/native/quat.h +79 -0
  72. warp/native/rand.h +27 -4
  73. warp/native/sparse.cpp +83 -81
  74. warp/native/sparse.cu +381 -453
  75. warp/native/vec.h +64 -0
  76. warp/native/volume.cpp +40 -49
  77. warp/native/volume_builder.cu +2 -3
  78. warp/native/volume_builder.h +12 -17
  79. warp/native/warp.cu +3 -3
  80. warp/native/warp.h +69 -59
  81. warp/render/render_opengl.py +17 -9
  82. warp/sim/articulation.py +117 -17
  83. warp/sim/collide.py +35 -29
  84. warp/sim/model.py +123 -18
  85. warp/sim/render.py +3 -1
  86. warp/sparse.py +867 -203
  87. warp/stubs.py +312 -541
  88. warp/tape.py +29 -1
  89. warp/tests/disabled_kinematics.py +1 -1
  90. warp/tests/test_adam.py +1 -1
  91. warp/tests/test_arithmetic.py +1 -1
  92. warp/tests/test_array.py +58 -1
  93. warp/tests/test_array_reduce.py +1 -1
  94. warp/tests/test_async.py +1 -1
  95. warp/tests/test_atomic.py +1 -1
  96. warp/tests/test_bool.py +1 -1
  97. warp/tests/test_builtins_resolution.py +1 -1
  98. warp/tests/test_bvh.py +6 -1
  99. warp/tests/test_closest_point_edge_edge.py +1 -1
  100. warp/tests/test_codegen.py +91 -1
  101. warp/tests/test_compile_consts.py +1 -1
  102. warp/tests/test_conditional.py +1 -1
  103. warp/tests/test_copy.py +1 -1
  104. warp/tests/test_ctypes.py +1 -1
  105. warp/tests/test_dense.py +1 -1
  106. warp/tests/test_devices.py +1 -1
  107. warp/tests/test_dlpack.py +1 -1
  108. warp/tests/test_examples.py +33 -4
  109. warp/tests/test_fabricarray.py +5 -2
  110. warp/tests/test_fast_math.py +1 -1
  111. warp/tests/test_fem.py +213 -6
  112. warp/tests/test_fp16.py +1 -1
  113. warp/tests/test_func.py +1 -1
  114. warp/tests/test_future_annotations.py +90 -0
  115. warp/tests/test_generics.py +1 -1
  116. warp/tests/test_grad.py +1 -1
  117. warp/tests/test_grad_customs.py +1 -1
  118. warp/tests/test_grad_debug.py +247 -0
  119. warp/tests/test_hash_grid.py +6 -1
  120. warp/tests/test_implicit_init.py +354 -0
  121. warp/tests/test_import.py +1 -1
  122. warp/tests/test_indexedarray.py +1 -1
  123. warp/tests/test_intersect.py +1 -1
  124. warp/tests/test_jax.py +1 -1
  125. warp/tests/test_large.py +1 -1
  126. warp/tests/test_launch.py +1 -1
  127. warp/tests/test_lerp.py +1 -1
  128. warp/tests/test_linear_solvers.py +1 -1
  129. warp/tests/test_lvalue.py +1 -1
  130. warp/tests/test_marching_cubes.py +5 -2
  131. warp/tests/test_mat.py +34 -35
  132. warp/tests/test_mat_lite.py +2 -1
  133. warp/tests/test_mat_scalar_ops.py +1 -1
  134. warp/tests/test_math.py +1 -1
  135. warp/tests/test_matmul.py +20 -16
  136. warp/tests/test_matmul_lite.py +1 -1
  137. warp/tests/test_mempool.py +1 -1
  138. warp/tests/test_mesh.py +5 -2
  139. warp/tests/test_mesh_query_aabb.py +1 -1
  140. warp/tests/test_mesh_query_point.py +1 -1
  141. warp/tests/test_mesh_query_ray.py +1 -1
  142. warp/tests/test_mlp.py +1 -1
  143. warp/tests/test_model.py +1 -1
  144. warp/tests/test_module_hashing.py +77 -1
  145. warp/tests/test_modules_lite.py +1 -1
  146. warp/tests/test_multigpu.py +1 -1
  147. warp/tests/test_noise.py +1 -1
  148. warp/tests/test_operators.py +1 -1
  149. warp/tests/test_options.py +1 -1
  150. warp/tests/test_overwrite.py +542 -0
  151. warp/tests/test_peer.py +1 -1
  152. warp/tests/test_pinned.py +1 -1
  153. warp/tests/test_print.py +1 -1
  154. warp/tests/test_quat.py +15 -1
  155. warp/tests/test_rand.py +1 -1
  156. warp/tests/test_reload.py +1 -1
  157. warp/tests/test_rounding.py +1 -1
  158. warp/tests/test_runlength_encode.py +1 -1
  159. warp/tests/test_scalar_ops.py +95 -0
  160. warp/tests/test_sim_grad.py +1 -1
  161. warp/tests/test_sim_kinematics.py +1 -1
  162. warp/tests/test_smoothstep.py +1 -1
  163. warp/tests/test_sparse.py +82 -15
  164. warp/tests/test_spatial.py +1 -1
  165. warp/tests/test_special_values.py +2 -11
  166. warp/tests/test_streams.py +11 -1
  167. warp/tests/test_struct.py +1 -1
  168. warp/tests/test_tape.py +1 -1
  169. warp/tests/test_torch.py +194 -1
  170. warp/tests/test_transient_module.py +1 -1
  171. warp/tests/test_types.py +1 -1
  172. warp/tests/test_utils.py +1 -1
  173. warp/tests/test_vec.py +15 -63
  174. warp/tests/test_vec_lite.py +2 -1
  175. warp/tests/test_vec_scalar_ops.py +65 -1
  176. warp/tests/test_verify_fp.py +1 -1
  177. warp/tests/test_volume.py +28 -2
  178. warp/tests/test_volume_write.py +1 -1
  179. warp/tests/unittest_serial.py +1 -1
  180. warp/tests/unittest_suites.py +9 -1
  181. warp/tests/walkthrough_debug.py +1 -1
  182. warp/thirdparty/unittest_parallel.py +2 -5
  183. warp/torch.py +103 -41
  184. warp/types.py +341 -224
  185. warp/utils.py +11 -2
  186. {warp_lang-1.2.2.dist-info → warp_lang-1.3.1.dist-info}/METADATA +99 -46
  187. warp_lang-1.3.1.dist-info/RECORD +368 -0
  188. warp/examples/fem/bsr_utils.py +0 -378
  189. warp/examples/fem/mesh_utils.py +0 -133
  190. warp/examples/fem/plot_utils.py +0 -292
  191. warp_lang-1.2.2.dist-info/RECORD +0 -359
  192. {warp_lang-1.2.2.dist-info → warp_lang-1.3.1.dist-info}/LICENSE.md +0 -0
  193. {warp_lang-1.2.2.dist-info → warp_lang-1.3.1.dist-info}/WHEEL +0 -0
  194. {warp_lang-1.2.2.dist-info → warp_lang-1.3.1.dist-info}/top_level.txt +0 -0
warp/dlpack.py CHANGED
@@ -60,10 +60,18 @@ PyCapsule_SetName.restype = ctypes.c_int
60
60
  class _DLPackTensorHolder:
61
61
  """Class responsible for deleting DLManagedTensor memory after ownership is transferred from a capsule."""
62
62
 
63
+ def __new__(cls, *args, **kwargs):
64
+ instance = super(_DLPackTensorHolder, cls).__new__(cls)
65
+ instance.mem_ptr = None
66
+ return instance
67
+
63
68
  def __init__(self, mem_ptr):
64
69
  self.mem_ptr = mem_ptr
65
70
 
66
71
  def __del__(self):
72
+ if not self.mem_ptr:
73
+ return
74
+
67
75
  managed_tensor = DLManagedTensor.from_address(self.mem_ptr)
68
76
  if managed_tensor.deleter:
69
77
  managed_tensor.deleter(self.mem_ptr)
Binary file
@@ -7,7 +7,7 @@
7
7
 
8
8
  import warp as wp
9
9
 
10
- wp.build.clear_kernel_cache()
10
+ wp.clear_kernel_cache()
11
11
 
12
12
 
13
13
  @wp.kernel
@@ -0,0 +1,158 @@
1
+ # Copyright (c) 2024 NVIDIA CORPORATION. All rights reserved.
2
+ # NVIDIA CORPORATION and its licensors retain all intellectual property
3
+ # and proprietary rights in and to this software, related documentation
4
+ # and any modifications thereto. Any use, reproduction, disclosure or
5
+ # distribution of this software and related documentation without an express
6
+ # license agreement from NVIDIA CORPORATION is strictly prohibited.
7
+
8
+ import time
9
+
10
+ import torch
11
+
12
+ import warp as wp
13
+
14
+
15
+ def create_simple_kernel(dtype):
16
+ def simple_kernel(
17
+ a: wp.array(dtype=dtype),
18
+ b: wp.array(dtype=dtype),
19
+ c: wp.array(dtype=dtype),
20
+ d: wp.array(dtype=dtype),
21
+ e: wp.array(dtype=dtype),
22
+ ):
23
+ pass
24
+
25
+ return wp.Kernel(simple_kernel)
26
+
27
+
28
+ def test_from_torch(kernel, num_iters, array_size, device, warp_dtype=None):
29
+ warp_device = wp.get_device(device)
30
+ torch_device = wp.device_to_torch(warp_device)
31
+
32
+ if hasattr(warp_dtype, "_shape_"):
33
+ torch_shape = (array_size, *warp_dtype._shape_)
34
+ torch_dtype = wp.dtype_to_torch(warp_dtype._wp_scalar_type_)
35
+ else:
36
+ torch_shape = (array_size,)
37
+ torch_dtype = torch.float32 if warp_dtype is None else wp.dtype_to_torch(warp_dtype)
38
+
39
+ _a = torch.zeros(torch_shape, dtype=torch_dtype, device=torch_device)
40
+ _b = torch.zeros(torch_shape, dtype=torch_dtype, device=torch_device)
41
+ _c = torch.zeros(torch_shape, dtype=torch_dtype, device=torch_device)
42
+ _d = torch.zeros(torch_shape, dtype=torch_dtype, device=torch_device)
43
+ _e = torch.zeros(torch_shape, dtype=torch_dtype, device=torch_device)
44
+
45
+ wp.synchronize()
46
+
47
+ # profiler = Profiler(interval=0.000001)
48
+ # profiler.start()
49
+
50
+ t1 = time.time_ns()
51
+
52
+ for _ in range(num_iters):
53
+ a = wp.from_torch(_a, dtype=warp_dtype)
54
+ b = wp.from_torch(_b, dtype=warp_dtype)
55
+ c = wp.from_torch(_c, dtype=warp_dtype)
56
+ d = wp.from_torch(_d, dtype=warp_dtype)
57
+ e = wp.from_torch(_e, dtype=warp_dtype)
58
+ wp.launch(kernel, dim=array_size, inputs=[a, b, c, d, e])
59
+
60
+ t2 = time.time_ns()
61
+ print(f"{(t2 - t1) / 1_000_000 :8.0f} ms from_torch(...)")
62
+
63
+ # profiler.stop()
64
+ # profiler.print()
65
+
66
+
67
+ def test_array_ctype_from_torch(kernel, num_iters, array_size, device, warp_dtype=None):
68
+ warp_device = wp.get_device(device)
69
+ torch_device = wp.device_to_torch(warp_device)
70
+
71
+ if hasattr(warp_dtype, "_shape_"):
72
+ torch_shape = (array_size, *warp_dtype._shape_)
73
+ torch_dtype = wp.dtype_to_torch(warp_dtype._wp_scalar_type_)
74
+ else:
75
+ torch_shape = (array_size,)
76
+ torch_dtype = torch.float32 if warp_dtype is None else wp.dtype_to_torch(warp_dtype)
77
+
78
+ _a = torch.zeros(torch_shape, dtype=torch_dtype, device=torch_device)
79
+ _b = torch.zeros(torch_shape, dtype=torch_dtype, device=torch_device)
80
+ _c = torch.zeros(torch_shape, dtype=torch_dtype, device=torch_device)
81
+ _d = torch.zeros(torch_shape, dtype=torch_dtype, device=torch_device)
82
+ _e = torch.zeros(torch_shape, dtype=torch_dtype, device=torch_device)
83
+
84
+ wp.synchronize()
85
+
86
+ # profiler = Profiler(interval=0.000001)
87
+ # profiler.start()
88
+
89
+ t1 = time.time_ns()
90
+
91
+ for _ in range(num_iters):
92
+ a = wp.from_torch(_a, dtype=warp_dtype, return_ctype=True)
93
+ b = wp.from_torch(_b, dtype=warp_dtype, return_ctype=True)
94
+ c = wp.from_torch(_c, dtype=warp_dtype, return_ctype=True)
95
+ d = wp.from_torch(_d, dtype=warp_dtype, return_ctype=True)
96
+ e = wp.from_torch(_e, dtype=warp_dtype, return_ctype=True)
97
+ wp.launch(kernel, dim=array_size, inputs=[a, b, c, d, e])
98
+
99
+ t2 = time.time_ns()
100
+ print(f"{(t2 - t1) / 1_000_000 :8.0f} ms from_torch(..., return_ctype=True)")
101
+
102
+ # profiler.stop()
103
+ # profiler.print()
104
+
105
+
106
+ def test_direct_from_torch(kernel, num_iters, array_size, device, warp_dtype=None):
107
+ warp_device = wp.get_device(device)
108
+ torch_device = wp.device_to_torch(warp_device)
109
+
110
+ if hasattr(warp_dtype, "_shape_"):
111
+ torch_shape = (array_size, *warp_dtype._shape_)
112
+ torch_dtype = wp.dtype_to_torch(warp_dtype._wp_scalar_type_)
113
+ else:
114
+ torch_shape = (array_size,)
115
+ torch_dtype = torch.float32 if warp_dtype is None else wp.dtype_to_torch(warp_dtype)
116
+
117
+ _a = torch.zeros(torch_shape, dtype=torch_dtype, device=torch_device)
118
+ _b = torch.zeros(torch_shape, dtype=torch_dtype, device=torch_device)
119
+ _c = torch.zeros(torch_shape, dtype=torch_dtype, device=torch_device)
120
+ _d = torch.zeros(torch_shape, dtype=torch_dtype, device=torch_device)
121
+ _e = torch.zeros(torch_shape, dtype=torch_dtype, device=torch_device)
122
+
123
+ wp.synchronize()
124
+
125
+ # profiler = Profiler(interval=0.000001)
126
+ # profiler.start()
127
+
128
+ t1 = time.time_ns()
129
+
130
+ for _ in range(num_iters):
131
+ wp.launch(kernel, dim=array_size, inputs=[_a, _b, _c, _d, _e])
132
+
133
+ t2 = time.time_ns()
134
+ print(f"{(t2 - t1) / 1_000_000 :8.0f} ms direct from torch")
135
+
136
+ # profiler.stop()
137
+ # profiler.print()
138
+
139
+
140
+ wp.init()
141
+
142
+ params = [
143
+ # (warp_dtype arg, kernel)
144
+ (None, create_simple_kernel(wp.float32)),
145
+ (wp.float32, create_simple_kernel(wp.float32)),
146
+ (wp.vec3f, create_simple_kernel(wp.vec3f)),
147
+ (wp.mat22f, create_simple_kernel(wp.mat22f)),
148
+ ]
149
+
150
+ wp.load_module()
151
+
152
+ num_iters = 100000
153
+
154
+ for warp_dtype, kernel in params:
155
+ print(f"\ndtype={wp.context.type_str(warp_dtype)}")
156
+ test_from_torch(kernel, num_iters, 10, "cuda:0", warp_dtype=warp_dtype)
157
+ test_array_ctype_from_torch(kernel, num_iters, 10, "cuda:0", warp_dtype=warp_dtype)
158
+ test_direct_from_torch(kernel, num_iters, 10, "cuda:0", warp_dtype=warp_dtype)
@@ -128,7 +128,7 @@ def ksz(s: Sz):
128
128
  tid = wp.tid() # noqa: F841
129
129
 
130
130
 
131
- wp.build.clear_kernel_cache()
131
+ wp.clear_kernel_cache()
132
132
 
133
133
  devices = wp.get_devices()
134
134
  num_launches = 100000
@@ -0,0 +1,78 @@
1
+ # Copyright (c) 2024 NVIDIA CORPORATION. All rights reserved.
2
+ # NVIDIA CORPORATION and its licensors retain all intellectual property
3
+ # and proprietary rights in and to this software, related documentation
4
+ # and any modifications thereto. Any use, reproduction, disclosure or
5
+ # distribution of this software and related documentation without an express
6
+ # license agreement from NVIDIA CORPORATION is strictly prohibited.
7
+
8
+ ###########################################################################
9
+ # Example CuPy
10
+ #
11
+ # The example demonstrates interoperability with CuPy on CUDA devices
12
+ # and NumPy on CPU devices.
13
+ ###########################################################################
14
+
15
+ import warp as wp
16
+
17
+
18
+ @wp.kernel
19
+ def saxpy(x: wp.array(dtype=float), y: wp.array(dtype=float), a: float):
20
+ i = wp.tid()
21
+ y[i] = a * x[i] + y[i]
22
+
23
+
24
+ class Example:
25
+ def __init__(self):
26
+ device = wp.get_device()
27
+
28
+ self.n = 10
29
+ self.a = 1.0
30
+
31
+ if device.is_cuda:
32
+ # use CuPy arrays on CUDA devices
33
+ import cupy as cp
34
+
35
+ print(f"Using CuPy on device {device}")
36
+
37
+ # tell CuPy to use the same device
38
+ with cp.cuda.Device(device.ordinal):
39
+ self.x = cp.arange(self.n, dtype=cp.float32)
40
+ self.y = cp.ones(self.n, dtype=cp.float32)
41
+ else:
42
+ # use NumPy arrays on CPU
43
+ import numpy as np
44
+
45
+ print("Using NumPy on CPU")
46
+
47
+ self.x = np.arange(self.n, dtype=np.float32)
48
+ self.y = np.ones(self.n, dtype=np.float32)
49
+
50
+ def step(self):
51
+ # Launch a Warp kernel on the pre-allocated arrays.
52
+ # When running on a CUDA device, these are CuPy arrays.
53
+ # When running on the CPU, these are NumPy arrays.
54
+ #
55
+ # Note that the arrays can be passed to Warp kernels directly. Under the hood,
56
+ # Warp uses the __cuda_array_interface__ and __array_interface__ protocols to
57
+ # access the data.
58
+ wp.launch(saxpy, dim=self.n, inputs=[self.x, self.y, self.a])
59
+
60
+ def render(self):
61
+ print(self.y)
62
+
63
+
64
+ if __name__ == "__main__":
65
+ import argparse
66
+
67
+ parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter)
68
+ parser.add_argument("--device", type=str, default=None, help="Override the default Warp device.")
69
+ parser.add_argument("--num_frames", type=int, default=10, help="Total number of frames.")
70
+
71
+ args = parser.parse_known_args()[0]
72
+
73
+ with wp.ScopedDevice(args.device):
74
+ example = Example()
75
+
76
+ for _ in range(args.num_frames):
77
+ example.step()
78
+ example.render()
@@ -15,17 +15,13 @@
15
15
  import numpy as np
16
16
 
17
17
  import warp as wp
18
+ import warp.examples.fem.utils as fem_example_utils
18
19
  import warp.fem as fem
19
20
  import warp.sim.render
20
21
  from warp.fem import Domain, Field, Sample, at_node, div, grad, integrand
21
22
  from warp.sim import Model, State
22
23
  from warp.sparse import BsrMatrix, bsr_mm, bsr_mv, bsr_transposed
23
24
 
24
- try:
25
- from .bsr_utils import bsr_cg
26
- except ImportError:
27
- from bsr_utils import bsr_cg
28
-
29
25
 
30
26
  @wp.func
31
27
  def collision_sdf(x: wp.vec3):
@@ -130,7 +126,7 @@ def scale_transposed_divergence_mat(
130
126
  tr_divergence_mat_values: wp.array(dtype=wp.mat(shape=(3, 1), dtype=float)),
131
127
  inv_fraction_int: wp.array(dtype=float),
132
128
  ):
133
- # In-place scaling of gradient operator rows wiht inverse mass
129
+ # In-place scaling of gradient operator rows with inverse mass
134
130
 
135
131
  u_i = wp.tid()
136
132
  block_beg = tr_divergence_mat_offsets[u_i]
@@ -140,22 +136,24 @@ def scale_transposed_divergence_mat(
140
136
  tr_divergence_mat_values[b] = tr_divergence_mat_values[b] * inv_fraction_int[u_i]
141
137
 
142
138
 
143
- @wp.kernel
144
- def compute_particle_ijk(positions: wp.array(dtype=wp.vec3), voxel_size: float, ijks: wp.array(dtype=wp.vec3i)):
145
- # Index-space coordinates of grid cell containing each particle
146
-
147
- p = wp.tid()
148
- pos = positions[p] / voxel_size
149
- ijks[p] = wp.vec3i(int(wp.floor(pos[0])), int(wp.floor(pos[1])), int(wp.floor(pos[2])))
150
-
151
-
152
- def solve_incompressibility(divergence_mat: BsrMatrix, inv_volume, pressure, velocity, quiet: bool = False):
139
+ def solve_incompressibility(
140
+ divergence_mat: BsrMatrix, dirichlet_projector: BsrMatrix, inv_volume, pressure, velocity, quiet: bool = False
141
+ ):
153
142
  """Solve for divergence-free velocity delta:
154
143
 
155
144
  delta_velocity = inv_volume * transpose(divergence_mat) * pressure
156
145
  divergence_mat * (velocity + delta_velocity) = 0
146
+ dirichlet_projector * delta_velocity = 0
157
147
  """
158
148
 
149
+ # Constraint-free divergence -- computed *before* projection of divergence_mat
150
+ rhs = wp.empty_like(pressure)
151
+ bsr_mv(A=divergence_mat, x=velocity, y=rhs, alpha=-1.0)
152
+
153
+ # Project matrix to enforce boundary conditions
154
+ # divergence_matrix -= divergence_matrix * vel_projector
155
+ bsr_mm(alpha=-1.0, x=divergence_mat, y=dirichlet_projector, z=divergence_mat, beta=1.0)
156
+
159
157
  # Build transposed gradient matrix, scale with inverse fraction
160
158
  transposed_divergence_mat = bsr_transposed(divergence_mat)
161
159
  wp.launch(
@@ -171,9 +169,7 @@ def solve_incompressibility(divergence_mat: BsrMatrix, inv_volume, pressure, vel
171
169
  # For simplicity, assemble Schur complement and solve with CG
172
170
  schur = bsr_mm(divergence_mat, transposed_divergence_mat)
173
171
 
174
- rhs = wp.zeros_like(pressure)
175
- bsr_mv(A=divergence_mat, x=velocity, y=rhs, alpha=-1.0, beta=0.0)
176
- bsr_cg(schur, b=rhs, x=pressure, quiet=quiet, tol=1.0e-6)
172
+ fem_example_utils.bsr_cg(schur, b=rhs, x=pressure, quiet=quiet, tol=1.0e-6)
177
173
 
178
174
  # Apply pressure to velocity
179
175
  bsr_mv(A=transposed_divergence_mat, x=pressure, y=velocity, alpha=1.0, beta=1.0)
@@ -249,23 +245,11 @@ class Example:
249
245
 
250
246
  self.current_frame = self.current_frame + 1
251
247
 
252
- particle_ijk = wp.empty(self.state_0.particle_count, dtype=wp.vec3i)
253
-
254
248
  with wp.ScopedTimer(f"simulate frame {self.current_frame}", active=True):
255
249
  for _s in range(self.sim_substeps):
256
- # Compute the voxel coordinates for each particle.
257
- # `Volume.allocate_by_voxels` accepts world positions, but allocates
258
- # the voxels with the closest origin rather than the enclosing ones
259
- # (i.e, it "round"s the positions, while here we eant to "floor" it)
260
- wp.launch(
261
- compute_particle_ijk,
262
- dim=particle_ijk.shape,
263
- inputs=[self.state_0.particle_q, self.voxel_size, particle_ijk],
264
- )
265
-
266
250
  # Allocate the voxels and create the warp.fem geometry
267
251
  volume = wp.Volume.allocate_by_voxels(
268
- voxel_points=particle_ijk,
252
+ voxel_points=self.state_0.particle_q,
269
253
  voxel_size=self.voxel_size,
270
254
  )
271
255
  grid = fem.Nanogrid(volume)
@@ -354,13 +338,10 @@ class Example:
354
338
  output_dtype=float,
355
339
  )
356
340
 
357
- # Project matrix to enforce boundary conditions
358
- # divergence_matrix -= divergence_matrix * vel_projector
359
- bsr_mm(alpha=-1.0, x=divergence_matrix, y=vel_projector, z=divergence_matrix, beta=1.0)
360
-
361
341
  # Solve unilateral incompressibility
362
342
  solve_incompressibility(
363
343
  divergence_matrix,
344
+ vel_projector,
364
345
  inv_volume,
365
346
  pressure_field.dof_values,
366
347
  velocity_field.dof_values,
@@ -16,17 +16,8 @@
16
16
  ###########################################################################
17
17
 
18
18
  import warp as wp
19
+ import warp.examples.fem.utils as fem_example_utils
19
20
  import warp.fem as fem
20
- import warp.sparse as sp
21
-
22
- # Import example utilities
23
- # Make sure that works both when imported as module and run as standalone file
24
- try:
25
- from .bsr_utils import invert_diagonal_bsr_mass_matrix
26
- from .plot_utils import Plot
27
- except ImportError:
28
- from bsr_utils import invert_diagonal_bsr_mass_matrix
29
- from plot_utils import Plot
30
21
 
31
22
 
32
23
  @fem.integrand
@@ -97,7 +88,7 @@ def slope_limiter(domain: fem.Domain, s: fem.Sample, u: fem.Field, dx: wp.vec2):
97
88
  # Assumes regular grid topology
98
89
 
99
90
  center_coords = fem.Coords(0.5, 0.5, 0.0)
100
- cell_center = fem.types.make_free_sample(s.element_index, center_coords)
91
+ cell_center = fem.make_free_sample(s.element_index, center_coords)
101
92
  center_pos = domain(cell_center)
102
93
 
103
94
  u_center = u(cell_center)
@@ -149,19 +140,19 @@ class Example:
149
140
  matrix_inertia = fem.integrate(
150
141
  vel_mass_form, fields={"u": trial, "v": self._test}, output_dtype=wp.float32, nodal=True
151
142
  )
152
- self._inv_mass_matrix = sp.bsr_copy(matrix_inertia)
153
- invert_diagonal_bsr_mass_matrix(self._inv_mass_matrix)
143
+ self._inv_mass_matrix = wp.sparse.bsr_copy(matrix_inertia)
144
+ fem_example_utils.invert_diagonal_bsr_matrix(self._inv_mass_matrix)
154
145
 
155
146
  # Initial condition
156
147
  self.velocity_field = vector_space.make_field()
157
148
  fem.interpolate(initial_condition, dest=self.velocity_field)
158
149
 
159
- # Velocity nor field -- for visualization purposes
150
+ # Velocity norm field -- for visualization purposes
160
151
  self.velocity_norm_field = scalar_space.make_field()
161
152
  fem.interpolate(velocity_norm, dest=self.velocity_norm_field, fields={"u": self.velocity_field})
162
153
 
163
- self.renderer = Plot()
164
- self.renderer.add_surface("u_norm", self.velocity_norm_field)
154
+ self.renderer = fem_example_utils.Plot()
155
+ self.renderer.add_field("u_norm", self.velocity_norm_field)
165
156
 
166
157
  def _velocity_delta(self, trial_velocity):
167
158
  # Integration on sides
@@ -186,7 +177,7 @@ class Example:
186
177
  alpha=1.0,
187
178
  beta=1.0,
188
179
  )
189
- return sp.bsr_mv(self._inv_mass_matrix, rhs)
180
+ return self._inv_mass_matrix @ rhs
190
181
 
191
182
  def step(self):
192
183
  self.current_frame += 1
@@ -223,7 +214,7 @@ class Example:
223
214
 
224
215
  def render(self):
225
216
  self.renderer.begin_frame(time=self.current_frame * self.sim_dt)
226
- self.renderer.add_surface("u_norm", self.velocity_norm_field)
217
+ self.renderer.add_field("u_norm", self.velocity_norm_field)
227
218
  self.renderer.end_frame()
228
219
 
229
220
 
@@ -15,19 +15,9 @@
15
15
  ###########################################################################
16
16
 
17
17
  import warp as wp
18
+ import warp.examples.fem.utils as fem_example_utils
18
19
  import warp.fem as fem
19
20
 
20
- # Import example utilities
21
- # Make sure that works both when imported as module and run as standalone file
22
- try:
23
- from .bsr_utils import bsr_cg
24
- from .mesh_utils import gen_trimesh
25
- from .plot_utils import Plot
26
- except ImportError:
27
- from bsr_utils import bsr_cg
28
- from mesh_utils import gen_trimesh
29
- from plot_utils import Plot
30
-
31
21
 
32
22
  @fem.integrand
33
23
  def initial_condition(domain: fem.Domain, s: fem.Sample):
@@ -94,8 +84,8 @@ class Example:
94
84
  self.current_frame = 0
95
85
 
96
86
  if tri_mesh:
97
- positions, tri_vidx = gen_trimesh(res=wp.vec2i(res))
98
- geo = fem.Trimesh2D(tri_vertex_indices=tri_vidx, positions=positions)
87
+ positions, tri_vidx = fem_example_utils.gen_trimesh(res=wp.vec2i(res))
88
+ geo = fem.Trimesh2D(tri_vertex_indices=tri_vidx, positions=positions, build_bvh=True)
99
89
  else:
100
90
  geo = fem.Grid2D(res=wp.vec2i(res))
101
91
 
@@ -116,8 +106,8 @@ class Example:
116
106
  output_dtype=float,
117
107
  )
118
108
 
119
- self.renderer = Plot()
120
- self.renderer.add_surface("phi", self._phi_field)
109
+ self.renderer = fem_example_utils.Plot()
110
+ self.renderer.add_field("phi", self._phi_field)
121
111
 
122
112
  def step(self):
123
113
  self.current_frame += 1
@@ -131,11 +121,11 @@ class Example:
131
121
  )
132
122
 
133
123
  # Solve linear system
134
- bsr_cg(self._matrix, x=self._phi_field.dof_values, b=rhs, quiet=self._quiet, tol=1.0e-12)
124
+ fem_example_utils.bsr_cg(self._matrix, x=self._phi_field.dof_values, b=rhs, quiet=self._quiet, tol=1.0e-12)
135
125
 
136
126
  def render(self):
137
127
  self.renderer.begin_frame(time=self.current_frame * self.sim_dt)
138
- self.renderer.add_surface("phi", self._phi_field)
128
+ self.renderer.add_field("phi", self._phi_field)
139
129
  self.renderer.end_frame()
140
130
 
141
131
 
@@ -15,31 +15,14 @@
15
15
  ###########################################################################
16
16
 
17
17
  import warp as wp
18
+ import warp.examples.fem.utils as fem_example_utils
18
19
  import warp.fem as fem
19
- from warp.sparse import bsr_axpy
20
-
21
- # Import example utilities
22
- # Make sure that works both when imported as module and run as standalone file
23
- try:
24
- from .bsr_utils import bsr_cg
25
- from .example_convection_diffusion import (
26
- diffusion_form,
27
- inertia_form,
28
- initial_condition,
29
- velocity,
30
- )
31
- from .mesh_utils import gen_quadmesh, gen_trimesh
32
- from .plot_utils import Plot
33
- except ImportError:
34
- from bsr_utils import bsr_cg
35
- from example_convection_diffusion import (
36
- diffusion_form,
37
- inertia_form,
38
- initial_condition,
39
- velocity,
40
- )
41
- from mesh_utils import gen_quadmesh, gen_trimesh
42
- from plot_utils import Plot
20
+ from warp.examples.fem.example_convection_diffusion import (
21
+ diffusion_form,
22
+ inertia_form,
23
+ initial_condition,
24
+ velocity,
25
+ )
43
26
 
44
27
 
45
28
  # Standard transport term, on cells' interior
@@ -58,6 +41,10 @@ def upwind_transport_form(s: fem.Sample, domain: fem.Domain, phi: fem.Field, psi
58
41
  vel = velocity(pos, ang_vel)
59
42
  vel_n = wp.dot(vel, fem.normal(domain, s))
60
43
 
44
+ if wp.min(pos) <= 0.0 or wp.max(pos) >= 1.0: # boundary side
45
+ return phi(s) * (-psi(s) * vel_n + 0.5 * psi(s) * wp.abs(vel_n))
46
+
47
+ # interior side
61
48
  return fem.jump(phi, s) * (-fem.average(psi, s) * vel_n + 0.5 * fem.jump(psi, s) * wp.abs(vel_n))
62
49
 
63
50
 
@@ -79,7 +66,7 @@ def sip_diffusion_form(
79
66
 
80
67
 
81
68
  class Example:
82
- def __init__(self, quiet=False, degree=2, resolution=50, mesh="grid", viscosity=0.001, ang_vel=1.0):
69
+ def __init__(self, quiet=False, degree=2, resolution=50, mesh="grid", viscosity=0.0001, ang_vel=1.0):
83
70
  self._quiet = quiet
84
71
 
85
72
  res = resolution
@@ -87,10 +74,10 @@ class Example:
87
74
  self.current_frame = 0
88
75
 
89
76
  if mesh == "tri":
90
- positions, tri_vidx = gen_trimesh(res=wp.vec2i(resolution))
77
+ positions, tri_vidx = fem_example_utils.gen_trimesh(res=wp.vec2i(resolution))
91
78
  geo = fem.Trimesh2D(tri_vertex_indices=tri_vidx, positions=positions)
92
79
  elif mesh == "quad":
93
- positions, quad_vidx = gen_quadmesh(res=wp.vec2i(resolution))
80
+ positions, quad_vidx = fem_example_utils.gen_quadmesh(res=wp.vec2i(resolution))
94
81
  geo = fem.Quadmesh2D(quad_vertex_indices=quad_vidx, positions=positions)
95
82
  else:
96
83
  geo = fem.Grid2D(res=wp.vec2i(resolution))
@@ -124,37 +111,30 @@ class Example:
124
111
  side_test = fem.make_test(space=scalar_space, domain=sides)
125
112
  side_trial = fem.make_trial(space=scalar_space, domain=sides)
126
113
 
127
- bsr_axpy(
128
- fem.integrate(
129
- upwind_transport_form,
130
- fields={"phi": side_trial, "psi": side_test},
131
- values={"ang_vel": ang_vel},
132
- ),
133
- y=matrix_transport,
114
+ matrix_transport += fem.integrate(
115
+ upwind_transport_form,
116
+ fields={"phi": side_trial, "psi": side_test},
117
+ values={"ang_vel": ang_vel},
134
118
  )
135
119
 
136
120
  matrix_diffusion = fem.integrate(
137
121
  diffusion_form,
138
122
  fields={"u": trial, "v": self._test},
139
123
  )
140
- bsr_axpy(
141
- fem.integrate(
142
- sip_diffusion_form,
143
- fields={"phi": side_trial, "psi": side_test},
144
- ),
145
- y=matrix_diffusion,
124
+
125
+ matrix_diffusion += fem.integrate(
126
+ sip_diffusion_form,
127
+ fields={"phi": side_trial, "psi": side_test},
146
128
  )
147
129
 
148
- self._matrix = matrix_inertia
149
- bsr_axpy(x=matrix_transport, y=self._matrix)
150
- bsr_axpy(x=matrix_diffusion, y=self._matrix, alpha=viscosity)
130
+ self._matrix = matrix_inertia + matrix_transport + viscosity * matrix_diffusion
151
131
 
152
132
  # Initial condition
153
133
  self._phi_field = scalar_space.make_field()
154
134
  fem.interpolate(initial_condition, dest=self._phi_field)
155
135
 
156
- self.renderer = Plot()
157
- self.renderer.add_surface("phi", self._phi_field)
136
+ self.renderer = fem_example_utils.Plot()
137
+ self.renderer.add_field("phi", self._phi_field)
158
138
 
159
139
  def step(self):
160
140
  self.current_frame += 1
@@ -166,13 +146,13 @@ class Example:
166
146
  )
167
147
 
168
148
  phi = wp.zeros_like(rhs)
169
- bsr_cg(self._matrix, b=rhs, x=phi, method="bicgstab", quiet=self._quiet)
149
+ fem_example_utils.bsr_cg(self._matrix, b=rhs, x=phi, method="bicgstab", quiet=self._quiet)
170
150
 
171
151
  wp.utils.array_cast(in_array=phi, out_array=self._phi_field.dof_values)
172
152
 
173
153
  def render(self):
174
154
  self.renderer.begin_frame(time=self.current_frame * self.sim_dt)
175
- self.renderer.add_surface("phi", self._phi_field)
155
+ self.renderer.add_field("phi", self._phi_field)
176
156
  self.renderer.end_frame()
177
157
 
178
158