warp-lang 1.1.0__py3-none-manylinux2014_x86_64.whl → 1.2.0__py3-none-manylinux2014_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.
- warp/bin/warp-clang.so +0 -0
- warp/bin/warp.so +0 -0
- warp/build.py +10 -37
- warp/build_dll.py +2 -2
- warp/builtins.py +274 -6
- warp/codegen.py +51 -4
- warp/config.py +2 -2
- warp/constants.py +4 -0
- warp/context.py +418 -203
- warp/examples/benchmarks/benchmark_api.py +0 -2
- warp/examples/benchmarks/benchmark_cloth_warp.py +0 -1
- warp/examples/benchmarks/benchmark_launches.py +0 -2
- warp/examples/core/example_dem.py +0 -2
- warp/examples/core/example_fluid.py +0 -2
- warp/examples/core/example_graph_capture.py +0 -2
- warp/examples/core/example_marching_cubes.py +0 -2
- warp/examples/core/example_mesh.py +0 -2
- warp/examples/core/example_mesh_intersect.py +0 -2
- warp/examples/core/example_nvdb.py +0 -2
- warp/examples/core/example_raycast.py +0 -2
- warp/examples/core/example_raymarch.py +0 -2
- warp/examples/core/example_render_opengl.py +0 -2
- warp/examples/core/example_sph.py +0 -2
- warp/examples/core/example_torch.py +0 -3
- warp/examples/core/example_wave.py +0 -2
- warp/examples/fem/example_apic_fluid.py +140 -115
- warp/examples/fem/example_burgers.py +262 -0
- warp/examples/fem/example_convection_diffusion.py +0 -2
- warp/examples/fem/example_convection_diffusion_dg.py +0 -2
- warp/examples/fem/example_deformed_geometry.py +0 -2
- warp/examples/fem/example_diffusion.py +0 -2
- warp/examples/fem/example_diffusion_3d.py +5 -4
- warp/examples/fem/example_diffusion_mgpu.py +0 -2
- warp/examples/fem/example_mixed_elasticity.py +0 -2
- warp/examples/fem/example_navier_stokes.py +0 -2
- warp/examples/fem/example_stokes.py +0 -2
- warp/examples/fem/example_stokes_transfer.py +0 -2
- warp/examples/optim/example_bounce.py +0 -2
- warp/examples/optim/example_cloth_throw.py +0 -2
- warp/examples/optim/example_diffray.py +0 -2
- warp/examples/optim/example_drone.py +0 -2
- warp/examples/optim/example_inverse_kinematics.py +0 -2
- warp/examples/optim/example_inverse_kinematics_torch.py +0 -2
- warp/examples/optim/example_spring_cage.py +0 -2
- warp/examples/optim/example_trajectory.py +0 -2
- warp/examples/optim/example_walker.py +0 -2
- warp/examples/sim/example_cartpole.py +0 -2
- warp/examples/sim/example_cloth.py +0 -2
- warp/examples/sim/example_granular.py +0 -2
- warp/examples/sim/example_granular_collision_sdf.py +0 -2
- warp/examples/sim/example_jacobian_ik.py +0 -2
- warp/examples/sim/example_particle_chain.py +0 -2
- warp/examples/sim/example_quadruped.py +0 -2
- warp/examples/sim/example_rigid_chain.py +0 -2
- warp/examples/sim/example_rigid_contact.py +0 -2
- warp/examples/sim/example_rigid_force.py +0 -2
- warp/examples/sim/example_rigid_gyroscopic.py +0 -2
- warp/examples/sim/example_rigid_soft_contact.py +0 -2
- warp/examples/sim/example_soft_body.py +0 -2
- warp/fem/__init__.py +1 -0
- warp/fem/cache.py +3 -1
- warp/fem/geometry/__init__.py +1 -0
- warp/fem/geometry/element.py +4 -0
- warp/fem/geometry/grid_3d.py +0 -4
- warp/fem/geometry/nanogrid.py +455 -0
- warp/fem/integrate.py +63 -9
- warp/fem/space/__init__.py +43 -158
- warp/fem/space/basis_space.py +34 -0
- warp/fem/space/collocated_function_space.py +1 -1
- warp/fem/space/grid_2d_function_space.py +13 -132
- warp/fem/space/grid_3d_function_space.py +16 -154
- warp/fem/space/hexmesh_function_space.py +37 -134
- warp/fem/space/nanogrid_function_space.py +202 -0
- warp/fem/space/quadmesh_2d_function_space.py +12 -119
- warp/fem/space/restriction.py +4 -1
- warp/fem/space/shape/__init__.py +77 -0
- warp/fem/space/shape/cube_shape_function.py +5 -15
- warp/fem/space/tetmesh_function_space.py +6 -76
- warp/fem/space/trimesh_2d_function_space.py +6 -76
- warp/native/array.h +12 -3
- warp/native/builtin.h +48 -5
- warp/native/bvh.cpp +14 -10
- warp/native/bvh.cu +23 -15
- warp/native/bvh.h +1 -0
- warp/native/clang/clang.cpp +2 -1
- warp/native/crt.cpp +11 -1
- warp/native/crt.h +18 -1
- warp/native/exports.h +187 -0
- warp/native/mat.h +47 -0
- warp/native/mesh.cpp +1 -1
- warp/native/mesh.cu +1 -2
- warp/native/nanovdb/GridHandle.h +366 -0
- warp/native/nanovdb/HostBuffer.h +590 -0
- warp/native/nanovdb/NanoVDB.h +3999 -2157
- warp/native/nanovdb/PNanoVDB.h +936 -99
- warp/native/quat.h +28 -1
- warp/native/rand.h +5 -1
- warp/native/vec.h +45 -1
- warp/native/volume.cpp +335 -103
- warp/native/volume.cu +39 -13
- warp/native/volume.h +725 -303
- warp/native/volume_builder.cu +381 -360
- warp/native/volume_builder.h +16 -1
- warp/native/volume_impl.h +61 -0
- warp/native/warp.cu +8 -2
- warp/native/warp.h +15 -7
- warp/render/render_opengl.py +191 -52
- warp/sim/integrator_featherstone.py +10 -3
- warp/sim/integrator_xpbd.py +16 -22
- warp/sparse.py +89 -27
- warp/stubs.py +83 -0
- warp/tests/assets/test_index_grid.nvdb +0 -0
- warp/tests/aux_test_dependent.py +0 -2
- warp/tests/aux_test_grad_customs.py +0 -2
- warp/tests/aux_test_reference.py +0 -2
- warp/tests/aux_test_reference_reference.py +0 -2
- warp/tests/aux_test_square.py +0 -2
- warp/tests/disabled_kinematics.py +0 -2
- warp/tests/test_adam.py +0 -2
- warp/tests/test_arithmetic.py +0 -36
- warp/tests/test_array.py +9 -11
- warp/tests/test_array_reduce.py +0 -2
- warp/tests/test_async.py +0 -2
- warp/tests/test_atomic.py +0 -2
- warp/tests/test_bool.py +58 -50
- warp/tests/test_builtins_resolution.py +0 -2
- warp/tests/test_bvh.py +0 -2
- warp/tests/test_closest_point_edge_edge.py +0 -1
- warp/tests/test_codegen.py +0 -4
- warp/tests/test_compile_consts.py +130 -10
- warp/tests/test_conditional.py +0 -2
- warp/tests/test_copy.py +0 -2
- warp/tests/test_ctypes.py +6 -8
- warp/tests/test_dense.py +0 -2
- warp/tests/test_devices.py +0 -2
- warp/tests/test_dlpack.py +9 -11
- warp/tests/test_examples.py +42 -39
- warp/tests/test_fabricarray.py +0 -3
- warp/tests/test_fast_math.py +0 -2
- warp/tests/test_fem.py +75 -54
- warp/tests/test_fp16.py +0 -2
- warp/tests/test_func.py +0 -2
- warp/tests/test_generics.py +27 -2
- warp/tests/test_grad.py +147 -8
- warp/tests/test_grad_customs.py +0 -2
- warp/tests/test_hash_grid.py +1 -3
- warp/tests/test_import.py +0 -2
- warp/tests/test_indexedarray.py +0 -2
- warp/tests/test_intersect.py +0 -2
- warp/tests/test_jax.py +0 -2
- warp/tests/test_large.py +11 -9
- warp/tests/test_launch.py +0 -2
- warp/tests/test_lerp.py +10 -54
- warp/tests/test_linear_solvers.py +3 -5
- warp/tests/test_lvalue.py +0 -2
- warp/tests/test_marching_cubes.py +0 -2
- warp/tests/test_mat.py +0 -2
- warp/tests/test_mat_lite.py +0 -2
- warp/tests/test_mat_scalar_ops.py +0 -2
- warp/tests/test_math.py +0 -2
- warp/tests/test_matmul.py +35 -37
- warp/tests/test_matmul_lite.py +29 -31
- warp/tests/test_mempool.py +0 -2
- warp/tests/test_mesh.py +0 -3
- warp/tests/test_mesh_query_aabb.py +0 -2
- warp/tests/test_mesh_query_point.py +0 -2
- warp/tests/test_mesh_query_ray.py +0 -2
- warp/tests/test_mlp.py +0 -2
- warp/tests/test_model.py +0 -2
- warp/tests/test_module_hashing.py +111 -0
- warp/tests/test_modules_lite.py +0 -3
- warp/tests/test_multigpu.py +0 -2
- warp/tests/test_noise.py +0 -4
- warp/tests/test_operators.py +0 -2
- warp/tests/test_options.py +0 -2
- warp/tests/test_peer.py +0 -2
- warp/tests/test_pinned.py +0 -2
- warp/tests/test_print.py +0 -2
- warp/tests/test_quat.py +0 -2
- warp/tests/test_rand.py +41 -5
- warp/tests/test_reload.py +0 -10
- warp/tests/test_rounding.py +0 -2
- warp/tests/test_runlength_encode.py +0 -2
- warp/tests/test_sim_grad.py +0 -2
- warp/tests/test_sim_kinematics.py +0 -2
- warp/tests/test_smoothstep.py +0 -2
- warp/tests/test_snippet.py +0 -2
- warp/tests/test_sparse.py +0 -2
- warp/tests/test_spatial.py +0 -2
- warp/tests/test_special_values.py +362 -0
- warp/tests/test_streams.py +0 -2
- warp/tests/test_struct.py +0 -2
- warp/tests/test_tape.py +0 -2
- warp/tests/test_torch.py +0 -2
- warp/tests/test_transient_module.py +0 -2
- warp/tests/test_types.py +0 -2
- warp/tests/test_utils.py +0 -2
- warp/tests/test_vec.py +0 -2
- warp/tests/test_vec_lite.py +0 -2
- warp/tests/test_vec_scalar_ops.py +0 -2
- warp/tests/test_verify_fp.py +0 -2
- warp/tests/test_volume.py +237 -13
- warp/tests/test_volume_write.py +86 -3
- warp/tests/unittest_serial.py +10 -9
- warp/tests/unittest_suites.py +6 -2
- warp/tests/unittest_utils.py +2 -171
- warp/tests/unused_test_misc.py +0 -2
- warp/tests/walkthrough_debug.py +1 -1
- warp/thirdparty/unittest_parallel.py +37 -40
- warp/types.py +514 -77
- {warp_lang-1.1.0.dist-info → warp_lang-1.2.0.dist-info}/METADATA +57 -30
- warp_lang-1.2.0.dist-info/RECORD +359 -0
- warp/examples/fem/example_convection_diffusion_dg0.py +0 -204
- warp/native/nanovdb/PNanoVDBWrite.h +0 -295
- warp_lang-1.1.0.dist-info/RECORD +0 -352
- {warp_lang-1.1.0.dist-info → warp_lang-1.2.0.dist-info}/LICENSE.md +0 -0
- {warp_lang-1.1.0.dist-info → warp_lang-1.2.0.dist-info}/WHEEL +0 -0
- {warp_lang-1.1.0.dist-info → warp_lang-1.2.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,455 @@
|
|
|
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
|
+
|
|
12
|
+
# Flag used for building edge/face grids to disambiguiate axis within the grid
|
|
13
|
+
GRID_AXIS_FLAG = wp.constant(wp.int32(1 << 20))
|
|
14
|
+
FACE_AXIS_MASK = wp.constant(wp.uint8((1 << 3) - 1))
|
|
15
|
+
FACE_INNER_OFFSET_BIT = wp.constant(wp.uint8(3))
|
|
16
|
+
FACE_OUTER_OFFSET_BIT = wp.constant(wp.uint8(4))
|
|
17
|
+
|
|
18
|
+
_mat32 = wp.mat(shape=(3, 2), dtype=float)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@wp.func
|
|
22
|
+
def _add_axis_flag(ijk: wp.vec3i, axis: int):
|
|
23
|
+
coord = ijk[axis]
|
|
24
|
+
ijk[axis] = wp.select(coord < 0, coord | GRID_AXIS_FLAG, coord & (~GRID_AXIS_FLAG))
|
|
25
|
+
return ijk
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@wp.func
|
|
29
|
+
def _extract_axis_flag(ijk: wp.vec3i):
|
|
30
|
+
for ax in range(3):
|
|
31
|
+
coord = ijk[ax]
|
|
32
|
+
if coord < 0:
|
|
33
|
+
if (ijk[ax] & GRID_AXIS_FLAG) == 0:
|
|
34
|
+
ijk[ax] = ijk[ax] | GRID_AXIS_FLAG
|
|
35
|
+
return ax, ijk
|
|
36
|
+
else:
|
|
37
|
+
if (ijk[ax] & GRID_AXIS_FLAG) != 0:
|
|
38
|
+
ijk[ax] = ijk[ax] & (~GRID_AXIS_FLAG)
|
|
39
|
+
return ax, ijk
|
|
40
|
+
|
|
41
|
+
return -1, ijk
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@wp.struct
|
|
45
|
+
class NanogridCellArg:
|
|
46
|
+
# Utility device functions
|
|
47
|
+
cell_grid: wp.uint64
|
|
48
|
+
cell_ijk: wp.array(dtype=wp.vec3i)
|
|
49
|
+
inverse_transform: wp.mat33
|
|
50
|
+
cell_volume: float
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
@wp.struct
|
|
54
|
+
class NanogridSideArg:
|
|
55
|
+
# Utility device functions
|
|
56
|
+
cell_arg: NanogridCellArg
|
|
57
|
+
face_ijk: wp.array(dtype=wp.vec3i)
|
|
58
|
+
face_flags: wp.array(dtype=wp.uint8)
|
|
59
|
+
face_areas: wp.vec3
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class Nanogrid(Geometry):
|
|
63
|
+
dimension = 3
|
|
64
|
+
|
|
65
|
+
def __init__(self, grid: wp.Volume, temporary_store: Optional[cache.TemporaryStore] = None):
|
|
66
|
+
self._cell_grid = grid
|
|
67
|
+
self._cell_grid_info = grid.get_grid_info()
|
|
68
|
+
|
|
69
|
+
device = grid.device
|
|
70
|
+
|
|
71
|
+
cell_count = grid.get_voxel_count()
|
|
72
|
+
self._cell_ijk = wp.array(shape=(cell_count,), dtype=wp.vec3i, device=device)
|
|
73
|
+
grid.get_voxels(out=self._cell_ijk)
|
|
74
|
+
|
|
75
|
+
self._node_grid = _build_node_grid(self._cell_ijk, grid, temporary_store)
|
|
76
|
+
node_count = self._node_grid.get_voxel_count()
|
|
77
|
+
self._node_ijk = wp.array(shape=(node_count,), dtype=wp.vec3i, device=device)
|
|
78
|
+
self._node_grid.get_voxels(out=self._node_ijk)
|
|
79
|
+
|
|
80
|
+
self._face_grid = _build_face_grid(self._cell_ijk, grid, temporary_store)
|
|
81
|
+
face_count = self._face_grid.get_voxel_count()
|
|
82
|
+
self._face_ijk = wp.array(shape=(face_count,), dtype=wp.vec3i, device=device)
|
|
83
|
+
self._face_grid.get_voxels(out=self._face_ijk)
|
|
84
|
+
|
|
85
|
+
self._face_flags = wp.array(shape=(face_count,), dtype=wp.uint8, device=device)
|
|
86
|
+
boundary_face_mask = cache.borrow_temporary(temporary_store, shape=(face_count,), dtype=wp.int32, device=device)
|
|
87
|
+
|
|
88
|
+
wp.launch(
|
|
89
|
+
_build_face_flags,
|
|
90
|
+
dim=face_count,
|
|
91
|
+
device=device,
|
|
92
|
+
inputs=[grid.id, self._face_ijk, self._face_flags, boundary_face_mask.array],
|
|
93
|
+
)
|
|
94
|
+
boundary_face_indices, _ = utils.masked_indices(boundary_face_mask.array)
|
|
95
|
+
self._boundary_face_indices = boundary_face_indices.detach()
|
|
96
|
+
|
|
97
|
+
self._edge_grid = None
|
|
98
|
+
self._edge_ijk = None
|
|
99
|
+
|
|
100
|
+
def _build_edge_grid(self, temporary_store: Optional[cache.TemporaryStore] = None):
|
|
101
|
+
self._edge_grid = _build_edge_grid(self._cell_ijk, self._cell_grid, temporary_store)
|
|
102
|
+
edge_count = self._edge_grid.get_voxel_count()
|
|
103
|
+
self._edge_ijk = wp.array(shape=(edge_count,), dtype=wp.vec3i, device=self._edge_grid.device)
|
|
104
|
+
self._edge_grid.get_voxels(out=self._edge_ijk)
|
|
105
|
+
|
|
106
|
+
def cell_count(self):
|
|
107
|
+
return self._cell_ijk.shape[0]
|
|
108
|
+
|
|
109
|
+
def vertex_count(self):
|
|
110
|
+
return self._node_ijk.shape[0]
|
|
111
|
+
|
|
112
|
+
def side_count(self):
|
|
113
|
+
return self._face_ijk.shape[0]
|
|
114
|
+
|
|
115
|
+
def edge_count(self):
|
|
116
|
+
if self._edge_ijk is None:
|
|
117
|
+
self._build_edge_grid()
|
|
118
|
+
|
|
119
|
+
return self._edge_ijk.shape[0]
|
|
120
|
+
|
|
121
|
+
def boundary_side_count(self):
|
|
122
|
+
return self._boundary_face_indices.shape[0]
|
|
123
|
+
|
|
124
|
+
def reference_cell(self) -> Cube:
|
|
125
|
+
return Cube()
|
|
126
|
+
|
|
127
|
+
def reference_side(self) -> Square:
|
|
128
|
+
return Square()
|
|
129
|
+
|
|
130
|
+
CellArg = NanogridCellArg
|
|
131
|
+
|
|
132
|
+
@cache.cached_arg_value
|
|
133
|
+
def cell_arg_value(self, device) -> CellArg:
|
|
134
|
+
args = self.CellArg()
|
|
135
|
+
args.cell_grid = self._cell_grid.id
|
|
136
|
+
args.cell_ijk = self._cell_ijk
|
|
137
|
+
|
|
138
|
+
transform = np.array(self._cell_grid_info.transform_matrix).reshape(3, 3)
|
|
139
|
+
args.inverse_transform = wp.mat33f(np.linalg.inv(transform))
|
|
140
|
+
args.cell_volume = abs(np.linalg.det(transform))
|
|
141
|
+
|
|
142
|
+
return args
|
|
143
|
+
|
|
144
|
+
@wp.func
|
|
145
|
+
def cell_position(args: CellArg, s: Sample):
|
|
146
|
+
uvw = wp.vec3(args.cell_ijk[s.element_index]) + s.element_coords
|
|
147
|
+
return wp.volume_index_to_world(args.cell_grid, uvw)
|
|
148
|
+
|
|
149
|
+
@wp.func
|
|
150
|
+
def cell_deformation_gradient(args: CellArg, s: Sample):
|
|
151
|
+
return wp.inverse(args.inverse_transform)
|
|
152
|
+
|
|
153
|
+
@wp.func
|
|
154
|
+
def cell_inverse_deformation_gradient(args: CellArg, s: Sample):
|
|
155
|
+
return args.inverse_transform
|
|
156
|
+
|
|
157
|
+
@wp.func
|
|
158
|
+
def cell_lookup(args: CellArg, pos: wp.vec3):
|
|
159
|
+
uvw = wp.volume_world_to_index(args.cell_grid, pos)
|
|
160
|
+
ijk = wp.vec3i(int(wp.floor(uvw[0])), int(wp.floor(uvw[1])), int(wp.floor(uvw[2])))
|
|
161
|
+
element_index = wp.volume_lookup_index(args.cell_grid, ijk[0], ijk[1], ijk[2])
|
|
162
|
+
|
|
163
|
+
return wp.select(
|
|
164
|
+
element_index == -1,
|
|
165
|
+
make_free_sample(element_index, uvw - wp.vec3(ijk)),
|
|
166
|
+
make_free_sample(NULL_ELEMENT_INDEX, Coords(OUTSIDE)),
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
@wp.func
|
|
170
|
+
def cell_lookup(args: CellArg, pos: wp.vec3, guess: Sample):
|
|
171
|
+
return Nanogrid.cell_lookup(args, pos)
|
|
172
|
+
|
|
173
|
+
@wp.func
|
|
174
|
+
def cell_measure(args: CellArg, s: Sample):
|
|
175
|
+
return args.cell_volume
|
|
176
|
+
|
|
177
|
+
@wp.func
|
|
178
|
+
def cell_normal(args: CellArg, s: Sample):
|
|
179
|
+
return wp.vec3(0.0)
|
|
180
|
+
|
|
181
|
+
SideArg = NanogridSideArg
|
|
182
|
+
|
|
183
|
+
@cache.cached_arg_value
|
|
184
|
+
def side_arg_value(self, device) -> SideArg:
|
|
185
|
+
args = self.SideArg()
|
|
186
|
+
args.cell_arg = self.cell_arg_value(device)
|
|
187
|
+
args.face_ijk = self._face_ijk.to(device)
|
|
188
|
+
args.face_flags = self._face_flags.to(device)
|
|
189
|
+
transform = np.array(self._cell_grid_info.transform_matrix).reshape(3, 3)
|
|
190
|
+
args.face_areas = wp.vec3(
|
|
191
|
+
tuple(np.linalg.norm(np.cross(transform[:, k - 2], transform[:, k - 1])) for k in range(3))
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
return args
|
|
195
|
+
|
|
196
|
+
@wp.struct
|
|
197
|
+
class SideIndexArg:
|
|
198
|
+
boundary_face_indices: wp.array(dtype=int)
|
|
199
|
+
|
|
200
|
+
@cache.cached_arg_value
|
|
201
|
+
def side_index_arg_value(self, device) -> SideIndexArg:
|
|
202
|
+
args = self.SideIndexArg()
|
|
203
|
+
args.boundary_face_indices = self._boundary_face_indices.to(device)
|
|
204
|
+
return args
|
|
205
|
+
|
|
206
|
+
@wp.func
|
|
207
|
+
def boundary_side_index(args: SideIndexArg, boundary_side_index: int):
|
|
208
|
+
return args.boundary_face_indices[boundary_side_index]
|
|
209
|
+
|
|
210
|
+
@wp.func
|
|
211
|
+
def _side_to_cell_coords(axis: int, inner: float, side_coords: Coords):
|
|
212
|
+
uvw = wp.vec3()
|
|
213
|
+
uvw[axis] = inner
|
|
214
|
+
uvw[(axis + 1) % 3] = side_coords[0]
|
|
215
|
+
uvw[(axis + 2) % 3] = side_coords[1]
|
|
216
|
+
return uvw
|
|
217
|
+
|
|
218
|
+
@wp.func
|
|
219
|
+
def _get_face_axis(flags: wp.uint8):
|
|
220
|
+
return wp.int32(flags & FACE_AXIS_MASK)
|
|
221
|
+
|
|
222
|
+
@wp.func
|
|
223
|
+
def _get_face_inner_offset(flags: wp.uint8):
|
|
224
|
+
return wp.int32(flags >> FACE_INNER_OFFSET_BIT) & 1
|
|
225
|
+
|
|
226
|
+
@wp.func
|
|
227
|
+
def _get_face_outer_offset(flags: wp.uint8):
|
|
228
|
+
return wp.int32(flags >> FACE_OUTER_OFFSET_BIT) & 1
|
|
229
|
+
|
|
230
|
+
@wp.func
|
|
231
|
+
def side_position(args: SideArg, s: Sample):
|
|
232
|
+
ijk = args.face_ijk[s.element_index]
|
|
233
|
+
axis = Nanogrid._get_face_axis(args.face_flags[s.element_index])
|
|
234
|
+
|
|
235
|
+
uvw = wp.vec3(ijk) + Nanogrid._side_to_cell_coords(axis, 0.0, s.element_coords)
|
|
236
|
+
|
|
237
|
+
cell_grid = args.cell_arg.cell_grid
|
|
238
|
+
return wp.volume_index_to_world(cell_grid, uvw)
|
|
239
|
+
|
|
240
|
+
@wp.func
|
|
241
|
+
def _face_tangent_vecs(args: SideArg, axis: int, flip: int):
|
|
242
|
+
u_axis = utils.unit_element(wp.vec3(), (axis + 1 + flip) % 3)
|
|
243
|
+
v_axis = utils.unit_element(wp.vec3(), (axis + 2 - flip) % 3)
|
|
244
|
+
|
|
245
|
+
cell_grid = args.cell_arg.cell_grid
|
|
246
|
+
|
|
247
|
+
return wp.volume_index_to_world_dir(cell_grid, u_axis), wp.volume_index_to_world_dir(cell_grid, v_axis)
|
|
248
|
+
|
|
249
|
+
@wp.func
|
|
250
|
+
def side_deformation_gradient(args: SideArg, s: Sample):
|
|
251
|
+
flags = args.face_flags[s.element_index]
|
|
252
|
+
axis = Nanogrid._get_face_axis(flags)
|
|
253
|
+
flip = Nanogrid._get_face_inner_offset(flags)
|
|
254
|
+
v1, v2 = Nanogrid._face_tangent_vecs(args, axis, flip)
|
|
255
|
+
return _mat32(v1, v2)
|
|
256
|
+
|
|
257
|
+
@wp.func
|
|
258
|
+
def side_inner_inverse_deformation_gradient(args: SideArg, s: Sample):
|
|
259
|
+
return Nanogrid.cell_inverse_deformation_gradient(args.cell_arg, s)
|
|
260
|
+
|
|
261
|
+
@wp.func
|
|
262
|
+
def side_outer_inverse_deformation_gradient(args: SideArg, s: Sample):
|
|
263
|
+
return Nanogrid.cell_inverse_deformation_gradient(args.cell_arg, s)
|
|
264
|
+
|
|
265
|
+
@wp.func
|
|
266
|
+
def side_measure(args: SideArg, s: Sample):
|
|
267
|
+
axis = Nanogrid._get_face_axis(args.face_flags[s.element_index])
|
|
268
|
+
return args.face_areas[axis]
|
|
269
|
+
|
|
270
|
+
@wp.func
|
|
271
|
+
def side_measure_ratio(args: SideArg, s: Sample):
|
|
272
|
+
axis = Nanogrid._get_face_axis(args.face_flags[s.element_index])
|
|
273
|
+
return args.face_areas[axis] / args.cell_arg.cell_volume
|
|
274
|
+
|
|
275
|
+
@wp.func
|
|
276
|
+
def side_normal(args: SideArg, s: Sample):
|
|
277
|
+
flags = args.face_flags[s.element_index]
|
|
278
|
+
axis = Nanogrid._get_face_axis(flags)
|
|
279
|
+
flip = Nanogrid._get_face_inner_offset(flags)
|
|
280
|
+
|
|
281
|
+
v1, v2 = Nanogrid._face_tangent_vecs(args, axis, flip)
|
|
282
|
+
return wp.cross(v1, v2) / args.face_areas[axis]
|
|
283
|
+
|
|
284
|
+
@wp.func
|
|
285
|
+
def side_inner_cell_index(args: SideArg, side_index: ElementIndex):
|
|
286
|
+
ijk = args.face_ijk[side_index]
|
|
287
|
+
flags = args.face_flags[side_index]
|
|
288
|
+
axis = Nanogrid._get_face_axis(flags)
|
|
289
|
+
offset = Nanogrid._get_face_inner_offset(flags)
|
|
290
|
+
|
|
291
|
+
ijk[axis] += offset - 1
|
|
292
|
+
cell_grid = args.cell_arg.cell_grid
|
|
293
|
+
|
|
294
|
+
return wp.volume_lookup_index(cell_grid, ijk[0], ijk[1], ijk[2])
|
|
295
|
+
|
|
296
|
+
@wp.func
|
|
297
|
+
def side_outer_cell_index(args: SideArg, side_index: ElementIndex):
|
|
298
|
+
ijk = args.face_ijk[side_index]
|
|
299
|
+
flags = args.face_flags[side_index]
|
|
300
|
+
axis = Nanogrid._get_face_axis(flags)
|
|
301
|
+
offset = Nanogrid._get_face_outer_offset(flags)
|
|
302
|
+
|
|
303
|
+
ijk[axis] -= offset
|
|
304
|
+
cell_grid = args.cell_arg.cell_grid
|
|
305
|
+
|
|
306
|
+
return wp.volume_lookup_index(cell_grid, ijk[0], ijk[1], ijk[2])
|
|
307
|
+
|
|
308
|
+
@wp.func
|
|
309
|
+
def side_inner_cell_coords(args: SideArg, side_index: ElementIndex, side_coords: Coords):
|
|
310
|
+
flags = args.face_flags[side_index]
|
|
311
|
+
axis = Nanogrid._get_face_axis(flags)
|
|
312
|
+
offset = float(Nanogrid._get_face_inner_offset(flags))
|
|
313
|
+
return Nanogrid._side_to_cell_coords(axis, 1.0 - offset, side_coords)
|
|
314
|
+
|
|
315
|
+
@wp.func
|
|
316
|
+
def side_outer_cell_coords(args: SideArg, side_index: ElementIndex, side_coords: Coords):
|
|
317
|
+
flags = args.face_flags[side_index]
|
|
318
|
+
axis = Nanogrid._get_face_axis(flags)
|
|
319
|
+
offset = float(Nanogrid._get_face_outer_offset(flags))
|
|
320
|
+
return Nanogrid._side_to_cell_coords(axis, offset, side_coords)
|
|
321
|
+
|
|
322
|
+
@wp.func
|
|
323
|
+
def side_from_cell_coords(
|
|
324
|
+
args: SideArg,
|
|
325
|
+
side_index: ElementIndex,
|
|
326
|
+
element_index: ElementIndex,
|
|
327
|
+
element_coords: Coords,
|
|
328
|
+
):
|
|
329
|
+
flags = args.face_flags[side_index]
|
|
330
|
+
axis = Nanogrid._get_face_axis(flags)
|
|
331
|
+
|
|
332
|
+
cell_ijk = args.cell_arg.cell_ijk[element_index]
|
|
333
|
+
side_ijk = args.face_ijk[side_index]
|
|
334
|
+
|
|
335
|
+
on_side = float(side_ijk[axis] - cell_ijk[axis]) == element_coords[axis]
|
|
336
|
+
|
|
337
|
+
return wp.select(
|
|
338
|
+
on_side, Coords(OUTSIDE), Coords(element_coords[(axis + 1) % 3], element_coords[(axis + 2) % 3], 0.0)
|
|
339
|
+
)
|
|
340
|
+
|
|
341
|
+
@wp.func
|
|
342
|
+
def side_to_cell_arg(side_arg: SideArg):
|
|
343
|
+
return side_arg.cell_arg
|
|
344
|
+
|
|
345
|
+
|
|
346
|
+
@wp.kernel
|
|
347
|
+
def _cell_node_indices(
|
|
348
|
+
cell_ijk: wp.array(dtype=wp.vec3i),
|
|
349
|
+
node_ijk: wp.array2d(dtype=wp.vec3i),
|
|
350
|
+
):
|
|
351
|
+
cell, n = wp.tid()
|
|
352
|
+
node_ijk[cell, n] = cell_ijk[cell] + wp.vec3i((n & 4) >> 2, (n & 2) >> 1, n & 1)
|
|
353
|
+
|
|
354
|
+
|
|
355
|
+
@wp.kernel
|
|
356
|
+
def _cell_face_indices(
|
|
357
|
+
cell_ijk: wp.array(dtype=wp.vec3i),
|
|
358
|
+
node_ijk: wp.array2d(dtype=wp.vec3i),
|
|
359
|
+
):
|
|
360
|
+
cell = wp.tid()
|
|
361
|
+
ijk = cell_ijk[cell]
|
|
362
|
+
node_ijk[cell, 0] = _add_axis_flag(ijk, 0)
|
|
363
|
+
node_ijk[cell, 1] = _add_axis_flag(ijk, 1)
|
|
364
|
+
node_ijk[cell, 2] = _add_axis_flag(ijk, 2)
|
|
365
|
+
|
|
366
|
+
node_ijk[cell, 3] = _add_axis_flag(ijk + wp.vec3i(1, 0, 0), 0)
|
|
367
|
+
node_ijk[cell, 4] = _add_axis_flag(ijk + wp.vec3i(0, 1, 0), 1)
|
|
368
|
+
node_ijk[cell, 5] = _add_axis_flag(ijk + wp.vec3i(0, 0, 1), 2)
|
|
369
|
+
|
|
370
|
+
|
|
371
|
+
@wp.kernel
|
|
372
|
+
def _cell_edge_indices(
|
|
373
|
+
cell_ijk: wp.array(dtype=wp.vec3i),
|
|
374
|
+
edge_ijk: wp.array2d(dtype=wp.vec3i),
|
|
375
|
+
):
|
|
376
|
+
cell = wp.tid()
|
|
377
|
+
ijk = cell_ijk[cell]
|
|
378
|
+
edge_ijk[cell, 0] = _add_axis_flag(ijk, 0)
|
|
379
|
+
edge_ijk[cell, 1] = _add_axis_flag(ijk, 1)
|
|
380
|
+
edge_ijk[cell, 2] = _add_axis_flag(ijk, 2)
|
|
381
|
+
|
|
382
|
+
edge_ijk[cell, 3] = _add_axis_flag(ijk + wp.vec3i(0, 1, 0), 0)
|
|
383
|
+
edge_ijk[cell, 4] = _add_axis_flag(ijk + wp.vec3i(0, 0, 1), 1)
|
|
384
|
+
edge_ijk[cell, 5] = _add_axis_flag(ijk + wp.vec3i(1, 0, 0), 2)
|
|
385
|
+
|
|
386
|
+
edge_ijk[cell, 6] = _add_axis_flag(ijk + wp.vec3i(0, 1, 1), 0)
|
|
387
|
+
edge_ijk[cell, 7] = _add_axis_flag(ijk + wp.vec3i(1, 0, 1), 1)
|
|
388
|
+
edge_ijk[cell, 8] = _add_axis_flag(ijk + wp.vec3i(1, 1, 0), 2)
|
|
389
|
+
|
|
390
|
+
edge_ijk[cell, 9] = _add_axis_flag(ijk + wp.vec3i(0, 0, 1), 0)
|
|
391
|
+
edge_ijk[cell, 10] = _add_axis_flag(ijk + wp.vec3i(1, 0, 0), 1)
|
|
392
|
+
edge_ijk[cell, 11] = _add_axis_flag(ijk + wp.vec3i(0, 1, 0), 2)
|
|
393
|
+
|
|
394
|
+
|
|
395
|
+
def _build_node_grid(cell_ijk, grid: wp.Volume, temporary_store: cache.TemporaryStore):
|
|
396
|
+
cell_count = cell_ijk.shape[0]
|
|
397
|
+
|
|
398
|
+
cell_nodes = cache.borrow_temporary(temporary_store, shape=(cell_count, 8), dtype=wp.vec3i, device=cell_ijk.device)
|
|
399
|
+
wp.launch(
|
|
400
|
+
_cell_node_indices, dim=cell_nodes.array.shape, inputs=[cell_ijk, cell_nodes.array], device=cell_ijk.device
|
|
401
|
+
)
|
|
402
|
+
node_grid = wp.Volume.allocate_by_voxels(
|
|
403
|
+
cell_nodes.array.flatten(), voxel_size=grid.get_voxel_size()[0], device=cell_ijk.device
|
|
404
|
+
)
|
|
405
|
+
|
|
406
|
+
return node_grid
|
|
407
|
+
|
|
408
|
+
|
|
409
|
+
def _build_face_grid(cell_ijk, grid: wp.Volume, temporary_store: cache.TemporaryStore):
|
|
410
|
+
cell_count = cell_ijk.shape[0]
|
|
411
|
+
|
|
412
|
+
cell_faces = cache.borrow_temporary(temporary_store, shape=(cell_count, 6), dtype=wp.vec3i, device=cell_ijk.device)
|
|
413
|
+
wp.launch(_cell_face_indices, dim=cell_count, inputs=[cell_ijk, cell_faces.array], device=cell_ijk.device)
|
|
414
|
+
face_grid = wp.Volume.allocate_by_voxels(
|
|
415
|
+
cell_faces.array.flatten(), voxel_size=grid.get_voxel_size()[0], device=cell_ijk.device
|
|
416
|
+
)
|
|
417
|
+
|
|
418
|
+
return face_grid
|
|
419
|
+
|
|
420
|
+
|
|
421
|
+
def _build_edge_grid(cell_ijk, grid: wp.Volume, temporary_store: cache.TemporaryStore):
|
|
422
|
+
cell_count = cell_ijk.shape[0]
|
|
423
|
+
|
|
424
|
+
cell_edges = cache.borrow_temporary(temporary_store, shape=(cell_count, 12), dtype=wp.vec3i, device=cell_ijk.device)
|
|
425
|
+
wp.launch(_cell_edge_indices, dim=cell_count, inputs=[cell_ijk, cell_edges.array], device=cell_ijk.device)
|
|
426
|
+
edge_grid = wp.Volume.allocate_by_voxels(
|
|
427
|
+
cell_edges.array.flatten(), voxel_size=grid.get_voxel_size()[0], device=cell_ijk.device
|
|
428
|
+
)
|
|
429
|
+
|
|
430
|
+
return edge_grid
|
|
431
|
+
|
|
432
|
+
|
|
433
|
+
@wp.kernel
|
|
434
|
+
def _build_face_flags(
|
|
435
|
+
cell_grid: wp.uint64,
|
|
436
|
+
face_ijk: wp.array(dtype=wp.vec3i),
|
|
437
|
+
face_flags: wp.array(dtype=wp.uint8),
|
|
438
|
+
boundary_face_mask: wp.array(dtype=int),
|
|
439
|
+
):
|
|
440
|
+
face = wp.tid()
|
|
441
|
+
|
|
442
|
+
axis, ijk = _extract_axis_flag(face_ijk[face])
|
|
443
|
+
|
|
444
|
+
ijk_minus = ijk
|
|
445
|
+
ijk_minus[axis] -= 1
|
|
446
|
+
|
|
447
|
+
plus_cell_index = wp.volume_lookup_index(cell_grid, ijk[0], ijk[1], ijk[2])
|
|
448
|
+
minus_cell_index = wp.volume_lookup_index(cell_grid, ijk_minus[0], ijk_minus[1], ijk_minus[2])
|
|
449
|
+
|
|
450
|
+
plus_boundary = wp.uint8(wp.select(plus_cell_index == -1, 0, 1)) << FACE_OUTER_OFFSET_BIT
|
|
451
|
+
minus_boundary = wp.uint8(wp.select(minus_cell_index == -1, 0, 1)) << FACE_INNER_OFFSET_BIT
|
|
452
|
+
|
|
453
|
+
face_ijk[face] = ijk
|
|
454
|
+
face_flags[face] = wp.uint8(axis) | plus_boundary | minus_boundary
|
|
455
|
+
boundary_face_mask[face] = wp.select((plus_boundary | minus_boundary) == 0, 1, 0)
|
warp/fem/integrate.py
CHANGED
|
@@ -9,6 +9,7 @@ from warp.fem.field import (
|
|
|
9
9
|
DiscreteField,
|
|
10
10
|
FieldLike,
|
|
11
11
|
FieldRestriction,
|
|
12
|
+
SpaceField,
|
|
12
13
|
TestField,
|
|
13
14
|
TrialField,
|
|
14
15
|
make_restriction,
|
|
@@ -195,7 +196,7 @@ def _get_integrand_field_arguments(
|
|
|
195
196
|
arg_type = argspec.annotations[arg]
|
|
196
197
|
if arg_type == Field:
|
|
197
198
|
if arg not in fields:
|
|
198
|
-
raise ValueError(f"Missing field for argument '{arg}'")
|
|
199
|
+
raise ValueError(f"Missing field for argument '{arg}' of integrand '{integrand.name}'")
|
|
199
200
|
field_args[arg] = fields[arg]
|
|
200
201
|
elif arg_type == Domain:
|
|
201
202
|
domain_name = arg
|
|
@@ -208,6 +209,52 @@ def _get_integrand_field_arguments(
|
|
|
208
209
|
return field_args, value_args, domain_name, sample_name
|
|
209
210
|
|
|
210
211
|
|
|
212
|
+
def _check_field_compat(
|
|
213
|
+
integrand: Integrand,
|
|
214
|
+
fields: Dict[str, FieldLike],
|
|
215
|
+
field_args: Dict[str, FieldLike],
|
|
216
|
+
domain: GeometryDomain = None,
|
|
217
|
+
):
|
|
218
|
+
# Check field compatilibity
|
|
219
|
+
for name, field in fields.items():
|
|
220
|
+
if name not in field_args:
|
|
221
|
+
raise ValueError(
|
|
222
|
+
f"Passed field argument '{name}' does not match any parameter of integrand '{integrand.name}'"
|
|
223
|
+
)
|
|
224
|
+
|
|
225
|
+
if isinstance(field, SpaceField) and domain is not None:
|
|
226
|
+
space = field.space
|
|
227
|
+
if space.geometry != domain.geometry:
|
|
228
|
+
raise ValueError(f"Field '{name}' must be defined on the same geometry as the integration domain")
|
|
229
|
+
if space.dimension != domain.dimension:
|
|
230
|
+
raise ValueError(
|
|
231
|
+
f"Field '{name}' dimension ({space.dimension}) does not match that of the integration domain ({domain.dimension}). Maybe a forgotten `.trace()`?"
|
|
232
|
+
)
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
def _populate_value_struct(ValueStruct: wp.codegen.Struct, values: Dict[str, Any], integrand_name: str):
|
|
236
|
+
value_struct_values = ValueStruct()
|
|
237
|
+
for k, v in values.items():
|
|
238
|
+
try:
|
|
239
|
+
setattr(value_struct_values, k, v)
|
|
240
|
+
except Exception as err:
|
|
241
|
+
if k not in ValueStruct.vars:
|
|
242
|
+
raise ValueError(
|
|
243
|
+
f"Passed value argument '{k}' does not match any of the integrand '{integrand_name}' parameters"
|
|
244
|
+
) from err
|
|
245
|
+
raise ValueError(
|
|
246
|
+
f"Passed value argument '{k}' of type '{wp.types.type_repr(v)}' is incompatible with the integrand '{integrand_name}' parameter of type '{wp.types.type_repr(ValueStruct.vars[k].type)}'"
|
|
247
|
+
) from err
|
|
248
|
+
|
|
249
|
+
missing_values = ValueStruct.vars.keys() - values.keys()
|
|
250
|
+
if missing_values:
|
|
251
|
+
wp.utils.warn(
|
|
252
|
+
f"Missing values for parameter(s) '{', '.join(missing_values)}' of the integrand '{integrand_name}', will be zero-initialized"
|
|
253
|
+
)
|
|
254
|
+
|
|
255
|
+
return value_struct_values
|
|
256
|
+
|
|
257
|
+
|
|
211
258
|
def _get_test_and_trial_fields(
|
|
212
259
|
fields: Dict[str, FieldLike],
|
|
213
260
|
):
|
|
@@ -217,14 +264,17 @@ def _get_test_and_trial_fields(
|
|
|
217
264
|
trial_name = None
|
|
218
265
|
|
|
219
266
|
for name, field in fields.items():
|
|
267
|
+
if not isinstance(field, FieldLike):
|
|
268
|
+
raise ValueError(f"Passed field argument '{name}' is not a proper Field")
|
|
269
|
+
|
|
220
270
|
if isinstance(field, TestField):
|
|
221
271
|
if test is not None:
|
|
222
|
-
raise ValueError("
|
|
272
|
+
raise ValueError(f"More than one test field argument: '{test_name}' and '{name}'")
|
|
223
273
|
test = field
|
|
224
274
|
test_name = name
|
|
225
275
|
elif isinstance(field, TrialField):
|
|
226
276
|
if trial is not None:
|
|
227
|
-
raise ValueError("
|
|
277
|
+
raise ValueError(f"More than one trial field argument: '{trial_name}' and '{name}'")
|
|
228
278
|
trial = field
|
|
229
279
|
trial_name = name
|
|
230
280
|
|
|
@@ -759,6 +809,8 @@ def _generate_integrate_kernel(
|
|
|
759
809
|
|
|
760
810
|
# Not found in cache, transform integrand and generate kernel
|
|
761
811
|
|
|
812
|
+
_check_field_compat(integrand, fields, field_args, domain)
|
|
813
|
+
|
|
762
814
|
integrand_func = _translate_integrand(
|
|
763
815
|
integrand,
|
|
764
816
|
field_args,
|
|
@@ -843,6 +895,7 @@ def _generate_integrate_kernel(
|
|
|
843
895
|
|
|
844
896
|
|
|
845
897
|
def _launch_integrate_kernel(
|
|
898
|
+
integrand: Integrand,
|
|
846
899
|
kernel: wp.Kernel,
|
|
847
900
|
FieldStruct: wp.codegen.Struct,
|
|
848
901
|
ValueStruct: wp.codegen.Struct,
|
|
@@ -870,9 +923,7 @@ def _launch_integrate_kernel(
|
|
|
870
923
|
for k, v in fields.items():
|
|
871
924
|
setattr(field_arg_values, k, v.eval_arg_value(device=device))
|
|
872
925
|
|
|
873
|
-
value_struct_values = ValueStruct
|
|
874
|
-
for k, v in values.items():
|
|
875
|
-
setattr(value_struct_values, k, v)
|
|
926
|
+
value_struct_values = _populate_value_struct(ValueStruct, values, integrand_name=integrand.name)
|
|
876
927
|
|
|
877
928
|
# Constant form
|
|
878
929
|
if test is None and trial is None:
|
|
@@ -1211,6 +1262,7 @@ def integrate(
|
|
|
1211
1262
|
)
|
|
1212
1263
|
|
|
1213
1264
|
return _launch_integrate_kernel(
|
|
1265
|
+
integrand=integrand,
|
|
1214
1266
|
kernel=kernel,
|
|
1215
1267
|
FieldStruct=FieldStruct,
|
|
1216
1268
|
ValueStruct=ValueStruct,
|
|
@@ -1428,6 +1480,8 @@ def _generate_interpolate_kernel(
|
|
|
1428
1480
|
if kernel is not None:
|
|
1429
1481
|
return kernel, FieldStruct, ValueStruct
|
|
1430
1482
|
|
|
1483
|
+
_check_field_compat(integrand, fields, field_args, domain)
|
|
1484
|
+
|
|
1431
1485
|
# Generate interpolation kernel
|
|
1432
1486
|
if isinstance(dest, FieldRestriction):
|
|
1433
1487
|
# need to split into kernel + function for diffferentiability
|
|
@@ -1499,6 +1553,7 @@ def _generate_interpolate_kernel(
|
|
|
1499
1553
|
|
|
1500
1554
|
|
|
1501
1555
|
def _launch_interpolate_kernel(
|
|
1556
|
+
integrand: Integrand,
|
|
1502
1557
|
kernel: wp.kernel,
|
|
1503
1558
|
FieldStruct: wp.codegen.Struct,
|
|
1504
1559
|
ValueStruct: wp.codegen.Struct,
|
|
@@ -1517,9 +1572,7 @@ def _launch_interpolate_kernel(
|
|
|
1517
1572
|
for k, v in fields.items():
|
|
1518
1573
|
setattr(field_arg_values, k, v.eval_arg_value(device=device))
|
|
1519
1574
|
|
|
1520
|
-
value_struct_values = ValueStruct
|
|
1521
|
-
for k, v in values.items():
|
|
1522
|
-
setattr(value_struct_values, k, v)
|
|
1575
|
+
value_struct_values = _populate_value_struct(ValueStruct, values, integrand_name=integrand.name)
|
|
1523
1576
|
|
|
1524
1577
|
if isinstance(dest, FieldRestriction):
|
|
1525
1578
|
dest_node_arg = dest.space_restriction.node_arg(device=device)
|
|
@@ -1618,6 +1671,7 @@ def interpolate(
|
|
|
1618
1671
|
)
|
|
1619
1672
|
|
|
1620
1673
|
return _launch_interpolate_kernel(
|
|
1674
|
+
integrand=integrand,
|
|
1621
1675
|
kernel=kernel,
|
|
1622
1676
|
FieldStruct=FieldStruct,
|
|
1623
1677
|
ValueStruct=ValueStruct,
|