warp-lang 1.7.0__py3-none-manylinux_2_28_x86_64.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 (429) hide show
  1. warp/__init__.py +139 -0
  2. warp/__init__.pyi +1 -0
  3. warp/autograd.py +1142 -0
  4. warp/bin/warp-clang.so +0 -0
  5. warp/bin/warp.so +0 -0
  6. warp/build.py +557 -0
  7. warp/build_dll.py +405 -0
  8. warp/builtins.py +6855 -0
  9. warp/codegen.py +3969 -0
  10. warp/config.py +158 -0
  11. warp/constants.py +57 -0
  12. warp/context.py +6812 -0
  13. warp/dlpack.py +462 -0
  14. warp/examples/__init__.py +24 -0
  15. warp/examples/assets/bear.usd +0 -0
  16. warp/examples/assets/bunny.usd +0 -0
  17. warp/examples/assets/cartpole.urdf +110 -0
  18. warp/examples/assets/crazyflie.usd +0 -0
  19. warp/examples/assets/cube.usd +0 -0
  20. warp/examples/assets/nonuniform.usd +0 -0
  21. warp/examples/assets/nv_ant.xml +92 -0
  22. warp/examples/assets/nv_humanoid.xml +183 -0
  23. warp/examples/assets/nvidia_logo.png +0 -0
  24. warp/examples/assets/pixel.jpg +0 -0
  25. warp/examples/assets/quadruped.urdf +268 -0
  26. warp/examples/assets/rocks.nvdb +0 -0
  27. warp/examples/assets/rocks.usd +0 -0
  28. warp/examples/assets/sphere.usd +0 -0
  29. warp/examples/assets/square_cloth.usd +0 -0
  30. warp/examples/benchmarks/benchmark_api.py +389 -0
  31. warp/examples/benchmarks/benchmark_cloth.py +296 -0
  32. warp/examples/benchmarks/benchmark_cloth_cupy.py +96 -0
  33. warp/examples/benchmarks/benchmark_cloth_jax.py +105 -0
  34. warp/examples/benchmarks/benchmark_cloth_numba.py +161 -0
  35. warp/examples/benchmarks/benchmark_cloth_numpy.py +85 -0
  36. warp/examples/benchmarks/benchmark_cloth_paddle.py +94 -0
  37. warp/examples/benchmarks/benchmark_cloth_pytorch.py +94 -0
  38. warp/examples/benchmarks/benchmark_cloth_taichi.py +120 -0
  39. warp/examples/benchmarks/benchmark_cloth_warp.py +153 -0
  40. warp/examples/benchmarks/benchmark_gemm.py +164 -0
  41. warp/examples/benchmarks/benchmark_interop_paddle.py +166 -0
  42. warp/examples/benchmarks/benchmark_interop_torch.py +166 -0
  43. warp/examples/benchmarks/benchmark_launches.py +301 -0
  44. warp/examples/benchmarks/benchmark_tile_load_store.py +103 -0
  45. warp/examples/browse.py +37 -0
  46. warp/examples/core/example_cupy.py +86 -0
  47. warp/examples/core/example_dem.py +241 -0
  48. warp/examples/core/example_fluid.py +299 -0
  49. warp/examples/core/example_graph_capture.py +150 -0
  50. warp/examples/core/example_marching_cubes.py +194 -0
  51. warp/examples/core/example_mesh.py +180 -0
  52. warp/examples/core/example_mesh_intersect.py +211 -0
  53. warp/examples/core/example_nvdb.py +182 -0
  54. warp/examples/core/example_raycast.py +111 -0
  55. warp/examples/core/example_raymarch.py +205 -0
  56. warp/examples/core/example_render_opengl.py +193 -0
  57. warp/examples/core/example_sample_mesh.py +300 -0
  58. warp/examples/core/example_sph.py +411 -0
  59. warp/examples/core/example_torch.py +211 -0
  60. warp/examples/core/example_wave.py +269 -0
  61. warp/examples/fem/example_adaptive_grid.py +286 -0
  62. warp/examples/fem/example_apic_fluid.py +423 -0
  63. warp/examples/fem/example_burgers.py +261 -0
  64. warp/examples/fem/example_convection_diffusion.py +178 -0
  65. warp/examples/fem/example_convection_diffusion_dg.py +204 -0
  66. warp/examples/fem/example_deformed_geometry.py +172 -0
  67. warp/examples/fem/example_diffusion.py +196 -0
  68. warp/examples/fem/example_diffusion_3d.py +225 -0
  69. warp/examples/fem/example_diffusion_mgpu.py +220 -0
  70. warp/examples/fem/example_distortion_energy.py +228 -0
  71. warp/examples/fem/example_magnetostatics.py +240 -0
  72. warp/examples/fem/example_mixed_elasticity.py +291 -0
  73. warp/examples/fem/example_navier_stokes.py +261 -0
  74. warp/examples/fem/example_nonconforming_contact.py +298 -0
  75. warp/examples/fem/example_stokes.py +213 -0
  76. warp/examples/fem/example_stokes_transfer.py +262 -0
  77. warp/examples/fem/example_streamlines.py +352 -0
  78. warp/examples/fem/utils.py +1000 -0
  79. warp/examples/interop/example_jax_callable.py +116 -0
  80. warp/examples/interop/example_jax_ffi_callback.py +132 -0
  81. warp/examples/interop/example_jax_kernel.py +205 -0
  82. warp/examples/optim/example_bounce.py +266 -0
  83. warp/examples/optim/example_cloth_throw.py +228 -0
  84. warp/examples/optim/example_diffray.py +561 -0
  85. warp/examples/optim/example_drone.py +870 -0
  86. warp/examples/optim/example_fluid_checkpoint.py +497 -0
  87. warp/examples/optim/example_inverse_kinematics.py +182 -0
  88. warp/examples/optim/example_inverse_kinematics_torch.py +191 -0
  89. warp/examples/optim/example_softbody_properties.py +400 -0
  90. warp/examples/optim/example_spring_cage.py +245 -0
  91. warp/examples/optim/example_trajectory.py +227 -0
  92. warp/examples/sim/example_cartpole.py +143 -0
  93. warp/examples/sim/example_cloth.py +225 -0
  94. warp/examples/sim/example_cloth_self_contact.py +322 -0
  95. warp/examples/sim/example_granular.py +130 -0
  96. warp/examples/sim/example_granular_collision_sdf.py +202 -0
  97. warp/examples/sim/example_jacobian_ik.py +244 -0
  98. warp/examples/sim/example_particle_chain.py +124 -0
  99. warp/examples/sim/example_quadruped.py +203 -0
  100. warp/examples/sim/example_rigid_chain.py +203 -0
  101. warp/examples/sim/example_rigid_contact.py +195 -0
  102. warp/examples/sim/example_rigid_force.py +133 -0
  103. warp/examples/sim/example_rigid_gyroscopic.py +115 -0
  104. warp/examples/sim/example_rigid_soft_contact.py +140 -0
  105. warp/examples/sim/example_soft_body.py +196 -0
  106. warp/examples/tile/example_tile_cholesky.py +87 -0
  107. warp/examples/tile/example_tile_convolution.py +66 -0
  108. warp/examples/tile/example_tile_fft.py +55 -0
  109. warp/examples/tile/example_tile_filtering.py +113 -0
  110. warp/examples/tile/example_tile_matmul.py +85 -0
  111. warp/examples/tile/example_tile_mlp.py +383 -0
  112. warp/examples/tile/example_tile_nbody.py +199 -0
  113. warp/examples/tile/example_tile_walker.py +327 -0
  114. warp/fabric.py +355 -0
  115. warp/fem/__init__.py +106 -0
  116. warp/fem/adaptivity.py +508 -0
  117. warp/fem/cache.py +572 -0
  118. warp/fem/dirichlet.py +202 -0
  119. warp/fem/domain.py +411 -0
  120. warp/fem/field/__init__.py +125 -0
  121. warp/fem/field/field.py +619 -0
  122. warp/fem/field/nodal_field.py +326 -0
  123. warp/fem/field/restriction.py +37 -0
  124. warp/fem/field/virtual.py +848 -0
  125. warp/fem/geometry/__init__.py +32 -0
  126. warp/fem/geometry/adaptive_nanogrid.py +857 -0
  127. warp/fem/geometry/closest_point.py +84 -0
  128. warp/fem/geometry/deformed_geometry.py +221 -0
  129. warp/fem/geometry/element.py +776 -0
  130. warp/fem/geometry/geometry.py +362 -0
  131. warp/fem/geometry/grid_2d.py +392 -0
  132. warp/fem/geometry/grid_3d.py +452 -0
  133. warp/fem/geometry/hexmesh.py +911 -0
  134. warp/fem/geometry/nanogrid.py +571 -0
  135. warp/fem/geometry/partition.py +389 -0
  136. warp/fem/geometry/quadmesh.py +663 -0
  137. warp/fem/geometry/tetmesh.py +855 -0
  138. warp/fem/geometry/trimesh.py +806 -0
  139. warp/fem/integrate.py +2335 -0
  140. warp/fem/linalg.py +419 -0
  141. warp/fem/operator.py +293 -0
  142. warp/fem/polynomial.py +229 -0
  143. warp/fem/quadrature/__init__.py +17 -0
  144. warp/fem/quadrature/pic_quadrature.py +299 -0
  145. warp/fem/quadrature/quadrature.py +591 -0
  146. warp/fem/space/__init__.py +228 -0
  147. warp/fem/space/basis_function_space.py +468 -0
  148. warp/fem/space/basis_space.py +667 -0
  149. warp/fem/space/dof_mapper.py +251 -0
  150. warp/fem/space/function_space.py +309 -0
  151. warp/fem/space/grid_2d_function_space.py +177 -0
  152. warp/fem/space/grid_3d_function_space.py +227 -0
  153. warp/fem/space/hexmesh_function_space.py +257 -0
  154. warp/fem/space/nanogrid_function_space.py +201 -0
  155. warp/fem/space/partition.py +367 -0
  156. warp/fem/space/quadmesh_function_space.py +223 -0
  157. warp/fem/space/restriction.py +179 -0
  158. warp/fem/space/shape/__init__.py +143 -0
  159. warp/fem/space/shape/cube_shape_function.py +1105 -0
  160. warp/fem/space/shape/shape_function.py +133 -0
  161. warp/fem/space/shape/square_shape_function.py +926 -0
  162. warp/fem/space/shape/tet_shape_function.py +834 -0
  163. warp/fem/space/shape/triangle_shape_function.py +672 -0
  164. warp/fem/space/tetmesh_function_space.py +271 -0
  165. warp/fem/space/topology.py +424 -0
  166. warp/fem/space/trimesh_function_space.py +194 -0
  167. warp/fem/types.py +99 -0
  168. warp/fem/utils.py +420 -0
  169. warp/jax.py +187 -0
  170. warp/jax_experimental/__init__.py +16 -0
  171. warp/jax_experimental/custom_call.py +351 -0
  172. warp/jax_experimental/ffi.py +698 -0
  173. warp/jax_experimental/xla_ffi.py +602 -0
  174. warp/math.py +244 -0
  175. warp/native/array.h +1145 -0
  176. warp/native/builtin.h +1800 -0
  177. warp/native/bvh.cpp +492 -0
  178. warp/native/bvh.cu +791 -0
  179. warp/native/bvh.h +554 -0
  180. warp/native/clang/clang.cpp +536 -0
  181. warp/native/coloring.cpp +613 -0
  182. warp/native/crt.cpp +51 -0
  183. warp/native/crt.h +362 -0
  184. warp/native/cuda_crt.h +1058 -0
  185. warp/native/cuda_util.cpp +646 -0
  186. warp/native/cuda_util.h +307 -0
  187. warp/native/error.cpp +77 -0
  188. warp/native/error.h +36 -0
  189. warp/native/exports.h +1878 -0
  190. warp/native/fabric.h +245 -0
  191. warp/native/hashgrid.cpp +311 -0
  192. warp/native/hashgrid.cu +87 -0
  193. warp/native/hashgrid.h +240 -0
  194. warp/native/initializer_array.h +41 -0
  195. warp/native/intersect.h +1230 -0
  196. warp/native/intersect_adj.h +375 -0
  197. warp/native/intersect_tri.h +339 -0
  198. warp/native/marching.cpp +19 -0
  199. warp/native/marching.cu +514 -0
  200. warp/native/marching.h +19 -0
  201. warp/native/mat.h +2220 -0
  202. warp/native/mathdx.cpp +87 -0
  203. warp/native/matnn.h +343 -0
  204. warp/native/mesh.cpp +266 -0
  205. warp/native/mesh.cu +404 -0
  206. warp/native/mesh.h +1980 -0
  207. warp/native/nanovdb/GridHandle.h +366 -0
  208. warp/native/nanovdb/HostBuffer.h +590 -0
  209. warp/native/nanovdb/NanoVDB.h +6624 -0
  210. warp/native/nanovdb/PNanoVDB.h +3390 -0
  211. warp/native/noise.h +859 -0
  212. warp/native/quat.h +1371 -0
  213. warp/native/rand.h +342 -0
  214. warp/native/range.h +139 -0
  215. warp/native/reduce.cpp +174 -0
  216. warp/native/reduce.cu +364 -0
  217. warp/native/runlength_encode.cpp +79 -0
  218. warp/native/runlength_encode.cu +61 -0
  219. warp/native/scan.cpp +47 -0
  220. warp/native/scan.cu +53 -0
  221. warp/native/scan.h +23 -0
  222. warp/native/solid_angle.h +466 -0
  223. warp/native/sort.cpp +251 -0
  224. warp/native/sort.cu +277 -0
  225. warp/native/sort.h +33 -0
  226. warp/native/sparse.cpp +378 -0
  227. warp/native/sparse.cu +524 -0
  228. warp/native/spatial.h +657 -0
  229. warp/native/svd.h +702 -0
  230. warp/native/temp_buffer.h +46 -0
  231. warp/native/tile.h +2584 -0
  232. warp/native/tile_reduce.h +264 -0
  233. warp/native/vec.h +1426 -0
  234. warp/native/volume.cpp +501 -0
  235. warp/native/volume.cu +67 -0
  236. warp/native/volume.h +969 -0
  237. warp/native/volume_builder.cu +477 -0
  238. warp/native/volume_builder.h +52 -0
  239. warp/native/volume_impl.h +70 -0
  240. warp/native/warp.cpp +1082 -0
  241. warp/native/warp.cu +3636 -0
  242. warp/native/warp.h +381 -0
  243. warp/optim/__init__.py +17 -0
  244. warp/optim/adam.py +163 -0
  245. warp/optim/linear.py +1137 -0
  246. warp/optim/sgd.py +112 -0
  247. warp/paddle.py +407 -0
  248. warp/render/__init__.py +18 -0
  249. warp/render/render_opengl.py +3518 -0
  250. warp/render/render_usd.py +784 -0
  251. warp/render/utils.py +160 -0
  252. warp/sim/__init__.py +65 -0
  253. warp/sim/articulation.py +793 -0
  254. warp/sim/collide.py +2395 -0
  255. warp/sim/graph_coloring.py +300 -0
  256. warp/sim/import_mjcf.py +790 -0
  257. warp/sim/import_snu.py +227 -0
  258. warp/sim/import_urdf.py +579 -0
  259. warp/sim/import_usd.py +894 -0
  260. warp/sim/inertia.py +324 -0
  261. warp/sim/integrator.py +242 -0
  262. warp/sim/integrator_euler.py +1997 -0
  263. warp/sim/integrator_featherstone.py +2101 -0
  264. warp/sim/integrator_vbd.py +2048 -0
  265. warp/sim/integrator_xpbd.py +3292 -0
  266. warp/sim/model.py +4791 -0
  267. warp/sim/particles.py +121 -0
  268. warp/sim/render.py +427 -0
  269. warp/sim/utils.py +428 -0
  270. warp/sparse.py +2057 -0
  271. warp/stubs.py +3333 -0
  272. warp/tape.py +1203 -0
  273. warp/tests/__init__.py +1 -0
  274. warp/tests/__main__.py +4 -0
  275. warp/tests/assets/curlnoise_golden.npy +0 -0
  276. warp/tests/assets/mlp_golden.npy +0 -0
  277. warp/tests/assets/pixel.npy +0 -0
  278. warp/tests/assets/pnoise_golden.npy +0 -0
  279. warp/tests/assets/spiky.usd +0 -0
  280. warp/tests/assets/test_grid.nvdb +0 -0
  281. warp/tests/assets/test_index_grid.nvdb +0 -0
  282. warp/tests/assets/test_int32_grid.nvdb +0 -0
  283. warp/tests/assets/test_vec_grid.nvdb +0 -0
  284. warp/tests/assets/torus.nvdb +0 -0
  285. warp/tests/assets/torus.usda +105 -0
  286. warp/tests/aux_test_class_kernel.py +34 -0
  287. warp/tests/aux_test_compile_consts_dummy.py +18 -0
  288. warp/tests/aux_test_conditional_unequal_types_kernels.py +29 -0
  289. warp/tests/aux_test_dependent.py +29 -0
  290. warp/tests/aux_test_grad_customs.py +29 -0
  291. warp/tests/aux_test_instancing_gc.py +26 -0
  292. warp/tests/aux_test_module_unload.py +23 -0
  293. warp/tests/aux_test_name_clash1.py +40 -0
  294. warp/tests/aux_test_name_clash2.py +40 -0
  295. warp/tests/aux_test_reference.py +9 -0
  296. warp/tests/aux_test_reference_reference.py +8 -0
  297. warp/tests/aux_test_square.py +16 -0
  298. warp/tests/aux_test_unresolved_func.py +22 -0
  299. warp/tests/aux_test_unresolved_symbol.py +22 -0
  300. warp/tests/cuda/__init__.py +0 -0
  301. warp/tests/cuda/test_async.py +676 -0
  302. warp/tests/cuda/test_ipc.py +124 -0
  303. warp/tests/cuda/test_mempool.py +233 -0
  304. warp/tests/cuda/test_multigpu.py +169 -0
  305. warp/tests/cuda/test_peer.py +139 -0
  306. warp/tests/cuda/test_pinned.py +84 -0
  307. warp/tests/cuda/test_streams.py +634 -0
  308. warp/tests/geometry/__init__.py +0 -0
  309. warp/tests/geometry/test_bvh.py +200 -0
  310. warp/tests/geometry/test_hash_grid.py +221 -0
  311. warp/tests/geometry/test_marching_cubes.py +74 -0
  312. warp/tests/geometry/test_mesh.py +316 -0
  313. warp/tests/geometry/test_mesh_query_aabb.py +399 -0
  314. warp/tests/geometry/test_mesh_query_point.py +932 -0
  315. warp/tests/geometry/test_mesh_query_ray.py +311 -0
  316. warp/tests/geometry/test_volume.py +1103 -0
  317. warp/tests/geometry/test_volume_write.py +346 -0
  318. warp/tests/interop/__init__.py +0 -0
  319. warp/tests/interop/test_dlpack.py +729 -0
  320. warp/tests/interop/test_jax.py +371 -0
  321. warp/tests/interop/test_paddle.py +800 -0
  322. warp/tests/interop/test_torch.py +1001 -0
  323. warp/tests/run_coverage_serial.py +39 -0
  324. warp/tests/sim/__init__.py +0 -0
  325. warp/tests/sim/disabled_kinematics.py +244 -0
  326. warp/tests/sim/flaky_test_sim_grad.py +290 -0
  327. warp/tests/sim/test_collision.py +604 -0
  328. warp/tests/sim/test_coloring.py +258 -0
  329. warp/tests/sim/test_model.py +224 -0
  330. warp/tests/sim/test_sim_grad_bounce_linear.py +212 -0
  331. warp/tests/sim/test_sim_kinematics.py +98 -0
  332. warp/tests/sim/test_vbd.py +597 -0
  333. warp/tests/test_adam.py +163 -0
  334. warp/tests/test_arithmetic.py +1096 -0
  335. warp/tests/test_array.py +2972 -0
  336. warp/tests/test_array_reduce.py +156 -0
  337. warp/tests/test_assert.py +250 -0
  338. warp/tests/test_atomic.py +153 -0
  339. warp/tests/test_bool.py +220 -0
  340. warp/tests/test_builtins_resolution.py +1298 -0
  341. warp/tests/test_closest_point_edge_edge.py +327 -0
  342. warp/tests/test_codegen.py +810 -0
  343. warp/tests/test_codegen_instancing.py +1495 -0
  344. warp/tests/test_compile_consts.py +215 -0
  345. warp/tests/test_conditional.py +252 -0
  346. warp/tests/test_context.py +42 -0
  347. warp/tests/test_copy.py +238 -0
  348. warp/tests/test_ctypes.py +638 -0
  349. warp/tests/test_dense.py +73 -0
  350. warp/tests/test_devices.py +97 -0
  351. warp/tests/test_examples.py +482 -0
  352. warp/tests/test_fabricarray.py +996 -0
  353. warp/tests/test_fast_math.py +74 -0
  354. warp/tests/test_fem.py +2003 -0
  355. warp/tests/test_fp16.py +136 -0
  356. warp/tests/test_func.py +454 -0
  357. warp/tests/test_future_annotations.py +98 -0
  358. warp/tests/test_generics.py +656 -0
  359. warp/tests/test_grad.py +893 -0
  360. warp/tests/test_grad_customs.py +339 -0
  361. warp/tests/test_grad_debug.py +341 -0
  362. warp/tests/test_implicit_init.py +411 -0
  363. warp/tests/test_import.py +45 -0
  364. warp/tests/test_indexedarray.py +1140 -0
  365. warp/tests/test_intersect.py +73 -0
  366. warp/tests/test_iter.py +76 -0
  367. warp/tests/test_large.py +177 -0
  368. warp/tests/test_launch.py +411 -0
  369. warp/tests/test_lerp.py +151 -0
  370. warp/tests/test_linear_solvers.py +193 -0
  371. warp/tests/test_lvalue.py +427 -0
  372. warp/tests/test_mat.py +2089 -0
  373. warp/tests/test_mat_lite.py +122 -0
  374. warp/tests/test_mat_scalar_ops.py +2913 -0
  375. warp/tests/test_math.py +178 -0
  376. warp/tests/test_mlp.py +282 -0
  377. warp/tests/test_module_hashing.py +258 -0
  378. warp/tests/test_modules_lite.py +44 -0
  379. warp/tests/test_noise.py +252 -0
  380. warp/tests/test_operators.py +299 -0
  381. warp/tests/test_options.py +129 -0
  382. warp/tests/test_overwrite.py +551 -0
  383. warp/tests/test_print.py +339 -0
  384. warp/tests/test_quat.py +2315 -0
  385. warp/tests/test_rand.py +339 -0
  386. warp/tests/test_reload.py +302 -0
  387. warp/tests/test_rounding.py +185 -0
  388. warp/tests/test_runlength_encode.py +196 -0
  389. warp/tests/test_scalar_ops.py +105 -0
  390. warp/tests/test_smoothstep.py +108 -0
  391. warp/tests/test_snippet.py +318 -0
  392. warp/tests/test_sparse.py +582 -0
  393. warp/tests/test_spatial.py +2229 -0
  394. warp/tests/test_special_values.py +361 -0
  395. warp/tests/test_static.py +592 -0
  396. warp/tests/test_struct.py +734 -0
  397. warp/tests/test_tape.py +204 -0
  398. warp/tests/test_transient_module.py +93 -0
  399. warp/tests/test_triangle_closest_point.py +145 -0
  400. warp/tests/test_types.py +562 -0
  401. warp/tests/test_utils.py +588 -0
  402. warp/tests/test_vec.py +1487 -0
  403. warp/tests/test_vec_lite.py +80 -0
  404. warp/tests/test_vec_scalar_ops.py +2327 -0
  405. warp/tests/test_verify_fp.py +100 -0
  406. warp/tests/tile/__init__.py +0 -0
  407. warp/tests/tile/test_tile.py +780 -0
  408. warp/tests/tile/test_tile_load.py +407 -0
  409. warp/tests/tile/test_tile_mathdx.py +208 -0
  410. warp/tests/tile/test_tile_mlp.py +402 -0
  411. warp/tests/tile/test_tile_reduce.py +447 -0
  412. warp/tests/tile/test_tile_shared_memory.py +247 -0
  413. warp/tests/tile/test_tile_view.py +173 -0
  414. warp/tests/unittest_serial.py +47 -0
  415. warp/tests/unittest_suites.py +427 -0
  416. warp/tests/unittest_utils.py +468 -0
  417. warp/tests/walkthrough_debug.py +93 -0
  418. warp/thirdparty/__init__.py +0 -0
  419. warp/thirdparty/appdirs.py +598 -0
  420. warp/thirdparty/dlpack.py +145 -0
  421. warp/thirdparty/unittest_parallel.py +570 -0
  422. warp/torch.py +391 -0
  423. warp/types.py +5230 -0
  424. warp/utils.py +1137 -0
  425. warp_lang-1.7.0.dist-info/METADATA +516 -0
  426. warp_lang-1.7.0.dist-info/RECORD +429 -0
  427. warp_lang-1.7.0.dist-info/WHEEL +5 -0
  428. warp_lang-1.7.0.dist-info/licenses/LICENSE.md +202 -0
  429. warp_lang-1.7.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,926 @@
1
+ # SPDX-FileCopyrightText: Copyright (c) 2023 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
+ import math
17
+
18
+ import numpy as np
19
+
20
+ import warp as wp
21
+ from warp.fem import cache
22
+ from warp.fem.polynomial import Polynomial, is_closed, lagrange_scales, quadrature_1d
23
+ from warp.fem.types import Coords
24
+
25
+ from .shape_function import ShapeFunction
26
+ from .triangle_shape_function import TrianglePolynomialShapeFunctions
27
+
28
+
29
+ class SquareShapeFunction(ShapeFunction):
30
+ VERTEX = 0
31
+ EDGE_X = 1
32
+ EDGE_Y = 2
33
+ INTERIOR = 3
34
+
35
+ VERTEX_NODE_COUNT: int
36
+ """Number of shape function nodes per vertex"""
37
+
38
+ EDGE_NODE_COUNT: int
39
+ """Number of shape function nodes per triangle edge (excluding vertex nodes)"""
40
+
41
+ INTERIOR_NODE_COUNT: int
42
+ """Number of shape function nodes per triangle (excluding edge and vertex nodes)"""
43
+
44
+ @wp.func
45
+ def _vertex_coords_f(vidx_in_cell: int):
46
+ x = vidx_in_cell // 2
47
+ y = vidx_in_cell - 2 * x
48
+ return wp.vec2(float(x), float(y))
49
+
50
+
51
+ class SquareBipolynomialShapeFunctions(SquareShapeFunction):
52
+ def __init__(self, degree: int, family: Polynomial):
53
+ self.family = family
54
+
55
+ self.ORDER = wp.constant(degree)
56
+ self.NODES_PER_ELEMENT = wp.constant((degree + 1) * (degree + 1))
57
+ self.NODES_PER_SIDE = wp.constant(degree + 1)
58
+
59
+ if is_closed(self.family):
60
+ self.VERTEX_NODE_COUNT = wp.constant(1)
61
+ self.EDGE_NODE_COUNT = wp.constant(max(0, degree - 1))
62
+ self.INTERIOR_NODE_COUNT = wp.constant(max(0, degree - 1) ** 2)
63
+ else:
64
+ self.VERTEX_NODE_COUNT = wp.constant(0)
65
+ self.EDGE_NODE_COUNT = wp.constant(0)
66
+ self.INTERIOR_NODE_COUNT = self.NODES_PER_ELEMENT
67
+
68
+ lobatto_coords, lobatto_weight = quadrature_1d(point_count=degree + 1, family=family)
69
+ lagrange_scale = lagrange_scales(lobatto_coords)
70
+
71
+ NodeVec = wp.types.vector(length=degree + 1, dtype=wp.float32)
72
+ self.LOBATTO_COORDS = wp.constant(NodeVec(lobatto_coords))
73
+ self.LOBATTO_WEIGHT = wp.constant(NodeVec(lobatto_weight))
74
+ self.LAGRANGE_SCALE = wp.constant(NodeVec(lagrange_scale))
75
+ self.ORDER_PLUS_ONE = wp.constant(self.ORDER + 1)
76
+
77
+ self._node_ij = self._make_node_ij()
78
+ self.node_type_and_type_index = self._make_node_type_and_type_index()
79
+
80
+ @property
81
+ def name(self) -> str:
82
+ return f"Square_Q{self.ORDER}_{self.family}"
83
+
84
+ def _make_node_ij(self):
85
+ ORDER_PLUS_ONE = self.ORDER_PLUS_ONE
86
+
87
+ def node_ij(node_index_in_elt: int):
88
+ node_i = node_index_in_elt // ORDER_PLUS_ONE
89
+ node_j = node_index_in_elt - ORDER_PLUS_ONE * node_i
90
+ return node_i, node_j
91
+
92
+ return cache.get_func(node_ij, self.name)
93
+
94
+ def _make_node_type_and_type_index(self):
95
+ ORDER = self.ORDER
96
+
97
+ @cache.dynamic_func(suffix=self.name)
98
+ def node_type_and_type_index_open(
99
+ node_index_in_elt: int,
100
+ ):
101
+ return SquareShapeFunction.INTERIOR, 0, node_index_in_elt
102
+
103
+ @cache.dynamic_func(suffix=self.name)
104
+ def node_type_and_type_index(
105
+ node_index_in_elt: int,
106
+ ):
107
+ i, j = self._node_ij(node_index_in_elt)
108
+
109
+ zi = int(i == 0)
110
+ zj = int(j == 0)
111
+
112
+ mi = int(i == ORDER)
113
+ mj = int(j == ORDER)
114
+
115
+ if zi + mi == 1:
116
+ if zj + mj == 1:
117
+ # vertex
118
+ type_instance = mi * 2 + mj
119
+ return SquareShapeFunction.VERTEX, type_instance, 0
120
+ # y edge
121
+ type_index = j - 1
122
+ type_instance = mi
123
+ return SquareShapeFunction.EDGE_Y, type_instance, type_index
124
+ elif zj + mj == 1:
125
+ # x edge
126
+ type_index = i - 1
127
+ type_instance = mj
128
+ return SquareShapeFunction.EDGE_X, type_instance, type_index
129
+
130
+ type_index = (i - 1) * (ORDER - 1) + (j - 1)
131
+ return SquareShapeFunction.INTERIOR, 0, type_index
132
+
133
+ return node_type_and_type_index if is_closed(self.family) else node_type_and_type_index_open
134
+
135
+ def make_node_coords_in_element(self):
136
+ LOBATTO_COORDS = self.LOBATTO_COORDS
137
+
138
+ @cache.dynamic_func(suffix=self.name)
139
+ def node_coords_in_element(
140
+ node_index_in_elt: int,
141
+ ):
142
+ node_i, node_j = self._node_ij(node_index_in_elt)
143
+ return Coords(LOBATTO_COORDS[node_i], LOBATTO_COORDS[node_j], 0.0)
144
+
145
+ return node_coords_in_element
146
+
147
+ def make_node_quadrature_weight(self):
148
+ ORDER = self.ORDER
149
+ LOBATTO_WEIGHT = self.LOBATTO_WEIGHT
150
+
151
+ def node_quadrature_weight(
152
+ node_index_in_elt: int,
153
+ ):
154
+ node_i, node_j = self._node_ij(node_index_in_elt)
155
+ return LOBATTO_WEIGHT[node_i] * LOBATTO_WEIGHT[node_j]
156
+
157
+ def node_quadrature_weight_linear(
158
+ node_index_in_elt: int,
159
+ ):
160
+ return 0.25
161
+
162
+ if ORDER == 1:
163
+ return cache.get_func(node_quadrature_weight_linear, self.name)
164
+
165
+ return cache.get_func(node_quadrature_weight, self.name)
166
+
167
+ def make_trace_node_quadrature_weight(self):
168
+ ORDER = self.ORDER
169
+ LOBATTO_WEIGHT = self.LOBATTO_WEIGHT
170
+
171
+ def trace_node_quadrature_weight(
172
+ node_index_in_elt: int,
173
+ ):
174
+ # We're either on a side interior or at a vertex
175
+ # I.e., either both indices are at extrema, or only one is
176
+ # Pick the interior one if possible, if both are at extrema pick any one
177
+ node_i, node_j = self._node_ij(node_index_in_elt)
178
+ if node_i > 0 and node_i < ORDER:
179
+ return LOBATTO_WEIGHT[node_i]
180
+
181
+ return LOBATTO_WEIGHT[node_j]
182
+
183
+ def trace_node_quadrature_weight_linear(
184
+ node_index_in_elt: int,
185
+ ):
186
+ return 0.5
187
+
188
+ def trace_node_quadrature_weight_open(
189
+ node_index_in_elt: int,
190
+ ):
191
+ return 0.0
192
+
193
+ if not is_closed(self.family):
194
+ return cache.get_func(trace_node_quadrature_weight_open, self.name)
195
+
196
+ if ORDER == 1:
197
+ return cache.get_func(trace_node_quadrature_weight_linear, self.name)
198
+
199
+ return cache.get_func(trace_node_quadrature_weight, self.name)
200
+
201
+ def make_element_inner_weight(self):
202
+ ORDER_PLUS_ONE = self.ORDER_PLUS_ONE
203
+ LOBATTO_COORDS = self.LOBATTO_COORDS
204
+ LAGRANGE_SCALE = self.LAGRANGE_SCALE
205
+
206
+ def element_inner_weight(
207
+ coords: Coords,
208
+ node_index_in_elt: int,
209
+ ):
210
+ node_i, node_j = self._node_ij(node_index_in_elt)
211
+
212
+ w = float(1.0)
213
+ for k in range(ORDER_PLUS_ONE):
214
+ if k != node_i:
215
+ w *= coords[0] - LOBATTO_COORDS[k]
216
+ if k != node_j:
217
+ w *= coords[1] - LOBATTO_COORDS[k]
218
+
219
+ w *= LAGRANGE_SCALE[node_i] * LAGRANGE_SCALE[node_j]
220
+
221
+ return w
222
+
223
+ def element_inner_weight_linear(
224
+ coords: Coords,
225
+ node_index_in_elt: int,
226
+ ):
227
+ v = SquareBipolynomialShapeFunctions._vertex_coords_f(node_index_in_elt)
228
+
229
+ wx = (1.0 - coords[0]) * (1.0 - v[0]) + v[0] * coords[0]
230
+ wy = (1.0 - coords[1]) * (1.0 - v[1]) + v[1] * coords[1]
231
+ return wx * wy
232
+
233
+ if self.ORDER == 1 and is_closed(self.family):
234
+ return cache.get_func(element_inner_weight_linear, self.name)
235
+
236
+ return cache.get_func(element_inner_weight, self.name)
237
+
238
+ def make_element_inner_weight_gradient(self):
239
+ ORDER_PLUS_ONE = self.ORDER_PLUS_ONE
240
+ LOBATTO_COORDS = self.LOBATTO_COORDS
241
+ LAGRANGE_SCALE = self.LAGRANGE_SCALE
242
+
243
+ def element_inner_weight_gradient(
244
+ coords: Coords,
245
+ node_index_in_elt: int,
246
+ ):
247
+ node_i, node_j = self._node_ij(node_index_in_elt)
248
+
249
+ prefix_x = float(1.0)
250
+ prefix_y = float(1.0)
251
+ for k in range(ORDER_PLUS_ONE):
252
+ if k != node_i:
253
+ prefix_y *= coords[0] - LOBATTO_COORDS[k]
254
+ if k != node_j:
255
+ prefix_x *= coords[1] - LOBATTO_COORDS[k]
256
+
257
+ grad_x = float(0.0)
258
+ grad_y = float(0.0)
259
+
260
+ for k in range(ORDER_PLUS_ONE):
261
+ if k != node_i:
262
+ delta_x = coords[0] - LOBATTO_COORDS[k]
263
+ grad_x = grad_x * delta_x + prefix_x
264
+ prefix_x *= delta_x
265
+ if k != node_j:
266
+ delta_y = coords[1] - LOBATTO_COORDS[k]
267
+ grad_y = grad_y * delta_y + prefix_y
268
+ prefix_y *= delta_y
269
+
270
+ grad = LAGRANGE_SCALE[node_i] * LAGRANGE_SCALE[node_j] * wp.vec2(grad_x, grad_y)
271
+
272
+ return grad
273
+
274
+ def element_inner_weight_gradient_linear(
275
+ coords: Coords,
276
+ node_index_in_elt: int,
277
+ ):
278
+ v = SquareBipolynomialShapeFunctions._vertex_coords_f(node_index_in_elt)
279
+
280
+ wx = (1.0 - coords[0]) * (1.0 - v[0]) + v[0] * coords[0]
281
+ wy = (1.0 - coords[1]) * (1.0 - v[1]) + v[1] * coords[1]
282
+
283
+ dx = 2.0 * v[0] - 1.0
284
+ dy = 2.0 * v[1] - 1.0
285
+
286
+ return wp.vec2(dx * wy, dy * wx)
287
+
288
+ if self.ORDER == 1 and is_closed(self.family):
289
+ return cache.get_func(element_inner_weight_gradient_linear, self.name)
290
+
291
+ return cache.get_func(element_inner_weight_gradient, self.name)
292
+
293
+ def element_node_triangulation(self):
294
+ from warp.fem.utils import grid_to_tris
295
+
296
+ return grid_to_tris(self.ORDER, self.ORDER)
297
+
298
+ def element_vtk_cells(self):
299
+ n = self.ORDER + 1
300
+
301
+ # vertices
302
+ cells = [[0, (n - 1) * n, n * n - 1, n - 1]]
303
+
304
+ if self.ORDER == 1:
305
+ cell_type = 9 # VTK_QUAD
306
+ else:
307
+ middle = np.arange(1, n - 1)
308
+
309
+ # edges
310
+ cells.append(middle * n)
311
+ cells.append(middle + (n - 1) * n)
312
+ cells.append(middle * n + n - 1)
313
+ cells.append(middle)
314
+
315
+ # faces
316
+ interior = np.broadcast_to(middle, (n - 2, n - 2))
317
+ cells.append((interior * n + interior.transpose()).flatten())
318
+
319
+ cell_type = 70 # VTK_LAGRANGE_QUADRILATERAL
320
+
321
+ return np.concatenate(cells)[np.newaxis, :], np.array([cell_type], dtype=np.int8)
322
+
323
+
324
+ class SquareSerendipityShapeFunctions(SquareShapeFunction):
325
+ """
326
+ Serendipity element ~ tensor product space without interior nodes
327
+ Side shape functions are usual Lagrange shape functions times a linear function in the normal direction
328
+ Corner shape functions are bilinear shape functions times a function of (x^{d-1} + y^{d-1})
329
+ """
330
+
331
+ def __init__(self, degree: int, family: Polynomial):
332
+ if not is_closed(family):
333
+ raise ValueError("A closed polynomial family is required to define serendipity elements")
334
+
335
+ if degree not in [2, 3]:
336
+ raise NotImplementedError("Serendipity element only implemented for order 2 or 3")
337
+
338
+ self.family = family
339
+
340
+ self.ORDER = wp.constant(degree)
341
+ self.NODES_PER_ELEMENT = wp.constant(4 * degree)
342
+ self.NODES_PER_SIDE = wp.constant(degree + 1)
343
+
344
+ self.VERTEX_NODE_COUNT = wp.constant(1)
345
+ self.EDGE_NODE_COUNT = wp.constant(degree - 1)
346
+ self.INTERIOR_NODE_COUNT = wp.constant(0)
347
+
348
+ lobatto_coords, lobatto_weight = quadrature_1d(point_count=degree + 1, family=family)
349
+ lagrange_scale = lagrange_scales(lobatto_coords)
350
+
351
+ NodeVec = wp.types.vector(length=degree + 1, dtype=wp.float32)
352
+ self.LOBATTO_COORDS = wp.constant(NodeVec(lobatto_coords))
353
+ self.LOBATTO_WEIGHT = wp.constant(NodeVec(lobatto_weight))
354
+ self.LAGRANGE_SCALE = wp.constant(NodeVec(lagrange_scale))
355
+ self.ORDER_PLUS_ONE = wp.constant(self.ORDER + 1)
356
+
357
+ self.node_type_and_type_index = self._get_node_type_and_type_index()
358
+ self._node_lobatto_indices = self._get_node_lobatto_indices()
359
+
360
+ @property
361
+ def name(self) -> str:
362
+ return f"Square_S{self.ORDER}_{self.family}"
363
+
364
+ def _get_node_type_and_type_index(self):
365
+ @cache.dynamic_func(suffix=self.name)
366
+ def node_type_and_index(
367
+ node_index_in_elt: int,
368
+ ):
369
+ if node_index_in_elt < 4:
370
+ return SquareSerendipityShapeFunctions.VERTEX, node_index_in_elt, 0
371
+
372
+ edge_index = (node_index_in_elt - 4) // 2
373
+ edge_axis = node_index_in_elt - 4 - 2 * edge_index
374
+
375
+ index_in_side = edge_index // 2
376
+ side_offset = edge_index - 2 * index_in_side
377
+ return SquareSerendipityShapeFunctions.EDGE_X + edge_axis, side_offset, index_in_side
378
+
379
+ return node_type_and_index
380
+
381
+ def _get_node_lobatto_indices(self):
382
+ ORDER = self.ORDER
383
+
384
+ @cache.dynamic_func(suffix=self.name)
385
+ def node_lobatto_indices(node_type: int, type_instance: int, type_index: int):
386
+ if node_type == SquareSerendipityShapeFunctions.VERTEX:
387
+ node_i = type_instance // 2
388
+ node_j = type_instance - 2 * node_i
389
+ return node_i * ORDER, node_j * ORDER
390
+
391
+ if node_type == SquareSerendipityShapeFunctions.EDGE_X:
392
+ node_i = 1 + type_index
393
+ node_j = type_instance * ORDER
394
+ else:
395
+ node_j = 1 + type_index
396
+ node_i = type_instance * ORDER
397
+
398
+ return node_i, node_j
399
+
400
+ return node_lobatto_indices
401
+
402
+ def make_node_coords_in_element(self):
403
+ LOBATTO_COORDS = self.LOBATTO_COORDS
404
+
405
+ @cache.dynamic_func(suffix=self.name)
406
+ def node_coords_in_element(
407
+ node_index_in_elt: int,
408
+ ):
409
+ node_type, type_instance, type_index = self.node_type_and_type_index(node_index_in_elt)
410
+ node_i, node_j = self._node_lobatto_indices(node_type, type_instance, type_index)
411
+ return Coords(LOBATTO_COORDS[node_i], LOBATTO_COORDS[node_j], 0.0)
412
+
413
+ return node_coords_in_element
414
+
415
+ def make_node_quadrature_weight(self):
416
+ ORDER = self.ORDER
417
+
418
+ @cache.dynamic_func(suffix=self.name)
419
+ def node_quadrature_weight(
420
+ node_index_in_elt: int,
421
+ ):
422
+ node_type, type_instance, type_index = self.node_type_and_type_index(node_index_in_elt)
423
+ if node_type == SquareSerendipityShapeFunctions.VERTEX:
424
+ return 0.25 / float(ORDER * ORDER)
425
+
426
+ return (0.25 - 0.25 / float(ORDER * ORDER)) / float(ORDER - 1)
427
+
428
+ return node_quadrature_weight
429
+
430
+ def make_trace_node_quadrature_weight(self):
431
+ LOBATTO_WEIGHT = self.LOBATTO_WEIGHT
432
+
433
+ @cache.dynamic_func(suffix=self.name)
434
+ def trace_node_quadrature_weight(
435
+ node_index_in_elt: int,
436
+ ):
437
+ node_type, type_instance, type_index = self.node_type_and_type_index(node_index_in_elt)
438
+ if node_type == SquareSerendipityShapeFunctions.VERTEX:
439
+ return LOBATTO_WEIGHT[0]
440
+
441
+ return LOBATTO_WEIGHT[1 + type_index]
442
+
443
+ return trace_node_quadrature_weight
444
+
445
+ def make_element_inner_weight(self):
446
+ ORDER = self.ORDER
447
+ ORDER_PLUS_ONE = self.ORDER_PLUS_ONE
448
+
449
+ LOBATTO_COORDS = self.LOBATTO_COORDS
450
+ LAGRANGE_SCALE = self.LAGRANGE_SCALE
451
+
452
+ DEGREE_3_CIRCLE_RAD = wp.constant(0.5**2 + (0.5 - LOBATTO_COORDS[1]) ** 2)
453
+ DEGREE_3_CIRCLE_SCALE = 1.0 / (0.5 - DEGREE_3_CIRCLE_RAD)
454
+
455
+ @cache.dynamic_func(suffix=self.name)
456
+ def element_inner_weight(
457
+ coords: Coords,
458
+ node_index_in_elt: int,
459
+ ):
460
+ node_type, type_instance, type_index = self.node_type_and_type_index(node_index_in_elt)
461
+ node_i, node_j = self._node_lobatto_indices(node_type, type_instance, type_index)
462
+
463
+ if node_type == SquareSerendipityShapeFunctions.VERTEX:
464
+ cx = wp.where(node_i == 0, 1.0 - coords[0], coords[0])
465
+ cy = wp.where(node_j == 0, 1.0 - coords[1], coords[1])
466
+
467
+ w = cx * cy
468
+
469
+ if ORDER == 2:
470
+ w *= cx + cy - 2.0 + LOBATTO_COORDS[1]
471
+ return w * LAGRANGE_SCALE[0]
472
+ if ORDER == 3:
473
+ w *= (cx - 0.5) * (cx - 0.5) + (cy - 0.5) * (cy - 0.5) - DEGREE_3_CIRCLE_RAD
474
+ return w * DEGREE_3_CIRCLE_SCALE
475
+
476
+ w = float(1.0)
477
+ if node_type == SquareSerendipityShapeFunctions.EDGE_Y:
478
+ w *= wp.where(node_i == 0, 1.0 - coords[0], coords[0])
479
+ else:
480
+ for k in range(ORDER_PLUS_ONE):
481
+ if k != node_i:
482
+ w *= coords[0] - LOBATTO_COORDS[k]
483
+
484
+ w *= LAGRANGE_SCALE[node_i]
485
+
486
+ if node_type == SquareSerendipityShapeFunctions.EDGE_X:
487
+ w *= wp.where(node_j == 0, 1.0 - coords[1], coords[1])
488
+ else:
489
+ for k in range(ORDER_PLUS_ONE):
490
+ if k != node_j:
491
+ w *= coords[1] - LOBATTO_COORDS[k]
492
+ w *= LAGRANGE_SCALE[node_j]
493
+
494
+ return w
495
+
496
+ return element_inner_weight
497
+
498
+ def make_element_inner_weight_gradient(self):
499
+ ORDER = self.ORDER
500
+ ORDER_PLUS_ONE = self.ORDER_PLUS_ONE
501
+ LOBATTO_COORDS = self.LOBATTO_COORDS
502
+ LAGRANGE_SCALE = self.LAGRANGE_SCALE
503
+
504
+ DEGREE_3_CIRCLE_RAD = wp.constant(0.5**2 + (0.5 - LOBATTO_COORDS[1]) ** 2)
505
+ DEGREE_3_CIRCLE_SCALE = 1.0 / (0.5 - DEGREE_3_CIRCLE_RAD)
506
+
507
+ @cache.dynamic_func(suffix=self.name)
508
+ def element_inner_weight_gradient(
509
+ coords: Coords,
510
+ node_index_in_elt: int,
511
+ ):
512
+ node_type, type_instance, type_index = self.node_type_and_type_index(node_index_in_elt)
513
+ node_i, node_j = self._node_lobatto_indices(node_type, type_instance, type_index)
514
+
515
+ if node_type == SquareSerendipityShapeFunctions.VERTEX:
516
+ cx = wp.where(node_i == 0, 1.0 - coords[0], coords[0])
517
+ cy = wp.where(node_j == 0, 1.0 - coords[1], coords[1])
518
+
519
+ gx = wp.where(node_i == 0, -1.0, 1.0)
520
+ gy = wp.where(node_j == 0, -1.0, 1.0)
521
+
522
+ if ORDER == 2:
523
+ w = cx + cy - 2.0 + LOBATTO_COORDS[1]
524
+ grad_x = cy * gx * (w + cx)
525
+ grad_y = cx * gy * (w + cy)
526
+
527
+ return wp.vec2(grad_x, grad_y) * LAGRANGE_SCALE[0]
528
+
529
+ if ORDER == 3:
530
+ w = (cx - 0.5) * (cx - 0.5) + (cy - 0.5) * (cy - 0.5) - DEGREE_3_CIRCLE_RAD
531
+
532
+ dw_dcx = 2.0 * cx - 1.0
533
+ dw_dcy = 2.0 * cy - 1.0
534
+ grad_x = cy * gx * (w + cx * dw_dcx)
535
+ grad_y = cx * gy * (w + cy * dw_dcy)
536
+
537
+ return wp.vec2(grad_x, grad_y) * DEGREE_3_CIRCLE_SCALE
538
+
539
+ if node_type == SquareSerendipityShapeFunctions.EDGE_X:
540
+ prefix_x = wp.where(node_j == 0, 1.0 - coords[1], coords[1])
541
+ else:
542
+ prefix_x = LAGRANGE_SCALE[node_j]
543
+ for k in range(ORDER_PLUS_ONE):
544
+ if k != node_j:
545
+ prefix_x *= coords[1] - LOBATTO_COORDS[k]
546
+
547
+ if node_type == SquareSerendipityShapeFunctions.EDGE_Y:
548
+ prefix_y = wp.where(node_i == 0, 1.0 - coords[0], coords[0])
549
+ else:
550
+ prefix_y = LAGRANGE_SCALE[node_i]
551
+ for k in range(ORDER_PLUS_ONE):
552
+ if k != node_i:
553
+ prefix_y *= coords[0] - LOBATTO_COORDS[k]
554
+
555
+ if node_type == SquareSerendipityShapeFunctions.EDGE_X:
556
+ grad_y = wp.where(node_j == 0, -1.0, 1.0) * prefix_y
557
+ else:
558
+ prefix_y *= LAGRANGE_SCALE[node_j]
559
+ grad_y = float(0.0)
560
+ for k in range(ORDER_PLUS_ONE):
561
+ if k != node_j:
562
+ delta_y = coords[1] - LOBATTO_COORDS[k]
563
+ grad_y = grad_y * delta_y + prefix_y
564
+ prefix_y *= delta_y
565
+
566
+ if node_type == SquareSerendipityShapeFunctions.EDGE_Y:
567
+ grad_x = wp.where(node_i == 0, -1.0, 1.0) * prefix_x
568
+ else:
569
+ prefix_x *= LAGRANGE_SCALE[node_i]
570
+ grad_x = float(0.0)
571
+ for k in range(ORDER_PLUS_ONE):
572
+ if k != node_i:
573
+ delta_x = coords[0] - LOBATTO_COORDS[k]
574
+ grad_x = grad_x * delta_x + prefix_x
575
+ prefix_x *= delta_x
576
+
577
+ grad = wp.vec2(grad_x, grad_y)
578
+ return grad
579
+
580
+ return element_inner_weight_gradient
581
+
582
+ def element_node_triangulation(self):
583
+ if self.ORDER == 2:
584
+ element_triangles = [
585
+ [0, 4, 5],
586
+ [5, 4, 6],
587
+ [5, 6, 1],
588
+ [4, 2, 7],
589
+ [4, 7, 6],
590
+ [6, 7, 3],
591
+ ]
592
+ else:
593
+ element_triangles = [
594
+ [0, 4, 5],
595
+ [2, 7, 8],
596
+ [3, 10, 11],
597
+ [1, 9, 6],
598
+ [5, 6, 9],
599
+ [5, 4, 6],
600
+ [8, 11, 10],
601
+ [8, 7, 11],
602
+ [4, 8, 10],
603
+ [4, 10, 6],
604
+ ]
605
+
606
+ return element_triangles
607
+
608
+ def element_vtk_cells(self):
609
+ tris = np.array(self.element_node_triangulation())
610
+ cell_type = 5 # VTK_TRIANGLE
611
+
612
+ return tris, np.full(tris.shape[0], cell_type, dtype=np.int8)
613
+
614
+
615
+ class SquareNonConformingPolynomialShapeFunctions(ShapeFunction):
616
+ # embeds the largest equilateral triangle centered at (0.5, 0.5) into the reference square
617
+ _tri_height = 0.75
618
+ _tri_side = 2.0 / math.sqrt(3.0) * _tri_height
619
+ _tri_to_square = np.array([[_tri_side, _tri_side / 2.0], [0.0, _tri_height]])
620
+
621
+ _TRI_OFFSET = wp.constant(wp.vec2(0.5 - 0.5 * _tri_side, 0.5 - _tri_height / 3.0))
622
+
623
+ def __init__(self, degree: int):
624
+ self._tri_shape = TrianglePolynomialShapeFunctions(degree=degree)
625
+ self.ORDER = self._tri_shape.ORDER
626
+ self.NODES_PER_ELEMENT = self._tri_shape.NODES_PER_ELEMENT
627
+
628
+ self.element_node_triangulation = self._tri_shape.element_node_triangulation
629
+ self.element_vtk_cells = self._tri_shape.element_vtk_cells
630
+
631
+ @property
632
+ def name(self) -> str:
633
+ return f"Square_P{self.ORDER}d"
634
+
635
+ def make_node_coords_in_element(self):
636
+ node_coords_in_tet = self._tri_shape.make_node_coords_in_element()
637
+
638
+ TRI_TO_SQUARE = wp.constant(wp.mat22(self._tri_to_square))
639
+
640
+ @cache.dynamic_func(suffix=self.name)
641
+ def node_coords_in_element(
642
+ node_index_in_elt: int,
643
+ ):
644
+ tri_coords = node_coords_in_tet(node_index_in_elt)
645
+ coords = (
646
+ TRI_TO_SQUARE * wp.vec2(tri_coords[1], tri_coords[2])
647
+ ) + SquareNonConformingPolynomialShapeFunctions._TRI_OFFSET
648
+ return Coords(coords[0], coords[1], 0.0)
649
+
650
+ return node_coords_in_element
651
+
652
+ def make_node_quadrature_weight(self):
653
+ NODES_PER_ELEMENT = self.NODES_PER_ELEMENT
654
+
655
+ if self.ORDER == 2:
656
+ # Intrinsic quadrature (order 2)
657
+ @cache.dynamic_func(suffix=self.name)
658
+ def node_quadrature_weight_quadratic(
659
+ node_index_in_elt: int,
660
+ ):
661
+ node_type, type_index = self._tri_shape.node_type_and_type_index(node_index_in_elt)
662
+ if node_type == TrianglePolynomialShapeFunctions.VERTEX:
663
+ return 0.18518521
664
+ return 0.14814811
665
+
666
+ return node_quadrature_weight_quadratic
667
+
668
+ @cache.dynamic_func(suffix=self.name)
669
+ def node_uniform_quadrature_weight(
670
+ node_index_in_elt: int,
671
+ ):
672
+ return 1.0 / float(NODES_PER_ELEMENT)
673
+
674
+ return node_uniform_quadrature_weight
675
+
676
+ def make_trace_node_quadrature_weight(self):
677
+ # Non-conforming, zero measure on sides
678
+
679
+ @wp.func
680
+ def zero(node_index_in_elt: int):
681
+ return 0.0
682
+
683
+ return zero
684
+
685
+ def make_element_inner_weight(self):
686
+ tri_inner_weight = self._tri_shape.make_element_inner_weight()
687
+
688
+ SQUARE_TO_TRI = wp.constant(wp.mat22(np.linalg.inv(self._tri_to_square)))
689
+
690
+ @cache.dynamic_func(suffix=self.name)
691
+ def element_inner_weight(
692
+ coords: Coords,
693
+ node_index_in_elt: int,
694
+ ):
695
+ tri_param = SQUARE_TO_TRI * (
696
+ wp.vec2(coords[0], coords[1]) - SquareNonConformingPolynomialShapeFunctions._TRI_OFFSET
697
+ )
698
+ tri_coords = Coords(1.0 - tri_param[0] - tri_param[1], tri_param[0], tri_param[1])
699
+
700
+ return tri_inner_weight(tri_coords, node_index_in_elt)
701
+
702
+ return element_inner_weight
703
+
704
+ def make_element_inner_weight_gradient(self):
705
+ tri_inner_weight_gradient = self._tri_shape.make_element_inner_weight_gradient()
706
+
707
+ SQUARE_TO_TRI = wp.constant(wp.mat22(np.linalg.inv(self._tri_to_square)))
708
+
709
+ @cache.dynamic_func(suffix=self.name)
710
+ def element_inner_weight_gradient(
711
+ coords: Coords,
712
+ node_index_in_elt: int,
713
+ ):
714
+ tri_param = SQUARE_TO_TRI * (
715
+ wp.vec2(coords[0], coords[1]) - SquareNonConformingPolynomialShapeFunctions._TRI_OFFSET
716
+ )
717
+ tri_coords = Coords(1.0 - tri_param[0] - tri_param[1], tri_param[0], tri_param[1])
718
+
719
+ grad = tri_inner_weight_gradient(tri_coords, node_index_in_elt)
720
+ return wp.transpose(SQUARE_TO_TRI) * grad
721
+
722
+ return element_inner_weight_gradient
723
+
724
+
725
+ class SquareNedelecFirstKindShapeFunctions(SquareShapeFunction):
726
+ value = ShapeFunction.Value.CovariantVector
727
+
728
+ def __init__(self, degree: int):
729
+ if degree != 1:
730
+ raise NotImplementedError("Only linear Nédélec implemented right now")
731
+
732
+ self.ORDER = wp.constant(degree)
733
+ self.NODES_PER_ELEMENT = wp.constant(4)
734
+ self.NODES_PER_SIDE = wp.constant(1)
735
+
736
+ self.VERTEX_NODE_COUNT = wp.constant(0)
737
+ self.EDGE_NODE_COUNT = wp.constant(1)
738
+ self.INTERIOR_NODE_COUNT = wp.constant(0)
739
+
740
+ self.node_type_and_type_index = self._get_node_type_and_type_index()
741
+
742
+ @property
743
+ def name(self) -> str:
744
+ return f"SquareN1_{self.ORDER}"
745
+
746
+ def _get_node_type_and_type_index(self):
747
+ @cache.dynamic_func(suffix=self.name)
748
+ def node_type_and_index(
749
+ node_index_in_elt: int,
750
+ ):
751
+ axis = node_index_in_elt // 2
752
+ offset = node_index_in_elt - 2 * axis
753
+ return SquareShapeFunction.EDGE_X + axis, offset, 0
754
+
755
+ return node_type_and_index
756
+
757
+ def make_node_coords_in_element(self):
758
+ @cache.dynamic_func(suffix=self.name)
759
+ def node_coords_in_element(
760
+ node_index_in_elt: int,
761
+ ):
762
+ node_type, type_instance, type_index = self.node_type_and_type_index(node_index_in_elt)
763
+ axis = node_type - SquareShapeFunction.EDGE_X
764
+
765
+ coords = Coords()
766
+ coords[axis] = 0.5
767
+ coords[1 - axis] = float(type_instance)
768
+
769
+ return node_coords_in_element
770
+
771
+ def make_node_quadrature_weight(self):
772
+ NODES_PER_ELEMENT = self.NODES_PER_ELEMENT
773
+
774
+ @cache.dynamic_func(suffix=self.name)
775
+ def node_quadrature_weight(node_index_in_element: int):
776
+ return 1.0 / float(NODES_PER_ELEMENT)
777
+
778
+ return node_quadrature_weight
779
+
780
+ def make_trace_node_quadrature_weight(self):
781
+ NODES_PER_SIDE = self.NODES_PER_SIDE
782
+
783
+ @cache.dynamic_func(suffix=self.name)
784
+ def trace_node_quadrature_weight(node_index_in_element: int):
785
+ return 1.0 / float(NODES_PER_SIDE)
786
+
787
+ return trace_node_quadrature_weight
788
+
789
+ def make_element_inner_weight(self):
790
+ @cache.dynamic_func(suffix=self.name)
791
+ def element_inner_weight(
792
+ coords: Coords,
793
+ node_index_in_elt: int,
794
+ ):
795
+ node_type, type_instance, type_index = self.node_type_and_type_index(node_index_in_elt)
796
+
797
+ axis = node_type - SquareShapeFunction.EDGE_X
798
+ a = float(2 * type_instance - 1)
799
+ b = float(1 - type_instance)
800
+
801
+ w = wp.vec2(0.0)
802
+ w[axis] = b + a * coords[1 - axis]
803
+
804
+ return w
805
+
806
+ return element_inner_weight
807
+
808
+ def make_element_inner_weight_gradient(self):
809
+ @cache.dynamic_func(suffix=self.name)
810
+ def element_inner_weight_gradient(
811
+ coords: Coords,
812
+ node_index_in_elt: int,
813
+ ):
814
+ node_type, type_instance, type_index = self.node_type_and_type_index(node_index_in_elt)
815
+
816
+ axis = node_type - SquareShapeFunction.EDGE_X
817
+ a = float(2 * type_instance - 1)
818
+
819
+ grad = wp.mat22(0.0)
820
+ grad[axis, 1 - axis] = a
821
+
822
+ return grad
823
+
824
+ return element_inner_weight_gradient
825
+
826
+
827
+ class SquareRaviartThomasShapeFunctions(SquareShapeFunction):
828
+ value = ShapeFunction.Value.ContravariantVector
829
+
830
+ def __init__(self, degree: int):
831
+ if degree != 1:
832
+ raise NotImplementedError("Only linear Nédélec implemented right now")
833
+
834
+ self.ORDER = wp.constant(degree)
835
+ self.NODES_PER_ELEMENT = wp.constant(4)
836
+ self.NODES_PER_SIDE = wp.constant(1)
837
+
838
+ self.VERTEX_NODE_COUNT = wp.constant(0)
839
+ self.EDGE_NODE_COUNT = wp.constant(1)
840
+ self.INTERIOR_NODE_COUNT = wp.constant(0)
841
+
842
+ self.node_type_and_type_index = self._get_node_type_and_type_index()
843
+
844
+ @property
845
+ def name(self) -> str:
846
+ return f"SquareRT_{self.ORDER}"
847
+
848
+ def _get_node_type_and_type_index(self):
849
+ @cache.dynamic_func(suffix=self.name)
850
+ def node_type_and_index(
851
+ node_index_in_elt: int,
852
+ ):
853
+ axis = node_index_in_elt // 2
854
+ offset = node_index_in_elt - 2 * axis
855
+ return SquareShapeFunction.EDGE_X + axis, offset, 0
856
+
857
+ return node_type_and_index
858
+
859
+ def make_node_coords_in_element(self):
860
+ @cache.dynamic_func(suffix=self.name)
861
+ def node_coords_in_element(
862
+ node_index_in_elt: int,
863
+ ):
864
+ node_type, type_instance, type_index = self.node_type_and_type_index(node_index_in_elt)
865
+ axis = node_type - SquareShapeFunction.EDGE_X
866
+
867
+ coords = Coords()
868
+ coords[axis] = 0.5
869
+ coords[1 - axis] = float(type_instance)
870
+
871
+ return node_coords_in_element
872
+
873
+ def make_node_quadrature_weight(self):
874
+ NODES_PER_ELEMENT = self.NODES_PER_ELEMENT
875
+
876
+ @cache.dynamic_func(suffix=self.name)
877
+ def node_quadrature_weight(node_index_in_element: int):
878
+ return 1.0 / float(NODES_PER_ELEMENT)
879
+
880
+ return node_quadrature_weight
881
+
882
+ def make_trace_node_quadrature_weight(self):
883
+ NODES_PER_SIDE = self.NODES_PER_SIDE
884
+
885
+ @cache.dynamic_func(suffix=self.name)
886
+ def trace_node_quadrature_weight(node_index_in_element: int):
887
+ return 1.0 / float(NODES_PER_SIDE)
888
+
889
+ return trace_node_quadrature_weight
890
+
891
+ def make_element_inner_weight(self):
892
+ @cache.dynamic_func(suffix=self.name)
893
+ def element_inner_weight(
894
+ coords: Coords,
895
+ node_index_in_elt: int,
896
+ ):
897
+ node_type, type_instance, type_index = self.node_type_and_type_index(node_index_in_elt)
898
+
899
+ axis = node_type - SquareShapeFunction.EDGE_X
900
+ a = float(2 * type_instance - 1)
901
+ b = float(1 - type_instance)
902
+
903
+ w = wp.vec2(0.0)
904
+ w[1 - axis] = b + a * coords[1 - axis]
905
+
906
+ return w
907
+
908
+ return element_inner_weight
909
+
910
+ def make_element_inner_weight_gradient(self):
911
+ @cache.dynamic_func(suffix=self.name)
912
+ def element_inner_weight_gradient(
913
+ coords: Coords,
914
+ node_index_in_elt: int,
915
+ ):
916
+ node_type, type_instance, type_index = self.node_type_and_type_index(node_index_in_elt)
917
+
918
+ axis = node_type - SquareShapeFunction.EDGE_X
919
+ a = float(2 * type_instance - 1)
920
+
921
+ grad = wp.mat22(0.0)
922
+ grad[1 - axis, 1 - axis] = a
923
+
924
+ return grad
925
+
926
+ return element_inner_weight_gradient