warp-lang 1.3.2__py3-none-win_amd64.whl → 1.4.0__py3-none-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of warp-lang might be problematic. Click here for more details.
- warp/__init__.py +6 -0
- warp/autograd.py +59 -6
- warp/bin/warp-clang.dll +0 -0
- warp/bin/warp.dll +0 -0
- warp/build_dll.py +8 -10
- warp/builtins.py +126 -4
- warp/codegen.py +435 -53
- warp/config.py +1 -1
- warp/context.py +678 -403
- warp/dlpack.py +2 -0
- warp/examples/benchmarks/benchmark_cloth.py +10 -0
- warp/examples/core/example_render_opengl.py +12 -10
- warp/examples/fem/example_adaptive_grid.py +251 -0
- warp/examples/fem/example_apic_fluid.py +1 -1
- warp/examples/fem/example_diffusion_3d.py +2 -2
- warp/examples/fem/example_magnetostatics.py +1 -1
- warp/examples/fem/example_streamlines.py +1 -0
- warp/examples/fem/utils.py +23 -4
- warp/examples/sim/example_cloth.py +50 -6
- warp/fem/__init__.py +2 -0
- warp/fem/adaptivity.py +493 -0
- warp/fem/field/field.py +2 -1
- warp/fem/field/nodal_field.py +18 -26
- warp/fem/field/test.py +4 -4
- warp/fem/field/trial.py +4 -4
- warp/fem/geometry/__init__.py +1 -0
- warp/fem/geometry/adaptive_nanogrid.py +843 -0
- warp/fem/geometry/nanogrid.py +55 -28
- warp/fem/space/__init__.py +1 -1
- warp/fem/space/nanogrid_function_space.py +69 -35
- warp/fem/utils.py +113 -107
- warp/jax_experimental.py +28 -15
- warp/native/array.h +0 -1
- warp/native/builtin.h +103 -6
- warp/native/bvh.cu +2 -0
- warp/native/cuda_util.cpp +14 -0
- warp/native/cuda_util.h +2 -0
- warp/native/error.cpp +4 -2
- warp/native/exports.h +99 -17
- warp/native/mat.h +97 -0
- warp/native/mesh.cpp +36 -0
- warp/native/mesh.cu +51 -0
- warp/native/mesh.h +1 -0
- warp/native/quat.h +43 -0
- warp/native/spatial.h +6 -0
- warp/native/vec.h +74 -0
- warp/native/warp.cpp +2 -1
- warp/native/warp.cu +10 -3
- warp/native/warp.h +8 -1
- warp/paddle.py +382 -0
- warp/sim/__init__.py +1 -0
- warp/sim/collide.py +519 -0
- warp/sim/integrator_euler.py +18 -5
- warp/sim/integrator_featherstone.py +5 -5
- warp/sim/integrator_vbd.py +1026 -0
- warp/sim/model.py +49 -23
- warp/stubs.py +459 -0
- warp/tape.py +2 -0
- warp/tests/aux_test_dependent.py +1 -0
- warp/tests/aux_test_name_clash1.py +32 -0
- warp/tests/aux_test_name_clash2.py +32 -0
- warp/tests/aux_test_square.py +1 -0
- warp/tests/test_array.py +222 -0
- warp/tests/test_async.py +3 -3
- warp/tests/test_atomic.py +6 -0
- warp/tests/test_closest_point_edge_edge.py +93 -1
- warp/tests/test_codegen.py +62 -15
- warp/tests/test_codegen_instancing.py +1457 -0
- warp/tests/test_collision.py +486 -0
- warp/tests/test_compile_consts.py +3 -28
- warp/tests/test_dlpack.py +170 -0
- warp/tests/test_examples.py +22 -8
- warp/tests/test_fast_math.py +10 -4
- warp/tests/test_fem.py +64 -0
- warp/tests/test_func.py +46 -0
- warp/tests/test_implicit_init.py +49 -0
- warp/tests/test_jax.py +58 -0
- warp/tests/test_mat.py +84 -0
- warp/tests/test_mesh_query_point.py +188 -0
- warp/tests/test_module_hashing.py +40 -0
- warp/tests/test_multigpu.py +3 -3
- warp/tests/test_overwrite.py +8 -0
- warp/tests/test_paddle.py +852 -0
- warp/tests/test_print.py +89 -0
- warp/tests/test_quat.py +111 -0
- warp/tests/test_reload.py +31 -1
- warp/tests/test_scalar_ops.py +2 -0
- warp/tests/test_static.py +412 -0
- warp/tests/test_streams.py +64 -3
- warp/tests/test_struct.py +4 -4
- warp/tests/test_torch.py +24 -0
- warp/tests/test_triangle_closest_point.py +137 -0
- warp/tests/test_types.py +1 -1
- warp/tests/test_vbd.py +386 -0
- warp/tests/test_vec.py +143 -0
- warp/tests/test_vec_scalar_ops.py +139 -0
- warp/tests/test_volume.py +30 -0
- warp/tests/unittest_suites.py +12 -0
- warp/tests/unittest_utils.py +9 -5
- warp/thirdparty/dlpack.py +3 -1
- warp/types.py +157 -34
- warp/utils.py +37 -14
- {warp_lang-1.3.2.dist-info → warp_lang-1.4.0.dist-info}/METADATA +10 -8
- {warp_lang-1.3.2.dist-info → warp_lang-1.4.0.dist-info}/RECORD +107 -95
- warp/tests/test_point_triangle_closest_point.py +0 -143
- {warp_lang-1.3.2.dist-info → warp_lang-1.4.0.dist-info}/LICENSE.md +0 -0
- {warp_lang-1.3.2.dist-info → warp_lang-1.4.0.dist-info}/WHEEL +0 -0
- {warp_lang-1.3.2.dist-info → warp_lang-1.4.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,843 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
|
|
5
|
+
import warp as wp
|
|
6
|
+
from warp.fem import cache, utils
|
|
7
|
+
from warp.fem.types import NULL_ELEMENT_INDEX, OUTSIDE, Coords, ElementIndex, Sample, make_free_sample
|
|
8
|
+
|
|
9
|
+
from .element import Cube, Square
|
|
10
|
+
from .geometry import Geometry
|
|
11
|
+
from .nanogrid import (
|
|
12
|
+
Nanogrid,
|
|
13
|
+
_add_axis_flag,
|
|
14
|
+
_build_node_grid,
|
|
15
|
+
_extract_axis_flag,
|
|
16
|
+
_get_boundary_mask,
|
|
17
|
+
_make_face_flags,
|
|
18
|
+
_mat32,
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
_FACE_LEVEL_BIT = wp.constant(wp.uint8(4)) # follows nanogrid.FACE_OUTER_OFFSET_BIT
|
|
22
|
+
_GRID_LEVEL_BIT = wp.constant(wp.int32(19)) # follows nanogrid.GRID_AXIS_FLAG
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@wp.struct
|
|
26
|
+
class AdaptiveNanogridCellArg:
|
|
27
|
+
# Utility device functions
|
|
28
|
+
cell_grid: wp.uint64
|
|
29
|
+
cell_ijk: wp.array(dtype=wp.vec3i)
|
|
30
|
+
cell_level: wp.array(dtype=wp.uint8)
|
|
31
|
+
inverse_transform: wp.mat33
|
|
32
|
+
cell_volume: float
|
|
33
|
+
level_count: int
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@wp.struct
|
|
37
|
+
class AdaptiveNanogridSideArg:
|
|
38
|
+
# Utility device functions
|
|
39
|
+
cell_arg: AdaptiveNanogridCellArg
|
|
40
|
+
face_ijk: wp.array(dtype=wp.vec3i)
|
|
41
|
+
face_cell_indices: wp.array(dtype=wp.vec2i)
|
|
42
|
+
face_flags: wp.array(dtype=wp.uint8)
|
|
43
|
+
face_areas: wp.vec3
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class AdaptiveNanogrid(Geometry):
|
|
47
|
+
"""Adaptive sparse grid"""
|
|
48
|
+
|
|
49
|
+
dimension = 3
|
|
50
|
+
|
|
51
|
+
def __init__(
|
|
52
|
+
self,
|
|
53
|
+
cell_grid: wp.Volume,
|
|
54
|
+
cell_level: wp.array,
|
|
55
|
+
level_count: int,
|
|
56
|
+
temporary_store: cache.TemporaryStore,
|
|
57
|
+
):
|
|
58
|
+
"""
|
|
59
|
+
Constructs an adaptive sparse grid geometry from an in-memory NanoVDB volume and a list of levels.
|
|
60
|
+
|
|
61
|
+
It is not recommended to use this constructor directly; see the helper functions :func:`warp.fem.adaptive_nanogrid_from_field` and :func:`warp.fem.adaptive_nanogrid_from_hierarchy`
|
|
62
|
+
|
|
63
|
+
Args:
|
|
64
|
+
cell_grid: A warp volume (ideally backed by an index grid) whose voxels coordinates correspond to the lowest fine-resolution voxel of each cell.
|
|
65
|
+
The cell's extent is then given by the `cell_level` array. For instance, a voxel at coordinates ``ijk`` and level ``0`` corresponds to a fine cell at the same coordinates,
|
|
66
|
+
a voxel at coordinates ``2*ijk`` and level ``1`` corresponds to a cell spanning ``2^3`` voxels from ``2*ijk`` to ``2*ijk + (1,1,1)``, etc.
|
|
67
|
+
cell_level: Refinement level for each voxel of the volume. Level 0 is the finest, level ``level_count-1`` is the coarsest.
|
|
68
|
+
level_count: Number of levels in the grid
|
|
69
|
+
"""
|
|
70
|
+
|
|
71
|
+
if level_count > 8:
|
|
72
|
+
raise ValueError("Too many refinement levels, max 8 supported")
|
|
73
|
+
|
|
74
|
+
self.level_count = level_count
|
|
75
|
+
self._cell_grid = cell_grid
|
|
76
|
+
self._cell_level = cell_level
|
|
77
|
+
|
|
78
|
+
device = self._cell_grid.device
|
|
79
|
+
self._cell_ijk = wp.array(dtype=wp.vec3i, shape=(cell_grid.get_voxel_count(),), device=device)
|
|
80
|
+
self._cell_grid.get_voxels(out=self._cell_ijk)
|
|
81
|
+
self._cell_grid_info = self._cell_grid.get_grid_info()
|
|
82
|
+
|
|
83
|
+
self._node_grid = _build_node_grid(self._cell_ijk, self._cell_level, self._cell_grid, temporary_store)
|
|
84
|
+
node_count = self._node_grid.get_voxel_count()
|
|
85
|
+
self._node_ijk = wp.array(shape=(node_count,), dtype=wp.vec3i, device=device)
|
|
86
|
+
self._node_grid.get_voxels(out=self._node_ijk)
|
|
87
|
+
|
|
88
|
+
self._face_grid = None
|
|
89
|
+
self._face_ijk = None
|
|
90
|
+
|
|
91
|
+
self._stacked_edge_grid = None
|
|
92
|
+
self._stacked_edge_count = 0
|
|
93
|
+
self._stacked_face_grid = None
|
|
94
|
+
self._stacked_face_count = 0
|
|
95
|
+
|
|
96
|
+
@property
|
|
97
|
+
def cell_grid(self) -> wp.Volume:
|
|
98
|
+
return self._cell_grid
|
|
99
|
+
|
|
100
|
+
@property
|
|
101
|
+
def vertex_grid(self) -> wp.Volume:
|
|
102
|
+
return self._node_grid
|
|
103
|
+
|
|
104
|
+
@property
|
|
105
|
+
def face_grid(self) -> wp.Volume:
|
|
106
|
+
self._ensure_face_grid()
|
|
107
|
+
return self._face_grid
|
|
108
|
+
|
|
109
|
+
def cell_count(self):
|
|
110
|
+
return self._cell_ijk.shape[0]
|
|
111
|
+
|
|
112
|
+
def vertex_count(self):
|
|
113
|
+
return self._node_ijk.shape[0]
|
|
114
|
+
|
|
115
|
+
def side_count(self):
|
|
116
|
+
self._ensure_face_grid()
|
|
117
|
+
return self._face_ijk.shape[0]
|
|
118
|
+
|
|
119
|
+
def boundary_side_count(self):
|
|
120
|
+
self._ensure_face_grid()
|
|
121
|
+
return self._boundary_face_indices.shape[0]
|
|
122
|
+
|
|
123
|
+
@property
|
|
124
|
+
def stacked_face_grid(self) -> wp.Volume:
|
|
125
|
+
self._ensure_stacked_face_grid()
|
|
126
|
+
return self._stacked_face_grid
|
|
127
|
+
|
|
128
|
+
def stacked_face_count(self):
|
|
129
|
+
self._ensure_stacked_face_grid()
|
|
130
|
+
return self._stacked_face_count
|
|
131
|
+
|
|
132
|
+
@property
|
|
133
|
+
def stacked_edge_grid(self) -> wp.Volume:
|
|
134
|
+
self._ensure_stacked_edge_grid()
|
|
135
|
+
return self._stacked_edge_grid
|
|
136
|
+
|
|
137
|
+
def stacked_edge_count(self):
|
|
138
|
+
self._ensure_stacked_edge_grid()
|
|
139
|
+
return self._stacked_edge_count
|
|
140
|
+
|
|
141
|
+
def reference_cell(self) -> Cube:
|
|
142
|
+
return Cube()
|
|
143
|
+
|
|
144
|
+
def reference_side(self) -> Square:
|
|
145
|
+
return Square()
|
|
146
|
+
|
|
147
|
+
@property
|
|
148
|
+
def transform(self):
|
|
149
|
+
return np.array(self._cell_grid_info.transform_matrix).reshape(3, 3)
|
|
150
|
+
|
|
151
|
+
CellArg = AdaptiveNanogridCellArg
|
|
152
|
+
|
|
153
|
+
@cache.cached_arg_value
|
|
154
|
+
def cell_arg_value(self, device) -> CellArg:
|
|
155
|
+
args = self.CellArg()
|
|
156
|
+
args.cell_grid = self._cell_grid.id
|
|
157
|
+
args.cell_ijk = self._cell_ijk
|
|
158
|
+
args.cell_level = self._cell_level
|
|
159
|
+
|
|
160
|
+
transform = self.transform
|
|
161
|
+
args.inverse_transform = wp.mat33f(np.linalg.inv(transform))
|
|
162
|
+
args.cell_volume = abs(np.linalg.det(transform))
|
|
163
|
+
args.level_count = self.level_count
|
|
164
|
+
|
|
165
|
+
return args
|
|
166
|
+
|
|
167
|
+
@wp.func
|
|
168
|
+
def _cell_scale(args: CellArg, cell_index: int):
|
|
169
|
+
return float(1 << int(args.cell_level[cell_index]))
|
|
170
|
+
|
|
171
|
+
@wp.func
|
|
172
|
+
def cell_position(args: CellArg, s: Sample):
|
|
173
|
+
scale = AdaptiveNanogrid._cell_scale(args, s.element_index)
|
|
174
|
+
uvw = wp.vec3(args.cell_ijk[s.element_index]) + s.element_coords * scale
|
|
175
|
+
return wp.volume_index_to_world(args.cell_grid, uvw - wp.vec3(0.5))
|
|
176
|
+
|
|
177
|
+
@wp.func
|
|
178
|
+
def cell_deformation_gradient(args: CellArg, s: Sample):
|
|
179
|
+
scale = AdaptiveNanogrid._cell_scale(args, s.element_index)
|
|
180
|
+
return wp.inverse(args.inverse_transform) * scale
|
|
181
|
+
|
|
182
|
+
@wp.func
|
|
183
|
+
def cell_inverse_deformation_gradient(args: CellArg, s: Sample):
|
|
184
|
+
scale = AdaptiveNanogrid._cell_scale(args, s.element_index)
|
|
185
|
+
return args.inverse_transform / scale
|
|
186
|
+
|
|
187
|
+
@wp.func
|
|
188
|
+
def _make_sample(args: CellArg, cell_index: int, uvw: wp.vec3):
|
|
189
|
+
ijk = args.cell_ijk[cell_index]
|
|
190
|
+
return make_free_sample(cell_index, (uvw - wp.vec3(ijk)) / AdaptiveNanogrid._cell_scale(args, cell_index))
|
|
191
|
+
|
|
192
|
+
@wp.func
|
|
193
|
+
def cell_lookup(args: CellArg, pos: wp.vec3):
|
|
194
|
+
uvw = wp.volume_world_to_index(args.cell_grid, pos) + wp.vec3(0.5)
|
|
195
|
+
ijk = wp.vec3i(int(wp.floor(uvw[0])), int(wp.floor(uvw[1])), int(wp.floor(uvw[2])))
|
|
196
|
+
cell_index = AdaptiveNanogrid.find_cell(args.cell_grid, ijk, args.level_count, args.cell_level)
|
|
197
|
+
|
|
198
|
+
if cell_index == -1:
|
|
199
|
+
coords = uvw - wp.vec3(ijk)
|
|
200
|
+
|
|
201
|
+
if wp.min(coords) == 0.0 or wp.max(coords) == 1.0:
|
|
202
|
+
il = wp.select(coords[0] > 0.5, -1, 0)
|
|
203
|
+
jl = wp.select(coords[1] > 0.5, -1, 0)
|
|
204
|
+
kl = wp.select(coords[2] > 0.5, -1, 0)
|
|
205
|
+
|
|
206
|
+
for n in range(8):
|
|
207
|
+
ni = n >> 2
|
|
208
|
+
nj = (n & 2) >> 1
|
|
209
|
+
nk = n & 1
|
|
210
|
+
nijk = ijk + wp.vec3i(ni + il, nj + jl, nk + kl)
|
|
211
|
+
|
|
212
|
+
coords = uvw - wp.vec3(nijk)
|
|
213
|
+
if wp.min(coords) >= 0.0 and wp.max(coords) <= 1.0:
|
|
214
|
+
cell_index = AdaptiveNanogrid.find_cell(args.cell_grid, nijk, args.level_count, args.cell_level)
|
|
215
|
+
if cell_index != -1:
|
|
216
|
+
return AdaptiveNanogrid._make_sample(args, cell_index, uvw)
|
|
217
|
+
|
|
218
|
+
return make_free_sample(NULL_ELEMENT_INDEX, Coords(OUTSIDE))
|
|
219
|
+
|
|
220
|
+
return AdaptiveNanogrid._make_sample(args, cell_index, uvw)
|
|
221
|
+
|
|
222
|
+
@wp.func
|
|
223
|
+
def cell_lookup(args: CellArg, pos: wp.vec3, guess: Sample):
|
|
224
|
+
s_global = AdaptiveNanogrid.cell_lookup(args, pos)
|
|
225
|
+
|
|
226
|
+
if s_global.element_index != NULL_ELEMENT_INDEX:
|
|
227
|
+
return s_global
|
|
228
|
+
|
|
229
|
+
closest_voxel = int(NULL_ELEMENT_INDEX)
|
|
230
|
+
closest_coords = Coords(OUTSIDE)
|
|
231
|
+
closest_dist = float(1.0e8)
|
|
232
|
+
|
|
233
|
+
# project to closest in stencil
|
|
234
|
+
uvw = wp.volume_world_to_index(args.cell_grid, pos) + wp.vec3(0.5)
|
|
235
|
+
cell_ijk = args.cell_ijk[guess.element_index]
|
|
236
|
+
for ni in range(-1, 2):
|
|
237
|
+
for nj in range(-1, 2):
|
|
238
|
+
for nk in range(-1, 2):
|
|
239
|
+
nijk = cell_ijk + wp.vec3i(ni, nj, nk)
|
|
240
|
+
cell_idx = AdaptiveNanogrid.find_cell(args.cell_grid, nijk, args.level_count, args.cell_level)
|
|
241
|
+
if cell_idx != -1:
|
|
242
|
+
nijk = args.cell_ijk[cell_idx]
|
|
243
|
+
scale = AdaptiveNanogrid._cell_scale(args, cell_idx)
|
|
244
|
+
coords = (uvw - wp.vec3(nijk)) / scale
|
|
245
|
+
dist, proj_coords = Nanogrid._project_on_voxel_at_origin(coords)
|
|
246
|
+
dist *= scale
|
|
247
|
+
if dist <= closest_dist:
|
|
248
|
+
closest_dist = dist
|
|
249
|
+
closest_voxel = cell_idx
|
|
250
|
+
closest_coords = proj_coords
|
|
251
|
+
|
|
252
|
+
return make_free_sample(closest_voxel, closest_coords)
|
|
253
|
+
|
|
254
|
+
@wp.func
|
|
255
|
+
def cell_measure(args: CellArg, s: Sample):
|
|
256
|
+
scale = AdaptiveNanogrid._cell_scale(args, s.element_index)
|
|
257
|
+
return args.cell_volume * scale * scale * scale
|
|
258
|
+
|
|
259
|
+
@wp.func
|
|
260
|
+
def cell_normal(args: CellArg, s: Sample):
|
|
261
|
+
return wp.vec3(0.0)
|
|
262
|
+
|
|
263
|
+
SideIndexArg = Nanogrid.SideIndexArg
|
|
264
|
+
side_index_arg_value = Nanogrid.side_index_arg_value
|
|
265
|
+
|
|
266
|
+
SideArg = AdaptiveNanogridSideArg
|
|
267
|
+
|
|
268
|
+
@wp.func
|
|
269
|
+
def side_to_cell_arg(side_arg: SideArg):
|
|
270
|
+
return side_arg.cell_arg
|
|
271
|
+
|
|
272
|
+
@cache.cached_arg_value
|
|
273
|
+
def side_arg_value(self, device) -> SideArg:
|
|
274
|
+
self._ensure_face_grid()
|
|
275
|
+
|
|
276
|
+
args = self.SideArg()
|
|
277
|
+
args.cell_arg = self.cell_arg_value(device)
|
|
278
|
+
args.face_ijk = self._face_ijk.to(device)
|
|
279
|
+
args.face_flags = self._face_flags.to(device)
|
|
280
|
+
args.face_cell_indices = self._face_cell_indices.to(device)
|
|
281
|
+
transform = self.transform
|
|
282
|
+
args.face_areas = wp.vec3(
|
|
283
|
+
tuple(np.linalg.norm(np.cross(transform[:, k - 2], transform[:, k - 1])) for k in range(3))
|
|
284
|
+
)
|
|
285
|
+
|
|
286
|
+
return args
|
|
287
|
+
|
|
288
|
+
@wp.func
|
|
289
|
+
def boundary_side_index(args: SideIndexArg, boundary_side_index: int):
|
|
290
|
+
return args.boundary_face_indices[boundary_side_index]
|
|
291
|
+
|
|
292
|
+
@wp.func
|
|
293
|
+
def _get_face_level(flags: wp.uint8):
|
|
294
|
+
return wp.int32(flags >> _FACE_LEVEL_BIT)
|
|
295
|
+
|
|
296
|
+
@wp.func
|
|
297
|
+
def _get_face_scale(flags: wp.uint8):
|
|
298
|
+
return float(1 << AdaptiveNanogrid._get_face_level(flags))
|
|
299
|
+
|
|
300
|
+
@wp.func
|
|
301
|
+
def side_position(args: SideArg, s: Sample):
|
|
302
|
+
ijk = args.face_ijk[s.element_index]
|
|
303
|
+
flags = args.face_flags[s.element_index]
|
|
304
|
+
axis = Nanogrid._get_face_axis(flags)
|
|
305
|
+
scale = AdaptiveNanogrid._get_face_scale(flags)
|
|
306
|
+
|
|
307
|
+
uvw = wp.vec3(ijk) + scale * Nanogrid._side_to_cell_coords(axis, 0.0, s.element_coords)
|
|
308
|
+
|
|
309
|
+
cell_grid = args.cell_arg.cell_grid
|
|
310
|
+
return wp.volume_index_to_world(cell_grid, uvw - wp.vec3(0.5))
|
|
311
|
+
|
|
312
|
+
@wp.func
|
|
313
|
+
def side_deformation_gradient(args: SideArg, s: Sample):
|
|
314
|
+
flags = args.face_flags[s.element_index]
|
|
315
|
+
axis = Nanogrid._get_face_axis(flags)
|
|
316
|
+
flip = Nanogrid._get_face_inner_offset(flags)
|
|
317
|
+
scale = AdaptiveNanogrid._get_face_scale(flags)
|
|
318
|
+
v1, v2 = Nanogrid._face_tangent_vecs(args.cell_arg.cell_grid, axis, flip)
|
|
319
|
+
return _mat32(v1, v2) * scale
|
|
320
|
+
|
|
321
|
+
@wp.func
|
|
322
|
+
def side_inner_inverse_deformation_gradient(args: SideArg, s: Sample):
|
|
323
|
+
s_cell = make_free_sample(AdaptiveNanogrid.side_inner_cell_index(args, s.element_index), Coords())
|
|
324
|
+
return AdaptiveNanogrid.cell_inverse_deformation_gradient(args.cell_arg, s_cell)
|
|
325
|
+
|
|
326
|
+
@wp.func
|
|
327
|
+
def side_outer_inverse_deformation_gradient(args: SideArg, s: Sample):
|
|
328
|
+
s_cell = make_free_sample(AdaptiveNanogrid.side_outer_cell_index(args, s.element_index), Coords())
|
|
329
|
+
return AdaptiveNanogrid.cell_inverse_deformation_gradient(args.cell_arg, s_cell)
|
|
330
|
+
|
|
331
|
+
@wp.func
|
|
332
|
+
def side_measure(args: SideArg, s: Sample):
|
|
333
|
+
flags = args.face_flags[s.element_index]
|
|
334
|
+
axis = Nanogrid._get_face_axis(flags)
|
|
335
|
+
scale = AdaptiveNanogrid._get_face_scale(flags)
|
|
336
|
+
return args.face_areas[axis] * scale * scale
|
|
337
|
+
|
|
338
|
+
@wp.func
|
|
339
|
+
def side_measure_ratio(args: SideArg, s: Sample):
|
|
340
|
+
flags = args.face_flags[s.element_index]
|
|
341
|
+
axis = Nanogrid._get_face_axis(flags)
|
|
342
|
+
scale = AdaptiveNanogrid._get_face_scale(flags)
|
|
343
|
+
return args.face_areas[axis] / (args.cell_arg.cell_volume * scale)
|
|
344
|
+
|
|
345
|
+
@wp.func
|
|
346
|
+
def side_normal(args: SideArg, s: Sample):
|
|
347
|
+
flags = args.face_flags[s.element_index]
|
|
348
|
+
axis = Nanogrid._get_face_axis(flags)
|
|
349
|
+
flip = Nanogrid._get_face_inner_offset(flags)
|
|
350
|
+
|
|
351
|
+
v1, v2 = Nanogrid._face_tangent_vecs(args.cell_arg.cell_grid, axis, flip)
|
|
352
|
+
return wp.cross(v1, v2) / args.face_areas[axis]
|
|
353
|
+
|
|
354
|
+
@wp.func
|
|
355
|
+
def side_inner_cell_index(args: SideArg, side_index: ElementIndex):
|
|
356
|
+
return args.face_cell_indices[side_index][0]
|
|
357
|
+
|
|
358
|
+
@wp.func
|
|
359
|
+
def side_outer_cell_index(args: SideArg, side_index: ElementIndex):
|
|
360
|
+
return args.face_cell_indices[side_index][1]
|
|
361
|
+
|
|
362
|
+
@wp.func
|
|
363
|
+
def _coarse_cell_coords(
|
|
364
|
+
fine_ijk: wp.vec3i,
|
|
365
|
+
fine_level: int,
|
|
366
|
+
fine_coords: Coords,
|
|
367
|
+
coarse_ijk: wp.vec3i,
|
|
368
|
+
coarse_level: int,
|
|
369
|
+
):
|
|
370
|
+
return (wp.vec3f(fine_ijk - coarse_ijk) + fine_coords * float(1 << fine_level)) / float(1 << coarse_level)
|
|
371
|
+
|
|
372
|
+
@wp.func
|
|
373
|
+
def side_inner_cell_coords(args: SideArg, side_index: ElementIndex, side_coords: Coords):
|
|
374
|
+
flags = args.face_flags[side_index]
|
|
375
|
+
axis = Nanogrid._get_face_axis(flags)
|
|
376
|
+
offset = Nanogrid._get_face_inner_offset(flags)
|
|
377
|
+
|
|
378
|
+
same_level_cell_coords = Nanogrid._side_to_cell_coords(axis, 1.0 - float(offset), side_coords)
|
|
379
|
+
same_level_cell_ijk = args.face_ijk[side_index]
|
|
380
|
+
side_level = AdaptiveNanogrid._get_face_level(flags)
|
|
381
|
+
same_level_cell_ijk[axis] += (offset - 1) << side_level
|
|
382
|
+
|
|
383
|
+
cell_index = AdaptiveNanogrid.side_inner_cell_index(args, side_index)
|
|
384
|
+
cell_level = int(args.cell_arg.cell_level[cell_index])
|
|
385
|
+
cell_ijk = args.cell_arg.cell_ijk[cell_index]
|
|
386
|
+
|
|
387
|
+
return AdaptiveNanogrid._coarse_cell_coords(
|
|
388
|
+
same_level_cell_ijk, side_level, same_level_cell_coords, cell_ijk, cell_level
|
|
389
|
+
)
|
|
390
|
+
|
|
391
|
+
@wp.func
|
|
392
|
+
def side_outer_cell_coords(args: SideArg, side_index: ElementIndex, side_coords: Coords):
|
|
393
|
+
flags = args.face_flags[side_index]
|
|
394
|
+
axis = Nanogrid._get_face_axis(flags)
|
|
395
|
+
offset = Nanogrid._get_face_outer_offset(flags)
|
|
396
|
+
|
|
397
|
+
same_level_cell_coords = Nanogrid._side_to_cell_coords(axis, float(offset), side_coords)
|
|
398
|
+
same_level_cell_ijk = args.face_ijk[side_index]
|
|
399
|
+
side_level = AdaptiveNanogrid._get_face_level(flags)
|
|
400
|
+
same_level_cell_ijk[axis] -= offset << side_level
|
|
401
|
+
|
|
402
|
+
cell_index = AdaptiveNanogrid.side_outer_cell_index(args, side_index)
|
|
403
|
+
cell_level = int(args.cell_arg.cell_level[cell_index])
|
|
404
|
+
cell_ijk = args.cell_arg.cell_ijk[cell_index]
|
|
405
|
+
|
|
406
|
+
return AdaptiveNanogrid._coarse_cell_coords(
|
|
407
|
+
same_level_cell_ijk, side_level, same_level_cell_coords, cell_ijk, cell_level
|
|
408
|
+
)
|
|
409
|
+
|
|
410
|
+
@wp.func
|
|
411
|
+
def side_from_cell_coords(
|
|
412
|
+
args: SideArg,
|
|
413
|
+
side_index: ElementIndex,
|
|
414
|
+
element_index: ElementIndex,
|
|
415
|
+
element_coords: Coords,
|
|
416
|
+
):
|
|
417
|
+
flags = args.face_flags[side_index]
|
|
418
|
+
axis = Nanogrid._get_face_axis(flags)
|
|
419
|
+
side_level = AdaptiveNanogrid._get_face_level(flags)
|
|
420
|
+
cell_level = int(args.cell_arg.cell_level[element_index])
|
|
421
|
+
|
|
422
|
+
cell_ijk = args.cell_arg.cell_ijk[element_index]
|
|
423
|
+
side_ijk = args.face_ijk[side_index]
|
|
424
|
+
|
|
425
|
+
same_level_cell_coords = AdaptiveNanogrid._coarse_cell_coords(
|
|
426
|
+
cell_ijk, cell_level, element_coords, side_ijk, side_level
|
|
427
|
+
)
|
|
428
|
+
|
|
429
|
+
on_side = (
|
|
430
|
+
same_level_cell_coords[axis] == 0.0
|
|
431
|
+
and wp.min(same_level_cell_coords) >= 0.0
|
|
432
|
+
and wp.max(same_level_cell_coords) <= 1.0
|
|
433
|
+
)
|
|
434
|
+
|
|
435
|
+
return wp.select(
|
|
436
|
+
on_side,
|
|
437
|
+
Coords(OUTSIDE),
|
|
438
|
+
Coords(same_level_cell_coords[(axis + 1) % 3], same_level_cell_coords[(axis + 2) % 3], 0.0),
|
|
439
|
+
)
|
|
440
|
+
|
|
441
|
+
def _build_face_grid(self, temporary_store: Optional[cache.TemporaryStore] = None):
|
|
442
|
+
device = self._cell_grid.device
|
|
443
|
+
|
|
444
|
+
# Create a first grid with faces from cells
|
|
445
|
+
cell_face_grid = _build_cell_face_grid(self._cell_ijk, self._cell_level, self._cell_grid, temporary_store)
|
|
446
|
+
|
|
447
|
+
# Complete faces at resolution boundaries
|
|
448
|
+
self._face_grid = _build_completed_face_grid(
|
|
449
|
+
cell_face_grid, self._cell_grid, self.level_count, self._cell_level, temporary_store
|
|
450
|
+
)
|
|
451
|
+
|
|
452
|
+
face_count = self._face_grid.get_voxel_count()
|
|
453
|
+
self._face_ijk = wp.array(shape=(face_count,), dtype=wp.vec3i, device=device)
|
|
454
|
+
self._face_grid.get_voxels(out=self._face_ijk)
|
|
455
|
+
|
|
456
|
+
# Finalize our faces, cache flags and neighbour indices
|
|
457
|
+
self._face_cell_indices = wp.array(shape=(face_count,), dtype=wp.vec2i, device=device)
|
|
458
|
+
self._face_flags = wp.array(shape=(face_count,), dtype=wp.uint8, device=device)
|
|
459
|
+
boundary_face_mask = cache.borrow_temporary(temporary_store, shape=(face_count,), dtype=wp.int32, device=device)
|
|
460
|
+
|
|
461
|
+
wp.launch(
|
|
462
|
+
_build_face_indices_and_flags,
|
|
463
|
+
dim=face_count,
|
|
464
|
+
device=device,
|
|
465
|
+
inputs=[
|
|
466
|
+
self._cell_grid.id,
|
|
467
|
+
self.level_count,
|
|
468
|
+
self._cell_level,
|
|
469
|
+
self._face_ijk,
|
|
470
|
+
self._face_cell_indices,
|
|
471
|
+
self._face_flags,
|
|
472
|
+
boundary_face_mask.array,
|
|
473
|
+
],
|
|
474
|
+
)
|
|
475
|
+
boundary_face_indices, _ = utils.masked_indices(boundary_face_mask.array)
|
|
476
|
+
self._boundary_face_indices = boundary_face_indices.detach()
|
|
477
|
+
|
|
478
|
+
def _ensure_face_grid(self):
|
|
479
|
+
if self._face_ijk is None:
|
|
480
|
+
self._build_face_grid()
|
|
481
|
+
|
|
482
|
+
def _ensure_stacked_edge_grid(self):
|
|
483
|
+
if self._stacked_edge_grid is None:
|
|
484
|
+
self._stacked_edge_grid = _build_stacked_edge_grid(
|
|
485
|
+
self._cell_ijk, self._cell_level, self._cell_grid, temporary_store=None
|
|
486
|
+
)
|
|
487
|
+
self._stacked_edge_count = self._stacked_edge_grid.get_voxel_count()
|
|
488
|
+
|
|
489
|
+
def _ensure_stacked_face_grid(self):
|
|
490
|
+
if self._stacked_face_grid is None:
|
|
491
|
+
self._stacked_face_grid = _build_stacked_face_grid(
|
|
492
|
+
self._cell_ijk, self._cell_level, self._cell_grid, temporary_store=None
|
|
493
|
+
)
|
|
494
|
+
self._stacked_face_count = self._stacked_face_grid.get_voxel_count()
|
|
495
|
+
|
|
496
|
+
@wp.func
|
|
497
|
+
def coarse_ijk(ijk: wp.vec3i, level: int):
|
|
498
|
+
# technically implementation-defined, but
|
|
499
|
+
# right-shifting negative numbers 1-fills on all our platforms
|
|
500
|
+
return wp.vec3i(ijk[0] >> level, ijk[1] >> level, ijk[2] >> level)
|
|
501
|
+
|
|
502
|
+
@wp.func
|
|
503
|
+
def fine_ijk(ijk: wp.vec3i, level: int):
|
|
504
|
+
# Our coords cannot exceed 1<<21,so no worries about overwriting the sign bit
|
|
505
|
+
return wp.vec3i(ijk[0] << level, ijk[1] << level, ijk[2] << level)
|
|
506
|
+
|
|
507
|
+
@wp.func
|
|
508
|
+
def encode_axis_and_level(ijk: wp.vec3i, axis: int, level: int):
|
|
509
|
+
# Embed a 3-bit level in the voxel coordinates
|
|
510
|
+
# by switching the _GRID_LEVEL_BIT for each axis
|
|
511
|
+
|
|
512
|
+
for ax in range(3):
|
|
513
|
+
coord = ijk[ax]
|
|
514
|
+
level_flag = ((level >> ax) & 1) << _GRID_LEVEL_BIT
|
|
515
|
+
ijk[ax] = wp.select(coord < 0, coord | level_flag, coord & ~level_flag)
|
|
516
|
+
|
|
517
|
+
return _add_axis_flag(ijk, axis)
|
|
518
|
+
|
|
519
|
+
@wp.func
|
|
520
|
+
def find_cell(
|
|
521
|
+
cell_grid: wp.uint64,
|
|
522
|
+
ijk: wp.vec3i,
|
|
523
|
+
level_count: int,
|
|
524
|
+
cell_level: wp.array(dtype=wp.uint8),
|
|
525
|
+
):
|
|
526
|
+
for l in range(level_count):
|
|
527
|
+
mask = ~((1 << l) - 1)
|
|
528
|
+
cell_index = wp.volume_lookup_index(cell_grid, ijk[0] & mask, ijk[1] & mask, ijk[2] & mask)
|
|
529
|
+
if cell_index != -1:
|
|
530
|
+
if int(cell_level[cell_index]) >= l:
|
|
531
|
+
return cell_index
|
|
532
|
+
|
|
533
|
+
return -1
|
|
534
|
+
|
|
535
|
+
|
|
536
|
+
@wp.kernel
|
|
537
|
+
def _cell_node_indices(
|
|
538
|
+
cell_ijk: wp.array(dtype=wp.vec3i),
|
|
539
|
+
cell_level: wp.array(dtype=wp.uint8),
|
|
540
|
+
node_ijk: wp.array2d(dtype=wp.vec3i),
|
|
541
|
+
):
|
|
542
|
+
cell, n = wp.tid()
|
|
543
|
+
level = int(cell_level[cell])
|
|
544
|
+
offset = AdaptiveNanogrid.fine_ijk(wp.vec3i((n & 4) >> 2, (n & 2) >> 1, n & 1), level)
|
|
545
|
+
node_ijk[cell, n] = cell_ijk[cell] + offset
|
|
546
|
+
|
|
547
|
+
|
|
548
|
+
@wp.kernel
|
|
549
|
+
def _cell_face_indices(
|
|
550
|
+
cell_ijk: wp.array(dtype=wp.vec3i),
|
|
551
|
+
cell_level: wp.array(dtype=wp.uint8),
|
|
552
|
+
node_ijk: wp.array2d(dtype=wp.vec3i),
|
|
553
|
+
):
|
|
554
|
+
cell = wp.tid()
|
|
555
|
+
ijk = cell_ijk[cell]
|
|
556
|
+
node_ijk[cell, 0] = _add_axis_flag(ijk, 0)
|
|
557
|
+
node_ijk[cell, 1] = _add_axis_flag(ijk, 1)
|
|
558
|
+
node_ijk[cell, 2] = _add_axis_flag(ijk, 2)
|
|
559
|
+
|
|
560
|
+
offset = 1 << int(cell_level[cell])
|
|
561
|
+
|
|
562
|
+
node_ijk[cell, 3] = _add_axis_flag(ijk + wp.vec3i(offset, 0, 0), 0)
|
|
563
|
+
node_ijk[cell, 4] = _add_axis_flag(ijk + wp.vec3i(0, offset, 0), 1)
|
|
564
|
+
node_ijk[cell, 5] = _add_axis_flag(ijk + wp.vec3i(0, 0, offset), 2)
|
|
565
|
+
|
|
566
|
+
|
|
567
|
+
@wp.kernel
|
|
568
|
+
def _cell_stacked_face_indices(
|
|
569
|
+
cell_ijk: wp.array(dtype=wp.vec3i),
|
|
570
|
+
cell_level: wp.array(dtype=wp.uint8),
|
|
571
|
+
node_ijk: wp.array2d(dtype=wp.vec3i),
|
|
572
|
+
):
|
|
573
|
+
cell = wp.tid()
|
|
574
|
+
|
|
575
|
+
level = int(cell_level[cell])
|
|
576
|
+
ijk = AdaptiveNanogrid.coarse_ijk(cell_ijk[cell], level)
|
|
577
|
+
|
|
578
|
+
node_ijk[cell, 0] = AdaptiveNanogrid.encode_axis_and_level(ijk, 0, level)
|
|
579
|
+
node_ijk[cell, 1] = AdaptiveNanogrid.encode_axis_and_level(ijk, 1, level)
|
|
580
|
+
node_ijk[cell, 2] = AdaptiveNanogrid.encode_axis_and_level(ijk, 2, level)
|
|
581
|
+
|
|
582
|
+
node_ijk[cell, 3] = AdaptiveNanogrid.encode_axis_and_level(ijk + wp.vec3i(1, 0, 0), 0, level)
|
|
583
|
+
node_ijk[cell, 4] = AdaptiveNanogrid.encode_axis_and_level(ijk + wp.vec3i(0, 1, 0), 1, level)
|
|
584
|
+
node_ijk[cell, 5] = AdaptiveNanogrid.encode_axis_and_level(ijk + wp.vec3i(0, 0, 1), 2, level)
|
|
585
|
+
|
|
586
|
+
|
|
587
|
+
@wp.kernel
|
|
588
|
+
def _cell_stacked_edge_indices(
|
|
589
|
+
cell_ijk: wp.array(dtype=wp.vec3i),
|
|
590
|
+
cell_level: wp.array(dtype=wp.uint8),
|
|
591
|
+
edge_ijk: wp.array2d(dtype=wp.vec3i),
|
|
592
|
+
):
|
|
593
|
+
cell = wp.tid()
|
|
594
|
+
level = int(cell_level[cell])
|
|
595
|
+
ijk = AdaptiveNanogrid.coarse_ijk(cell_ijk[cell], level)
|
|
596
|
+
|
|
597
|
+
edge_ijk[cell, 0] = AdaptiveNanogrid.encode_axis_and_level(ijk, 0, level)
|
|
598
|
+
edge_ijk[cell, 1] = AdaptiveNanogrid.encode_axis_and_level(ijk, 1, level)
|
|
599
|
+
edge_ijk[cell, 2] = AdaptiveNanogrid.encode_axis_and_level(ijk, 2, level)
|
|
600
|
+
|
|
601
|
+
edge_ijk[cell, 3] = AdaptiveNanogrid.encode_axis_and_level(ijk + wp.vec3i(0, 1, 0), 0, level)
|
|
602
|
+
edge_ijk[cell, 4] = AdaptiveNanogrid.encode_axis_and_level(ijk + wp.vec3i(0, 0, 1), 1, level)
|
|
603
|
+
edge_ijk[cell, 5] = AdaptiveNanogrid.encode_axis_and_level(ijk + wp.vec3i(1, 0, 0), 2, level)
|
|
604
|
+
|
|
605
|
+
edge_ijk[cell, 6] = AdaptiveNanogrid.encode_axis_and_level(ijk + wp.vec3i(0, 1, 1), 0, level)
|
|
606
|
+
edge_ijk[cell, 7] = AdaptiveNanogrid.encode_axis_and_level(ijk + wp.vec3i(1, 0, 1), 1, level)
|
|
607
|
+
edge_ijk[cell, 8] = AdaptiveNanogrid.encode_axis_and_level(ijk + wp.vec3i(1, 1, 0), 2, level)
|
|
608
|
+
|
|
609
|
+
edge_ijk[cell, 9] = AdaptiveNanogrid.encode_axis_and_level(ijk + wp.vec3i(0, 0, 1), 0, level)
|
|
610
|
+
edge_ijk[cell, 10] = AdaptiveNanogrid.encode_axis_and_level(ijk + wp.vec3i(1, 0, 0), 1, level)
|
|
611
|
+
edge_ijk[cell, 11] = AdaptiveNanogrid.encode_axis_and_level(ijk + wp.vec3i(0, 1, 0), 2, level)
|
|
612
|
+
|
|
613
|
+
|
|
614
|
+
def _build_node_grid(cell_ijk, cell_level, cell_grid: wp.Volume, temporary_store: cache.TemporaryStore):
|
|
615
|
+
cell_count = cell_ijk.shape[0]
|
|
616
|
+
|
|
617
|
+
cell_nodes = cache.borrow_temporary(temporary_store, shape=(cell_count, 8), dtype=wp.vec3i, device=cell_ijk.device)
|
|
618
|
+
wp.launch(
|
|
619
|
+
_cell_node_indices,
|
|
620
|
+
dim=cell_nodes.array.shape,
|
|
621
|
+
inputs=[cell_ijk, cell_level, cell_nodes.array],
|
|
622
|
+
device=cell_ijk.device,
|
|
623
|
+
)
|
|
624
|
+
node_grid = wp.Volume.allocate_by_voxels(
|
|
625
|
+
cell_nodes.array.flatten(), voxel_size=cell_grid.get_voxel_size()[0], device=cell_ijk.device
|
|
626
|
+
)
|
|
627
|
+
|
|
628
|
+
return node_grid
|
|
629
|
+
|
|
630
|
+
|
|
631
|
+
def _build_cell_face_grid(cell_ijk, cell_level, grid: wp.Volume, temporary_store: cache.TemporaryStore):
|
|
632
|
+
cell_count = cell_ijk.shape[0]
|
|
633
|
+
|
|
634
|
+
cell_faces = cache.borrow_temporary(temporary_store, shape=(cell_count, 6), dtype=wp.vec3i, device=cell_ijk.device)
|
|
635
|
+
wp.launch(
|
|
636
|
+
_cell_face_indices, dim=cell_count, inputs=[cell_ijk, cell_level, cell_faces.array], device=cell_ijk.device
|
|
637
|
+
)
|
|
638
|
+
face_grid = wp.Volume.allocate_by_voxels(
|
|
639
|
+
cell_faces.array.flatten(), voxel_size=grid.get_voxel_size()[0], device=cell_ijk.device
|
|
640
|
+
)
|
|
641
|
+
|
|
642
|
+
return face_grid
|
|
643
|
+
|
|
644
|
+
|
|
645
|
+
def _build_completed_face_grid(
|
|
646
|
+
cell_face_grid: wp.Volume,
|
|
647
|
+
cell_grid: wp.Volume,
|
|
648
|
+
level_count: int,
|
|
649
|
+
cell_level: wp.array,
|
|
650
|
+
temporary_store: cache.TemporaryStore,
|
|
651
|
+
):
|
|
652
|
+
device = cell_grid.device
|
|
653
|
+
|
|
654
|
+
cell_face_count = cell_face_grid.get_voxel_count()
|
|
655
|
+
cell_face_ijk = cache.borrow_temporary(temporary_store, shape=(cell_face_count,), dtype=wp.vec3i, device=device)
|
|
656
|
+
|
|
657
|
+
additional_face_count = cache.borrow_temporary(temporary_store, shape=1, dtype=int, device=device)
|
|
658
|
+
|
|
659
|
+
# Count the number of supplemental faces we need to add at resolution boundaries
|
|
660
|
+
cell_face_grid.get_voxels(out=cell_face_ijk.array)
|
|
661
|
+
additional_face_count.array.zero_()
|
|
662
|
+
wp.launch(
|
|
663
|
+
_count_multires_faces,
|
|
664
|
+
dim=cell_face_count,
|
|
665
|
+
device=device,
|
|
666
|
+
inputs=[
|
|
667
|
+
cell_grid.id,
|
|
668
|
+
level_count,
|
|
669
|
+
cell_level,
|
|
670
|
+
cell_face_ijk.array,
|
|
671
|
+
additional_face_count.array,
|
|
672
|
+
],
|
|
673
|
+
)
|
|
674
|
+
|
|
675
|
+
# Cat these new faces with the original ones
|
|
676
|
+
cat_face_count = cell_face_count + int(additional_face_count.array.numpy()[0])
|
|
677
|
+
cat_face_ijk = cache.borrow_temporary(temporary_store, shape=(cat_face_count,), dtype=wp.vec3i, device=device)
|
|
678
|
+
wp.copy(src=cell_face_ijk.array, dest=cat_face_ijk.array, dest_offset=cat_face_count - cell_face_count)
|
|
679
|
+
|
|
680
|
+
wp.launch(
|
|
681
|
+
_fill_multires_faces,
|
|
682
|
+
dim=cell_face_count,
|
|
683
|
+
device=device,
|
|
684
|
+
inputs=[
|
|
685
|
+
cell_grid.id,
|
|
686
|
+
level_count,
|
|
687
|
+
cell_level,
|
|
688
|
+
cell_face_ijk.array,
|
|
689
|
+
additional_face_count.array,
|
|
690
|
+
cat_face_ijk.array,
|
|
691
|
+
],
|
|
692
|
+
)
|
|
693
|
+
|
|
694
|
+
# Now recreate a new grid with all those faces
|
|
695
|
+
face_grid = wp.Volume.allocate_by_voxels(
|
|
696
|
+
cat_face_ijk.array.flatten(), voxel_size=cell_face_grid.get_voxel_size(), device=device
|
|
697
|
+
)
|
|
698
|
+
|
|
699
|
+
return face_grid
|
|
700
|
+
|
|
701
|
+
|
|
702
|
+
def _build_stacked_face_grid(cell_ijk, cell_level, grid: wp.Volume, temporary_store: cache.TemporaryStore):
|
|
703
|
+
cell_count = cell_ijk.shape[0]
|
|
704
|
+
|
|
705
|
+
cell_faces = cache.borrow_temporary(temporary_store, shape=(cell_count, 6), dtype=wp.vec3i, device=cell_ijk.device)
|
|
706
|
+
wp.launch(
|
|
707
|
+
_cell_stacked_face_indices,
|
|
708
|
+
dim=cell_count,
|
|
709
|
+
inputs=[cell_ijk, cell_level, cell_faces.array],
|
|
710
|
+
device=cell_ijk.device,
|
|
711
|
+
)
|
|
712
|
+
face_grid = wp.Volume.allocate_by_voxels(
|
|
713
|
+
cell_faces.array.flatten(), voxel_size=grid.get_voxel_size()[0], device=cell_ijk.device
|
|
714
|
+
)
|
|
715
|
+
|
|
716
|
+
return face_grid
|
|
717
|
+
|
|
718
|
+
|
|
719
|
+
def _build_stacked_edge_grid(cell_ijk, cell_level, grid: wp.Volume, temporary_store: cache.TemporaryStore):
|
|
720
|
+
cell_count = cell_ijk.shape[0]
|
|
721
|
+
|
|
722
|
+
cell_edges = cache.borrow_temporary(temporary_store, shape=(cell_count, 12), dtype=wp.vec3i, device=cell_ijk.device)
|
|
723
|
+
wp.launch(
|
|
724
|
+
_cell_stacked_edge_indices,
|
|
725
|
+
dim=cell_count,
|
|
726
|
+
inputs=[cell_ijk, cell_level, cell_edges.array],
|
|
727
|
+
device=cell_ijk.device,
|
|
728
|
+
)
|
|
729
|
+
edge_grid = wp.Volume.allocate_by_voxels(
|
|
730
|
+
cell_edges.array.flatten(), voxel_size=grid.get_voxel_size()[0], device=cell_ijk.device
|
|
731
|
+
)
|
|
732
|
+
|
|
733
|
+
return edge_grid
|
|
734
|
+
|
|
735
|
+
|
|
736
|
+
@wp.func
|
|
737
|
+
def _find_face_neighbours(
|
|
738
|
+
cell_grid: wp.uint64,
|
|
739
|
+
ijk: wp.vec3i,
|
|
740
|
+
axis: int,
|
|
741
|
+
level_count: int,
|
|
742
|
+
cell_level: wp.array(dtype=wp.uint8),
|
|
743
|
+
):
|
|
744
|
+
ijk_minus = ijk
|
|
745
|
+
ijk_minus[axis] -= 1
|
|
746
|
+
|
|
747
|
+
plus_cell_index = AdaptiveNanogrid.find_cell(cell_grid, ijk, level_count, cell_level)
|
|
748
|
+
minus_cell_index = AdaptiveNanogrid.find_cell(cell_grid, ijk_minus, level_count, cell_level)
|
|
749
|
+
return plus_cell_index, minus_cell_index
|
|
750
|
+
|
|
751
|
+
|
|
752
|
+
@wp.kernel
|
|
753
|
+
def _count_multires_faces(
|
|
754
|
+
cell_grid: wp.uint64,
|
|
755
|
+
level_count: int,
|
|
756
|
+
cell_level: wp.array(dtype=wp.uint8),
|
|
757
|
+
face_ijk: wp.array(dtype=wp.vec3i),
|
|
758
|
+
count: wp.array(dtype=int),
|
|
759
|
+
):
|
|
760
|
+
face = wp.tid()
|
|
761
|
+
|
|
762
|
+
axis, ijk = _extract_axis_flag(face_ijk[face])
|
|
763
|
+
|
|
764
|
+
plus_cell_index, minus_cell_index = _find_face_neighbours(cell_grid, ijk, axis, level_count, cell_level)
|
|
765
|
+
|
|
766
|
+
if plus_cell_index == -1 or minus_cell_index == -1:
|
|
767
|
+
return
|
|
768
|
+
|
|
769
|
+
plus_level = int(cell_level[plus_cell_index])
|
|
770
|
+
minus_level = int(cell_level[minus_cell_index])
|
|
771
|
+
level_diff = wp.abs(plus_level - minus_level)
|
|
772
|
+
|
|
773
|
+
if level_diff != 0:
|
|
774
|
+
fine_face_count = 1 << (2 * level_diff)
|
|
775
|
+
wp.atomic_add(count, 0, fine_face_count)
|
|
776
|
+
|
|
777
|
+
|
|
778
|
+
@wp.kernel
|
|
779
|
+
def _fill_multires_faces(
|
|
780
|
+
cell_grid: wp.uint64,
|
|
781
|
+
level_count: int,
|
|
782
|
+
cell_level: wp.array(dtype=wp.uint8),
|
|
783
|
+
face_ijk: wp.array(dtype=wp.vec3i),
|
|
784
|
+
count: wp.array(dtype=int),
|
|
785
|
+
added_ijk: wp.array(dtype=wp.vec3i),
|
|
786
|
+
):
|
|
787
|
+
face = wp.tid()
|
|
788
|
+
|
|
789
|
+
axis, ijk = _extract_axis_flag(face_ijk[face])
|
|
790
|
+
plus_cell_index, minus_cell_index = _find_face_neighbours(cell_grid, ijk, axis, level_count, cell_level)
|
|
791
|
+
|
|
792
|
+
if plus_cell_index == -1 or minus_cell_index == -1:
|
|
793
|
+
return
|
|
794
|
+
|
|
795
|
+
plus_level = int(cell_level[plus_cell_index])
|
|
796
|
+
minus_level = int(cell_level[minus_cell_index])
|
|
797
|
+
level_diff = wp.abs(plus_level - minus_level)
|
|
798
|
+
|
|
799
|
+
if level_diff != 0:
|
|
800
|
+
fine_face_count = 1 << (2 * level_diff)
|
|
801
|
+
side_mask = (1 << level_diff) - 1
|
|
802
|
+
|
|
803
|
+
fine_level = min(plus_level, minus_level)
|
|
804
|
+
base_level = max(plus_level, minus_level)
|
|
805
|
+
|
|
806
|
+
base_mask = ~((1 << base_level) - 1)
|
|
807
|
+
base_ijk = wp.vec3i(ijk[0] & base_mask, ijk[1] & base_mask, ijk[2] & base_mask)
|
|
808
|
+
|
|
809
|
+
offset = wp.atomic_sub(count, 0, fine_face_count) - fine_face_count
|
|
810
|
+
for f in range(fine_face_count):
|
|
811
|
+
f_ijk = base_ijk
|
|
812
|
+
f_ijk[(axis + 1) % 3] |= (f & side_mask) << fine_level
|
|
813
|
+
f_ijk[(axis + 2) % 3] |= (f >> level_diff) << fine_level
|
|
814
|
+
added_ijk[offset + f] = _add_axis_flag(f_ijk, axis)
|
|
815
|
+
|
|
816
|
+
|
|
817
|
+
@wp.kernel
|
|
818
|
+
def _build_face_indices_and_flags(
|
|
819
|
+
cell_grid: wp.uint64,
|
|
820
|
+
level_count: int,
|
|
821
|
+
cell_level: wp.array(dtype=wp.uint8),
|
|
822
|
+
face_ijk: wp.array(dtype=wp.vec3i),
|
|
823
|
+
face_cell_indices: wp.array(dtype=wp.vec2i),
|
|
824
|
+
face_flags: wp.array(dtype=wp.uint8),
|
|
825
|
+
boundary_face_mask: wp.array(dtype=int),
|
|
826
|
+
):
|
|
827
|
+
face = wp.tid()
|
|
828
|
+
|
|
829
|
+
axis, ijk = _extract_axis_flag(face_ijk[face])
|
|
830
|
+
|
|
831
|
+
plus_cell_index, minus_cell_index = _find_face_neighbours(cell_grid, ijk, axis, level_count, cell_level)
|
|
832
|
+
|
|
833
|
+
inner_cell = wp.select(minus_cell_index == -1, minus_cell_index, plus_cell_index)
|
|
834
|
+
outer_cell = wp.select(plus_cell_index == -1, plus_cell_index, minus_cell_index)
|
|
835
|
+
|
|
836
|
+
face_level = wp.min(cell_level[inner_cell], cell_level[outer_cell])
|
|
837
|
+
|
|
838
|
+
face_ijk[face] = ijk
|
|
839
|
+
flags = _make_face_flags(axis, plus_cell_index, minus_cell_index) | (face_level << _FACE_LEVEL_BIT)
|
|
840
|
+
face_flags[face] = flags
|
|
841
|
+
boundary_face_mask[face] = _get_boundary_mask(flags)
|
|
842
|
+
|
|
843
|
+
face_cell_indices[face] = wp.vec2i(inner_cell, outer_cell)
|