@@ -42,6 +42,152 @@ def test_indexedarray_1d(test, device):
4242 wp .launch (kernel_1d , dim = iarr .size , inputs = [iarr , expected_arr ], device = device )
4343
4444
45+ @wp .struct
46+ class IndexedArrayStruct :
47+ iarr : wp .indexedarray (dtype = float )
48+
49+
50+ @wp .struct
51+ class NestedIndexedArrayStruct :
52+ inner : IndexedArrayStruct
53+
54+
55+ @wp .kernel
56+ def kernel_indexedarray_in_struct (arg : IndexedArrayStruct , expected : wp .array (dtype = float )):
57+ i = wp .tid ()
58+
59+ wp .expect_eq (arg .iarr [i ], expected [i ])
60+
61+ arg .iarr [i ] = 2.0 * arg .iarr [i ]
62+ wp .atomic_add (arg .iarr , i , 1.0 )
63+
64+ wp .expect_eq (arg .iarr [i ], 2.0 * expected [i ] + 1.0 )
65+
66+
67+ @wp .kernel
68+ def kernel_indexedarray_in_nested_struct (arg : NestedIndexedArrayStruct , expected : wp .array (dtype = float )):
69+ i = wp .tid ()
70+
71+ wp .expect_eq (arg .inner .iarr [i ], expected [i ])
72+
73+ arg .inner .iarr [i ] = 2.0 * arg .inner .iarr [i ]
74+ wp .atomic_add (arg .inner .iarr , i , 1.0 )
75+
76+ wp .expect_eq (arg .inner .iarr [i ], 2.0 * expected [i ] + 1.0 )
77+
78+
79+ @wp .kernel
80+ def kernel_indexedarray_in_struct_array (args : wp .array (dtype = IndexedArrayStruct ), expected : wp .array (dtype = float )):
81+ i = wp .tid ()
82+
83+ s = args [0 ]
84+ wp .expect_eq (s .iarr [i ], expected [i ])
85+
86+ s .iarr [i ] = 2.0 * s .iarr [i ]
87+ wp .atomic_add (s .iarr , i , 1.0 )
88+
89+ wp .expect_eq (s .iarr [i ], 2.0 * expected [i ] + 1.0 )
90+
91+
92+ def test_indexedarray_in_struct (test , device ):
93+ values = np .arange (10 , dtype = np .float32 )
94+ arr = wp .array (data = values , device = device )
95+
96+ indices = wp .array ([1 , 3 , 5 , 7 , 9 ], dtype = int , device = device )
97+ iarr = wp .indexedarray1d (arr , [indices ])
98+
99+ expected_arr = wp .array (data = [1 , 3 , 5 , 7 , 9 ], dtype = float , device = device )
100+
101+ s = IndexedArrayStruct ()
102+ s .iarr = iarr
103+
104+ wp .launch (kernel_indexedarray_in_struct , dim = iarr .size , inputs = [s , expected_arr ], device = device )
105+ wp .synchronize_device (device )
106+
107+
108+ def test_indexedarray_in_nested_struct (test , device ):
109+ values = np .arange (10 , dtype = np .float32 )
110+ arr = wp .array (data = values , device = device )
111+
112+ indices = wp .array ([1 , 3 , 5 , 7 , 9 ], dtype = int , device = device )
113+ iarr = wp .indexedarray1d (arr , [indices ])
114+
115+ expected_arr = wp .array (data = [1 , 3 , 5 , 7 , 9 ], dtype = float , device = device )
116+
117+ inner = IndexedArrayStruct ()
118+ inner .iarr = iarr
119+
120+ outer = NestedIndexedArrayStruct ()
121+ outer .inner = inner
122+
123+ wp .launch (kernel_indexedarray_in_nested_struct , dim = iarr .size , inputs = [outer , expected_arr ], device = device )
124+ wp .synchronize_device (device )
125+
126+
127+ def test_indexedarray_in_struct_array (test , device ):
128+ values = np .arange (10 , dtype = np .float32 )
129+ arr = wp .array (data = values , device = device )
130+
131+ indices = wp .array ([1 , 3 , 5 , 7 , 9 ], dtype = int , device = device )
132+ iarr = wp .indexedarray1d (arr , [indices ])
133+
134+ expected_arr = wp .array (data = [1 , 3 , 5 , 7 , 9 ], dtype = float , device = device )
135+
136+ s = IndexedArrayStruct ()
137+ s .iarr = iarr
138+ struct_arr = wp .array ([s ], dtype = IndexedArrayStruct , device = device )
139+
140+ wp .launch (kernel_indexedarray_in_struct_array , dim = iarr .size , inputs = [struct_arr , expected_arr ], device = device )
141+ wp .synchronize_device (device )
142+
143+
144+ def test_indexedarray_in_struct_numpy (test , device ):
145+ values = np .arange (4 , dtype = np .float32 )
146+ arr = wp .array (data = values , device = device )
147+
148+ indices = wp .array ([0 , 2 ], dtype = int , device = device )
149+ iarr = wp .indexedarray1d (arr , [indices ])
150+
151+ s = IndexedArrayStruct ()
152+ s .iarr = iarr
153+
154+ # Just ensure these are functional for structs embedding indexedarray_t
155+ dtype = IndexedArrayStruct .numpy_dtype ()
156+ value = s .numpy_value ()
157+
158+ test .assertIsInstance (dtype , dict )
159+ test .assertEqual (dtype ["names" ], ["iarr" ])
160+ test .assertEqual (len (value ), 1 )
161+
162+
163+ def test_indexedarray_in_struct_to_device_transfer (test , device ):
164+ # This test only applies to CUDA target devices.
165+ if not wp .is_cuda_available () or not wp .get_device (device ).is_cuda :
166+ test .skipTest ("Requires CUDA" )
167+
168+ # Create the indexedarray on CPU, then move the struct to CUDA.
169+ values = np .arange (10 , dtype = np .float32 )
170+ arr_cpu = wp .array (data = values , device = "cpu" )
171+ indices_cpu = wp .array ([1 , 3 , 5 , 7 , 9 ], dtype = int , device = "cpu" )
172+ iarr_cpu = wp .indexedarray1d (arr_cpu , [indices_cpu ])
173+
174+ s = IndexedArrayStruct ()
175+ s .iarr = iarr_cpu
176+
177+ s_cuda = s .to (device )
178+ test .assertIsInstance (s_cuda .iarr , wp .indexedarray )
179+ test .assertTrue (all (x is None for x in s_cuda .iarr .indices ))
180+ test .assertEqual (s_cuda .iarr .shape , iarr_cpu .shape )
181+
182+ expected_values = np .array ([1 , 3 , 5 , 7 , 9 ], dtype = np .float32 )
183+ expected_arr = wp .array (data = expected_values , dtype = float , device = device )
184+
185+ wp .launch (kernel_indexedarray_in_struct , dim = s_cuda .iarr .size , inputs = [s_cuda , expected_arr ], device = device )
186+ # After the kernel: a[i] = 2*a[i] then atomic_add(a, i, 1) => 2*expected + 1
187+ result = s_cuda .iarr .numpy ()
188+ assert_np_equal (result , 2.0 * expected_values + 1.0 )
189+
190+
45191@wp .kernel
46192def kernel_2d (a : wp .indexedarray2d (dtype = float ), expected : wp .array2d (dtype = float )):
47193 i , j = wp .tid ()
@@ -1121,6 +1267,22 @@ class TestIndexedArray(unittest.TestCase):
11211267add_function_test (TestIndexedArray , "test_indexedarray_fill_vector" , test_indexedarray_fill_vector , devices = devices )
11221268add_function_test (TestIndexedArray , "test_indexedarray_fill_matrix" , test_indexedarray_fill_matrix , devices = devices )
11231269add_function_test (TestIndexedArray , "test_indexedarray_fill_struct" , test_indexedarray_fill_struct , devices = devices )
1270+ add_function_test (TestIndexedArray , "test_indexedarray_in_struct" , test_indexedarray_in_struct , devices = devices )
1271+ add_function_test (
1272+ TestIndexedArray , "test_indexedarray_in_nested_struct" , test_indexedarray_in_nested_struct , devices = devices
1273+ )
1274+ add_function_test (
1275+ TestIndexedArray , "test_indexedarray_in_struct_array" , test_indexedarray_in_struct_array , devices = devices
1276+ )
1277+ add_function_test (
1278+ TestIndexedArray , "test_indexedarray_in_struct_numpy" , test_indexedarray_in_struct_numpy , devices = devices
1279+ )
1280+ add_function_test (
1281+ TestIndexedArray ,
1282+ "test_indexedarray_in_struct_to_device_transfer" ,
1283+ test_indexedarray_in_struct_to_device_transfer ,
1284+ devices = devices ,
1285+ )
11241286
11251287
11261288if __name__ == "__main__" :
0 commit comments