warp-lang 1.4.2__py3-none-win_amd64.whl → 1.5.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 (166) hide show
  1. warp/__init__.py +4 -0
  2. warp/autograd.py +43 -8
  3. warp/bin/warp-clang.dll +0 -0
  4. warp/bin/warp.dll +0 -0
  5. warp/build.py +21 -2
  6. warp/build_dll.py +23 -6
  7. warp/builtins.py +1819 -7
  8. warp/codegen.py +197 -61
  9. warp/config.py +2 -2
  10. warp/context.py +379 -107
  11. warp/examples/assets/pixel.jpg +0 -0
  12. warp/examples/benchmarks/benchmark_cloth_paddle.py +86 -0
  13. warp/examples/benchmarks/benchmark_gemm.py +121 -0
  14. warp/examples/benchmarks/benchmark_interop_paddle.py +158 -0
  15. warp/examples/benchmarks/benchmark_tile.py +179 -0
  16. warp/examples/fem/example_adaptive_grid.py +37 -10
  17. warp/examples/fem/example_apic_fluid.py +3 -2
  18. warp/examples/fem/example_convection_diffusion_dg.py +4 -5
  19. warp/examples/fem/example_deformed_geometry.py +1 -1
  20. warp/examples/fem/example_diffusion_3d.py +47 -4
  21. warp/examples/fem/example_distortion_energy.py +220 -0
  22. warp/examples/fem/example_magnetostatics.py +127 -85
  23. warp/examples/fem/example_nonconforming_contact.py +5 -5
  24. warp/examples/fem/example_stokes.py +3 -1
  25. warp/examples/fem/example_streamlines.py +12 -19
  26. warp/examples/fem/utils.py +38 -15
  27. warp/examples/sim/example_cloth.py +4 -25
  28. warp/examples/sim/example_quadruped.py +2 -1
  29. warp/examples/tile/example_tile_convolution.py +58 -0
  30. warp/examples/tile/example_tile_fft.py +47 -0
  31. warp/examples/tile/example_tile_filtering.py +105 -0
  32. warp/examples/tile/example_tile_matmul.py +79 -0
  33. warp/examples/tile/example_tile_mlp.py +375 -0
  34. warp/fem/__init__.py +8 -0
  35. warp/fem/cache.py +16 -12
  36. warp/fem/dirichlet.py +1 -1
  37. warp/fem/domain.py +44 -1
  38. warp/fem/field/__init__.py +1 -2
  39. warp/fem/field/field.py +31 -19
  40. warp/fem/field/nodal_field.py +101 -49
  41. warp/fem/field/virtual.py +794 -0
  42. warp/fem/geometry/__init__.py +2 -2
  43. warp/fem/geometry/deformed_geometry.py +3 -105
  44. warp/fem/geometry/element.py +13 -0
  45. warp/fem/geometry/geometry.py +165 -7
  46. warp/fem/geometry/grid_2d.py +3 -6
  47. warp/fem/geometry/grid_3d.py +31 -28
  48. warp/fem/geometry/hexmesh.py +3 -46
  49. warp/fem/geometry/nanogrid.py +3 -2
  50. warp/fem/geometry/{quadmesh_2d.py → quadmesh.py} +280 -159
  51. warp/fem/geometry/tetmesh.py +2 -43
  52. warp/fem/geometry/{trimesh_2d.py → trimesh.py} +354 -186
  53. warp/fem/integrate.py +683 -261
  54. warp/fem/linalg.py +404 -0
  55. warp/fem/operator.py +101 -18
  56. warp/fem/polynomial.py +5 -5
  57. warp/fem/quadrature/quadrature.py +45 -21
  58. warp/fem/space/__init__.py +45 -11
  59. warp/fem/space/basis_function_space.py +451 -0
  60. warp/fem/space/basis_space.py +58 -11
  61. warp/fem/space/function_space.py +146 -5
  62. warp/fem/space/grid_2d_function_space.py +80 -66
  63. warp/fem/space/grid_3d_function_space.py +113 -68
  64. warp/fem/space/hexmesh_function_space.py +96 -108
  65. warp/fem/space/nanogrid_function_space.py +62 -110
  66. warp/fem/space/quadmesh_function_space.py +208 -0
  67. warp/fem/space/shape/__init__.py +45 -7
  68. warp/fem/space/shape/cube_shape_function.py +328 -54
  69. warp/fem/space/shape/shape_function.py +10 -1
  70. warp/fem/space/shape/square_shape_function.py +328 -60
  71. warp/fem/space/shape/tet_shape_function.py +269 -19
  72. warp/fem/space/shape/triangle_shape_function.py +238 -19
  73. warp/fem/space/tetmesh_function_space.py +69 -37
  74. warp/fem/space/topology.py +38 -0
  75. warp/fem/space/trimesh_function_space.py +179 -0
  76. warp/fem/utils.py +6 -331
  77. warp/jax_experimental.py +3 -1
  78. warp/native/array.h +15 -0
  79. warp/native/builtin.h +66 -26
  80. warp/native/bvh.h +4 -0
  81. warp/native/coloring.cpp +604 -0
  82. warp/native/cuda_util.cpp +68 -51
  83. warp/native/cuda_util.h +2 -1
  84. warp/native/fabric.h +8 -0
  85. warp/native/hashgrid.h +4 -0
  86. warp/native/marching.cu +8 -0
  87. warp/native/mat.h +14 -3
  88. warp/native/mathdx.cpp +59 -0
  89. warp/native/mesh.h +4 -0
  90. warp/native/range.h +13 -1
  91. warp/native/reduce.cpp +9 -1
  92. warp/native/reduce.cu +7 -0
  93. warp/native/runlength_encode.cpp +9 -1
  94. warp/native/runlength_encode.cu +7 -1
  95. warp/native/scan.cpp +8 -0
  96. warp/native/scan.cu +8 -0
  97. warp/native/scan.h +8 -1
  98. warp/native/sparse.cpp +8 -0
  99. warp/native/sparse.cu +8 -0
  100. warp/native/temp_buffer.h +7 -0
  101. warp/native/tile.h +1854 -0
  102. warp/native/tile_gemm.h +341 -0
  103. warp/native/tile_reduce.h +210 -0
  104. warp/native/volume_builder.cu +8 -0
  105. warp/native/volume_builder.h +8 -0
  106. warp/native/warp.cpp +10 -2
  107. warp/native/warp.cu +369 -15
  108. warp/native/warp.h +12 -2
  109. warp/optim/adam.py +39 -4
  110. warp/paddle.py +29 -12
  111. warp/render/render_opengl.py +140 -67
  112. warp/sim/graph_coloring.py +292 -0
  113. warp/sim/import_urdf.py +8 -8
  114. warp/sim/integrator_euler.py +4 -2
  115. warp/sim/integrator_featherstone.py +115 -44
  116. warp/sim/integrator_vbd.py +6 -0
  117. warp/sim/model.py +109 -32
  118. warp/sparse.py +1 -1
  119. warp/stubs.py +569 -4
  120. warp/tape.py +12 -7
  121. warp/tests/assets/pixel.npy +0 -0
  122. warp/tests/aux_test_instancing_gc.py +18 -0
  123. warp/tests/test_array.py +39 -0
  124. warp/tests/test_codegen.py +81 -1
  125. warp/tests/test_codegen_instancing.py +30 -0
  126. warp/tests/test_collision.py +110 -0
  127. warp/tests/test_coloring.py +251 -0
  128. warp/tests/test_context.py +34 -0
  129. warp/tests/test_examples.py +21 -5
  130. warp/tests/test_fem.py +453 -113
  131. warp/tests/test_func.py +34 -4
  132. warp/tests/test_generics.py +52 -0
  133. warp/tests/test_iter.py +68 -0
  134. warp/tests/test_lerp.py +13 -87
  135. warp/tests/test_mat_scalar_ops.py +1 -1
  136. warp/tests/test_matmul.py +6 -9
  137. warp/tests/test_matmul_lite.py +6 -11
  138. warp/tests/test_mesh_query_point.py +1 -1
  139. warp/tests/test_module_hashing.py +23 -0
  140. warp/tests/test_overwrite.py +45 -0
  141. warp/tests/test_paddle.py +27 -87
  142. warp/tests/test_print.py +56 -1
  143. warp/tests/test_smoothstep.py +17 -83
  144. warp/tests/test_spatial.py +1 -1
  145. warp/tests/test_static.py +3 -3
  146. warp/tests/test_tile.py +744 -0
  147. warp/tests/test_tile_mathdx.py +144 -0
  148. warp/tests/test_tile_mlp.py +383 -0
  149. warp/tests/test_tile_reduce.py +374 -0
  150. warp/tests/test_tile_shared_memory.py +190 -0
  151. warp/tests/test_vbd.py +12 -20
  152. warp/tests/test_volume.py +43 -0
  153. warp/tests/unittest_suites.py +19 -2
  154. warp/tests/unittest_utils.py +4 -2
  155. warp/types.py +340 -74
  156. warp/utils.py +23 -3
  157. {warp_lang-1.4.2.dist-info → warp_lang-1.5.1.dist-info}/METADATA +32 -7
  158. {warp_lang-1.4.2.dist-info → warp_lang-1.5.1.dist-info}/RECORD +161 -134
  159. {warp_lang-1.4.2.dist-info → warp_lang-1.5.1.dist-info}/WHEEL +1 -1
  160. warp/fem/field/test.py +0 -180
  161. warp/fem/field/trial.py +0 -183
  162. warp/fem/space/collocated_function_space.py +0 -102
  163. warp/fem/space/quadmesh_2d_function_space.py +0 -261
  164. warp/fem/space/trimesh_2d_function_space.py +0 -153
  165. {warp_lang-1.4.2.dist-info → warp_lang-1.5.1.dist-info}/LICENSE.md +0 -0
  166. {warp_lang-1.4.2.dist-info → warp_lang-1.5.1.dist-info}/top_level.txt +0 -0
@@ -1,261 +0,0 @@
1
- import warp as wp
2
- from warp.fem import cache
3
- from warp.fem.geometry import Quadmesh2D
4
- from warp.fem.polynomial import is_closed
5
- from warp.fem.types import ElementIndex
6
-
7
- from .shape import (
8
- ShapeFunction,
9
- SquareBipolynomialShapeFunctions,
10
- SquareSerendipityShapeFunctions,
11
- )
12
- from .topology import SpaceTopology, forward_base_topology
13
-
14
-
15
- @wp.struct
16
- class Quadmesh2DTopologyArg:
17
- edge_vertex_indices: wp.array(dtype=wp.vec2i)
18
- quad_edge_indices: wp.array2d(dtype=int)
19
-
20
- vertex_count: int
21
- edge_count: int
22
-
23
-
24
- class Quadmesh2DSpaceTopology(SpaceTopology):
25
- TopologyArg = Quadmesh2DTopologyArg
26
-
27
- def __init__(self, mesh: Quadmesh2D, shape: ShapeFunction):
28
- if not is_closed(shape.family):
29
- raise ValueError("A closed polynomial family is required to define a continuous function space")
30
-
31
- super().__init__(mesh, shape.NODES_PER_ELEMENT)
32
- self._mesh = mesh
33
- self._shape = shape
34
-
35
- self._compute_quad_edge_indices()
36
-
37
- @cache.cached_arg_value
38
- def topo_arg_value(self, device):
39
- arg = Quadmesh2DTopologyArg()
40
- arg.quad_edge_indices = self._quad_edge_indices.to(device)
41
- arg.edge_vertex_indices = self._mesh.edge_vertex_indices.to(device)
42
-
43
- arg.vertex_count = self._mesh.vertex_count()
44
- arg.edge_count = self._mesh.side_count()
45
- return arg
46
-
47
- def _compute_quad_edge_indices(self):
48
- self._quad_edge_indices = wp.empty(
49
- dtype=int, device=self._mesh.quad_vertex_indices.device, shape=(self._mesh.cell_count(), 4)
50
- )
51
-
52
- wp.launch(
53
- kernel=Quadmesh2DSpaceTopology._compute_quad_edge_indices_kernel,
54
- dim=self._mesh.edge_quad_indices.shape,
55
- device=self._mesh.quad_vertex_indices.device,
56
- inputs=[
57
- self._mesh.edge_quad_indices,
58
- self._mesh.edge_vertex_indices,
59
- self._mesh.quad_vertex_indices,
60
- self._quad_edge_indices,
61
- ],
62
- )
63
-
64
- @wp.func
65
- def _find_edge_index_in_quad(
66
- edge_vtx: wp.vec2i,
67
- quad_vtx: wp.vec4i,
68
- ):
69
- for k in range(3):
70
- if (edge_vtx[0] == quad_vtx[k] and edge_vtx[1] == quad_vtx[k + 1]) or (
71
- edge_vtx[1] == quad_vtx[k] and edge_vtx[0] == quad_vtx[k + 1]
72
- ):
73
- return k
74
- return 3
75
-
76
- @wp.kernel
77
- def _compute_quad_edge_indices_kernel(
78
- edge_quad_indices: wp.array(dtype=wp.vec2i),
79
- edge_vertex_indices: wp.array(dtype=wp.vec2i),
80
- quad_vertex_indices: wp.array2d(dtype=int),
81
- quad_edge_indices: wp.array2d(dtype=int),
82
- ):
83
- e = wp.tid()
84
-
85
- edge_vtx = edge_vertex_indices[e]
86
- edge_quads = edge_quad_indices[e]
87
-
88
- q0 = edge_quads[0]
89
- q0_vtx = wp.vec4i(
90
- quad_vertex_indices[q0, 0],
91
- quad_vertex_indices[q0, 1],
92
- quad_vertex_indices[q0, 2],
93
- quad_vertex_indices[q0, 3],
94
- )
95
- q0_edge = Quadmesh2DSpaceTopology._find_edge_index_in_quad(edge_vtx, q0_vtx)
96
- quad_edge_indices[q0, q0_edge] = e
97
-
98
- q1 = edge_quads[1]
99
- if q1 != q0:
100
- t1_vtx = wp.vec4i(
101
- quad_vertex_indices[q1, 0],
102
- quad_vertex_indices[q1, 1],
103
- quad_vertex_indices[q1, 2],
104
- quad_vertex_indices[q1, 3],
105
- )
106
- t1_edge = Quadmesh2DSpaceTopology._find_edge_index_in_quad(edge_vtx, t1_vtx)
107
- quad_edge_indices[q1, t1_edge] = e
108
-
109
-
110
- class Quadmesh2DBipolynomialSpaceTopology(Quadmesh2DSpaceTopology):
111
- def __init__(self, mesh: Quadmesh2D, shape: SquareBipolynomialShapeFunctions):
112
- super().__init__(mesh, shape)
113
-
114
- self.element_node_index = self._make_element_node_index()
115
-
116
- def node_count(self) -> int:
117
- ORDER = self._shape.ORDER
118
- INTERIOR_NODES_PER_SIDE = max(0, ORDER - 1)
119
- INTERIOR_NODES_PER_CELL = INTERIOR_NODES_PER_SIDE**2
120
-
121
- return (
122
- self._mesh.vertex_count()
123
- + self._mesh.side_count() * INTERIOR_NODES_PER_SIDE
124
- + self._mesh.cell_count() * INTERIOR_NODES_PER_CELL
125
- )
126
-
127
- def _make_element_node_index(self):
128
- ORDER = self._shape.ORDER
129
- INTERIOR_NODES_PER_SIDE = wp.constant(max(0, ORDER - 1))
130
- INTERIOR_NODES_PER_CELL = wp.constant(INTERIOR_NODES_PER_SIDE**2)
131
-
132
- @cache.dynamic_func(suffix=self.name)
133
- def element_node_index(
134
- geo_arg: Quadmesh2D.CellArg,
135
- topo_arg: Quadmesh2DTopologyArg,
136
- element_index: ElementIndex,
137
- node_index_in_elt: int,
138
- ):
139
- node_i = node_index_in_elt // (ORDER + 1)
140
- node_j = node_index_in_elt - (ORDER + 1) * node_i
141
-
142
- # Vertices
143
- if node_i == 0:
144
- if node_j == 0:
145
- return geo_arg.quad_vertex_indices[element_index, 0]
146
- elif node_j == ORDER:
147
- return geo_arg.quad_vertex_indices[element_index, 3]
148
-
149
- # 3-0 edge
150
- side_index = topo_arg.quad_edge_indices[element_index, 3]
151
- local_vs = geo_arg.quad_vertex_indices[element_index, 3]
152
- global_vs = topo_arg.edge_vertex_indices[side_index][0]
153
- index_in_side = wp.select(local_vs == global_vs, ORDER - node_j, node_j) - 1
154
-
155
- return topo_arg.vertex_count + (ORDER - 1) * side_index + index_in_side
156
-
157
- elif node_i == ORDER:
158
- if node_j == 0:
159
- return geo_arg.quad_vertex_indices[element_index, 1]
160
- elif node_j == ORDER:
161
- return geo_arg.quad_vertex_indices[element_index, 2]
162
-
163
- # 1-2 edge
164
- side_index = topo_arg.quad_edge_indices[element_index, 1]
165
- local_vs = geo_arg.quad_vertex_indices[element_index, 1]
166
- global_vs = topo_arg.edge_vertex_indices[side_index][0]
167
- index_in_side = wp.select(local_vs == global_vs, ORDER - node_j, node_j) - 1
168
-
169
- return topo_arg.vertex_count + (ORDER - 1) * side_index + index_in_side
170
-
171
- if node_j == 0:
172
- # 0-1 edge
173
- side_index = topo_arg.quad_edge_indices[element_index, 0]
174
- local_vs = geo_arg.quad_vertex_indices[element_index, 0]
175
- global_vs = topo_arg.edge_vertex_indices[side_index][0]
176
- index_in_side = wp.select(local_vs == global_vs, node_i, ORDER - node_i) - 1
177
-
178
- return topo_arg.vertex_count + (ORDER - 1) * side_index + index_in_side
179
-
180
- elif node_j == ORDER:
181
- # 2-3 edge
182
- side_index = topo_arg.quad_edge_indices[element_index, 2]
183
- local_vs = geo_arg.quad_vertex_indices[element_index, 2]
184
- global_vs = topo_arg.edge_vertex_indices[side_index][0]
185
- index_in_side = wp.select(local_vs == global_vs, node_i, ORDER - node_i) - 1
186
-
187
- return topo_arg.vertex_count + (ORDER - 1) * side_index + index_in_side
188
-
189
- return (
190
- topo_arg.vertex_count
191
- + topo_arg.edge_count * INTERIOR_NODES_PER_SIDE
192
- + element_index * INTERIOR_NODES_PER_CELL
193
- + (node_i - 1) * INTERIOR_NODES_PER_SIDE
194
- + node_j
195
- - 1
196
- )
197
-
198
- return element_node_index
199
-
200
-
201
- class Quadmesh2DSerendipitySpaceTopology(Quadmesh2DSpaceTopology):
202
- def __init__(self, grid: Quadmesh2D, shape: SquareSerendipityShapeFunctions):
203
- super().__init__(grid, shape)
204
-
205
- self.element_node_index = self._make_element_node_index()
206
-
207
- def node_count(self) -> int:
208
- return self.geometry.vertex_count() + (self._shape.ORDER - 1) * self.geometry.side_count()
209
-
210
- def _make_element_node_index(self):
211
- ORDER = self._shape.ORDER
212
-
213
- SHAPE_TO_QUAD_IDX = wp.constant(wp.vec4i([0, 3, 1, 2]))
214
-
215
- @cache.dynamic_func(suffix=self.name)
216
- def element_node_index(
217
- cell_arg: Quadmesh2D.CellArg,
218
- topo_arg: Quadmesh2DSpaceTopology.TopologyArg,
219
- element_index: ElementIndex,
220
- node_index_in_elt: int,
221
- ):
222
- node_type, type_index = self._shape.node_type_and_type_index(node_index_in_elt)
223
-
224
- if node_type == SquareSerendipityShapeFunctions.VERTEX:
225
- return cell_arg.quad_vertex_indices[element_index, SHAPE_TO_QUAD_IDX[type_index]]
226
-
227
- side_offset, index_in_side = SquareSerendipityShapeFunctions.side_offset_and_index(type_index)
228
-
229
- if node_type == SquareSerendipityShapeFunctions.EDGE_X:
230
- if side_offset == 0:
231
- side_start = 0
232
- else:
233
- side_start = 2
234
- index_in_side = ORDER - 2 - index_in_side
235
- else:
236
- if side_offset == 0:
237
- side_start = 3
238
- index_in_side = ORDER - 2 - index_in_side
239
- else:
240
- side_start = 1
241
-
242
- side_index = topo_arg.quad_edge_indices[element_index, side_start]
243
- local_vs = cell_arg.quad_vertex_indices[element_index, side_start]
244
- global_vs = topo_arg.edge_vertex_indices[side_index][0]
245
- if local_vs != global_vs:
246
- # Flip indexing direction
247
- index_in_side = ORDER - 2 - index_in_side
248
-
249
- return topo_arg.vertex_count + (ORDER - 1) * side_index + index_in_side
250
-
251
- return element_node_index
252
-
253
-
254
- def make_quadmesh_2d_space_topology(mesh: Quadmesh2D, shape: ShapeFunction):
255
- if isinstance(shape, SquareSerendipityShapeFunctions):
256
- return forward_base_topology(Quadmesh2DSerendipitySpaceTopology, mesh, shape)
257
-
258
- if isinstance(shape, SquareBipolynomialShapeFunctions):
259
- return forward_base_topology(Quadmesh2DBipolynomialSpaceTopology, mesh, shape)
260
-
261
- raise ValueError(f"Unsupported shape function {shape.name}")
@@ -1,153 +0,0 @@
1
- import warp as wp
2
- from warp.fem import cache
3
- from warp.fem.geometry import Trimesh2D
4
- from warp.fem.types import ElementIndex
5
-
6
- from .shape import (
7
- ShapeFunction,
8
- Triangle2DPolynomialShapeFunctions,
9
- )
10
- from .topology import SpaceTopology, forward_base_topology
11
-
12
-
13
- @wp.struct
14
- class Trimesh2DTopologyArg:
15
- edge_vertex_indices: wp.array(dtype=wp.vec2i)
16
- tri_edge_indices: wp.array2d(dtype=int)
17
-
18
- vertex_count: int
19
- edge_count: int
20
-
21
-
22
- class Trimesh2DSpaceTopology(SpaceTopology):
23
- TopologyArg = Trimesh2DTopologyArg
24
-
25
- def __init__(self, mesh: Trimesh2D, shape: ShapeFunction):
26
- super().__init__(mesh, shape.NODES_PER_ELEMENT)
27
- self._mesh = mesh
28
- self._shape = shape
29
-
30
- self._compute_tri_edge_indices()
31
-
32
- @cache.cached_arg_value
33
- def topo_arg_value(self, device):
34
- arg = Trimesh2DTopologyArg()
35
- arg.tri_edge_indices = self._tri_edge_indices.to(device)
36
- arg.edge_vertex_indices = self._mesh.edge_vertex_indices.to(device)
37
-
38
- arg.vertex_count = self._mesh.vertex_count()
39
- arg.edge_count = self._mesh.side_count()
40
- return arg
41
-
42
- def _compute_tri_edge_indices(self):
43
- self._tri_edge_indices = wp.empty(
44
- dtype=int, device=self._mesh.tri_vertex_indices.device, shape=(self._mesh.cell_count(), 3)
45
- )
46
-
47
- wp.launch(
48
- kernel=Trimesh2DSpaceTopology._compute_tri_edge_indices_kernel,
49
- dim=self._mesh.edge_tri_indices.shape,
50
- device=self._mesh.tri_vertex_indices.device,
51
- inputs=[
52
- self._mesh.edge_tri_indices,
53
- self._mesh.edge_vertex_indices,
54
- self._mesh.tri_vertex_indices,
55
- self._tri_edge_indices,
56
- ],
57
- )
58
-
59
- @wp.func
60
- def _find_edge_index_in_tri(
61
- edge_vtx: wp.vec2i,
62
- tri_vtx: wp.vec3i,
63
- ):
64
- for k in range(2):
65
- if (edge_vtx[0] == tri_vtx[k] and edge_vtx[1] == tri_vtx[k + 1]) or (
66
- edge_vtx[1] == tri_vtx[k] and edge_vtx[0] == tri_vtx[k + 1]
67
- ):
68
- return k
69
- return 2
70
-
71
- @wp.kernel
72
- def _compute_tri_edge_indices_kernel(
73
- edge_tri_indices: wp.array(dtype=wp.vec2i),
74
- edge_vertex_indices: wp.array(dtype=wp.vec2i),
75
- tri_vertex_indices: wp.array2d(dtype=int),
76
- tri_edge_indices: wp.array2d(dtype=int),
77
- ):
78
- e = wp.tid()
79
-
80
- edge_vtx = edge_vertex_indices[e]
81
- edge_tris = edge_tri_indices[e]
82
-
83
- t0 = edge_tris[0]
84
- t0_vtx = wp.vec3i(tri_vertex_indices[t0, 0], tri_vertex_indices[t0, 1], tri_vertex_indices[t0, 2])
85
- t0_edge = Trimesh2DSpaceTopology._find_edge_index_in_tri(edge_vtx, t0_vtx)
86
- tri_edge_indices[t0, t0_edge] = e
87
-
88
- t1 = edge_tris[1]
89
- if t1 != t0:
90
- t1_vtx = wp.vec3i(tri_vertex_indices[t1, 0], tri_vertex_indices[t1, 1], tri_vertex_indices[t1, 2])
91
- t1_edge = Trimesh2DSpaceTopology._find_edge_index_in_tri(edge_vtx, t1_vtx)
92
- tri_edge_indices[t1, t1_edge] = e
93
-
94
-
95
- class Trimesh2DPolynomialSpaceTopology(Trimesh2DSpaceTopology):
96
- def __init__(self, mesh: Trimesh2D, shape: Triangle2DPolynomialShapeFunctions):
97
- super().__init__(mesh, shape)
98
-
99
- self.element_node_index = self._make_element_node_index()
100
-
101
- def node_count(self) -> int:
102
- INTERIOR_NODES_PER_SIDE = max(0, self._shape.ORDER - 1)
103
- INTERIOR_NODES_PER_CELL = max(0, self._shape.ORDER - 2) * max(0, self._shape.ORDER - 1) // 2
104
-
105
- return (
106
- self._mesh.vertex_count()
107
- + self._mesh.side_count() * INTERIOR_NODES_PER_SIDE
108
- + self._mesh.cell_count() * INTERIOR_NODES_PER_CELL
109
- )
110
-
111
- def _make_element_node_index(self):
112
- INTERIOR_NODES_PER_SIDE = wp.constant(max(0, self._shape.ORDER - 1))
113
- INTERIOR_NODES_PER_CELL = wp.constant(max(0, self._shape.ORDER - 2) * max(0, self._shape.ORDER - 1) // 2)
114
-
115
- @cache.dynamic_func(suffix=self.name)
116
- def element_node_index(
117
- geo_arg: Trimesh2D.CellArg,
118
- topo_arg: Trimesh2DTopologyArg,
119
- element_index: ElementIndex,
120
- node_index_in_elt: int,
121
- ):
122
- node_type, type_index = self._shape.node_type_and_type_index(node_index_in_elt)
123
-
124
- if node_type == Triangle2DPolynomialShapeFunctions.VERTEX:
125
- return geo_arg.tri_vertex_indices[element_index][type_index]
126
-
127
- global_offset = topo_arg.vertex_count
128
-
129
- if node_type == Triangle2DPolynomialShapeFunctions.EDGE:
130
- edge = type_index // INTERIOR_NODES_PER_SIDE
131
- edge_node = type_index - INTERIOR_NODES_PER_SIDE * edge
132
-
133
- global_edge_index = topo_arg.tri_edge_indices[element_index][edge]
134
-
135
- if (
136
- topo_arg.edge_vertex_indices[global_edge_index][0]
137
- != geo_arg.tri_vertex_indices[element_index][edge]
138
- ):
139
- edge_node = INTERIOR_NODES_PER_SIDE - 1 - edge_node
140
-
141
- return global_offset + INTERIOR_NODES_PER_SIDE * global_edge_index + edge_node
142
-
143
- global_offset += INTERIOR_NODES_PER_SIDE * topo_arg.edge_count
144
- return global_offset + INTERIOR_NODES_PER_CELL * element_index + type_index
145
-
146
- return element_node_index
147
-
148
-
149
- def make_trimesh_2d_space_topology(mesh: Trimesh2D, shape: ShapeFunction):
150
- if isinstance(shape, Triangle2DPolynomialShapeFunctions):
151
- return forward_base_topology(Trimesh2DPolynomialSpaceTopology, mesh, shape)
152
-
153
- raise ValueError(f"Unsupported shape function {shape.name}")