1 //============================================================================
2 // Copyright (c) Kitware, Inc.
3 // All rights reserved.
4 // See LICENSE.txt for details.
5 //
6 // This software is distributed WITHOUT ANY WARRANTY; without even
7 // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
8 // PURPOSE. See the above copyright notice for more information.
9 //============================================================================
10 #ifndef vtk_m_cont_ArrayHandleGroupVecVariable_h
11 #define vtk_m_cont_ArrayHandleGroupVecVariable_h
12
13 #include <vtkm/cont/Algorithm.h>
14 #include <vtkm/cont/ArrayGetValues.h>
15 #include <vtkm/cont/ArrayHandle.h>
16 #include <vtkm/cont/ArrayHandleCast.h>
17 #include <vtkm/cont/ArrayPortal.h>
18 #include <vtkm/cont/ErrorBadValue.h>
19 #include <vtkm/cont/RuntimeDeviceTracker.h>
20 #include <vtkm/cont/TryExecute.h>
21
22 #include <vtkm/Assert.h>
23 #include <vtkm/VecFromPortal.h>
24
25 namespace vtkm
26 {
27 namespace internal
28 {
29
30 template <typename ComponentsPortalType, typename OffsetsPortalType>
31 class VTKM_ALWAYS_EXPORT ArrayPortalGroupVecVariable
32 {
33 public:
34 using ComponentType = typename std::remove_const<typename ComponentsPortalType::ValueType>::type;
35 using ValueType = vtkm::VecFromPortal<ComponentsPortalType>;
36
37 VTKM_SUPPRESS_EXEC_WARNINGS
38 VTKM_EXEC_CONT
ArrayPortalGroupVecVariable()39 ArrayPortalGroupVecVariable()
40 : ComponentsPortal()
41 , OffsetsPortal()
42 {
43 }
44
45 VTKM_SUPPRESS_EXEC_WARNINGS
46 VTKM_EXEC_CONT
ArrayPortalGroupVecVariable(const ComponentsPortalType & componentsPortal,const OffsetsPortalType & offsetsPortal)47 ArrayPortalGroupVecVariable(const ComponentsPortalType& componentsPortal,
48 const OffsetsPortalType& offsetsPortal)
49 : ComponentsPortal(componentsPortal)
50 , OffsetsPortal(offsetsPortal)
51 {
52 }
53
54 /// Copy constructor for any other ArrayPortalConcatenate with a portal type
55 /// that can be copied to this portal type. This allows us to do any type
56 /// casting that the portals do (like the non-const to const cast).
57 VTKM_SUPPRESS_EXEC_WARNINGS
58 template <typename OtherComponentsPortalType, typename OtherOffsetsPortalType>
ArrayPortalGroupVecVariable(const ArrayPortalGroupVecVariable<OtherComponentsPortalType,OtherOffsetsPortalType> & src)59 VTKM_EXEC_CONT ArrayPortalGroupVecVariable(
60 const ArrayPortalGroupVecVariable<OtherComponentsPortalType, OtherOffsetsPortalType>& src)
61 : ComponentsPortal(src.GetComponentsPortal())
62 , OffsetsPortal(src.GetOffsetsPortal())
63 {
64 }
65
66 VTKM_SUPPRESS_EXEC_WARNINGS
67 VTKM_EXEC_CONT
GetNumberOfValues()68 vtkm::Id GetNumberOfValues() const { return this->OffsetsPortal.GetNumberOfValues() - 1; }
69
70 VTKM_SUPPRESS_EXEC_WARNINGS
71 VTKM_EXEC_CONT
Get(vtkm::Id index)72 ValueType Get(vtkm::Id index) const
73 {
74 vtkm::Id offsetIndex = this->OffsetsPortal.Get(index);
75 vtkm::Id nextOffsetIndex = this->OffsetsPortal.Get(index + 1);
76
77 return ValueType(this->ComponentsPortal,
78 static_cast<vtkm::IdComponent>(nextOffsetIndex - offsetIndex),
79 offsetIndex);
80 }
81
82 VTKM_SUPPRESS_EXEC_WARNINGS
83 VTKM_EXEC_CONT
Set(vtkm::Id vtkmNotUsed (index),const ValueType & vtkmNotUsed (value))84 void Set(vtkm::Id vtkmNotUsed(index), const ValueType& vtkmNotUsed(value)) const
85 {
86 // The ValueType (VecFromPortal) operates on demand. Thus, if you set
87 // something in the value, it has already been passed to the array. Perhaps
88 // we should check to make sure that the value used matches the location
89 // you are trying to set in the array, but we don't do that.
90 }
91
92 VTKM_SUPPRESS_EXEC_WARNINGS
93 VTKM_EXEC_CONT
GetComponentsPortal()94 const ComponentsPortalType& GetComponentsPortal() const { return this->ComponentsPortal; }
95
96 VTKM_SUPPRESS_EXEC_WARNINGS
97 VTKM_EXEC_CONT
GetOffsetsPortal()98 const OffsetsPortalType& GetOffsetsPortal() const { return this->OffsetsPortal; }
99
100 private:
101 ComponentsPortalType ComponentsPortal;
102 OffsetsPortalType OffsetsPortal;
103 };
104
105 }
106 } // namespace vtkm::internal
107
108 namespace vtkm
109 {
110 namespace cont
111 {
112
113 template <typename ComponentsStorageTag, typename OffsetsStorageTag>
114 struct VTKM_ALWAYS_EXPORT StorageTagGroupVecVariable
115 {
116 };
117
118 namespace internal
119 {
120
121 template <typename ComponentsPortal, typename ComponentsStorageTag, typename OffsetsStorageTag>
122 class Storage<vtkm::VecFromPortal<ComponentsPortal>,
123 vtkm::cont::StorageTagGroupVecVariable<ComponentsStorageTag, OffsetsStorageTag>>
124 {
125 using ComponentType = typename ComponentsPortal::ValueType;
126 using ComponentsStorage = vtkm::cont::internal::Storage<ComponentType, ComponentsStorageTag>;
127 using OffsetsStorage = vtkm::cont::internal::Storage<vtkm::Id, OffsetsStorageTag>;
128
129 VTKM_STATIC_ASSERT_MSG(
130 (std::is_same<ComponentsPortal, typename ComponentsStorage::WritePortalType>::value),
131 "Used invalid ComponentsPortal type with expected ComponentsStorageTag.");
132
133 template <typename Buff>
ComponentsBuffers(Buff * buffers)134 VTKM_CONT static Buff* ComponentsBuffers(Buff* buffers)
135 {
136 return buffers;
137 }
138
139 template <typename Buff>
OffsetsBuffers(Buff * buffers)140 VTKM_CONT static Buff* OffsetsBuffers(Buff* buffers)
141 {
142 return buffers + ComponentsStorage::GetNumberOfBuffers();
143 }
144
145 public:
146 VTKM_STORAGE_NO_RESIZE;
147
148 using ReadPortalType =
149 vtkm::internal::ArrayPortalGroupVecVariable<typename ComponentsStorage::ReadPortalType,
150 typename OffsetsStorage::ReadPortalType>;
151 using WritePortalType =
152 vtkm::internal::ArrayPortalGroupVecVariable<typename ComponentsStorage::WritePortalType,
153 typename OffsetsStorage::ReadPortalType>;
154
GetNumberOfBuffers()155 VTKM_CONT static vtkm::IdComponent GetNumberOfBuffers()
156 {
157 return ComponentsStorage::GetNumberOfBuffers() + OffsetsStorage::GetNumberOfBuffers();
158 }
159
GetNumberOfValues(const vtkm::cont::internal::Buffer * buffers)160 VTKM_CONT static vtkm::Id GetNumberOfValues(const vtkm::cont::internal::Buffer* buffers)
161 {
162 return OffsetsStorage::GetNumberOfValues(OffsetsBuffers(buffers)) - 1;
163 }
164
CreateReadPortal(const vtkm::cont::internal::Buffer * buffers,vtkm::cont::DeviceAdapterId device,vtkm::cont::Token & token)165 VTKM_CONT static ReadPortalType CreateReadPortal(const vtkm::cont::internal::Buffer* buffers,
166 vtkm::cont::DeviceAdapterId device,
167 vtkm::cont::Token& token)
168 {
169 return ReadPortalType(
170 ComponentsStorage::CreateReadPortal(ComponentsBuffers(buffers), device, token),
171 OffsetsStorage::CreateReadPortal(OffsetsBuffers(buffers), device, token));
172 }
173
CreateWritePortal(vtkm::cont::internal::Buffer * buffers,vtkm::cont::DeviceAdapterId device,vtkm::cont::Token & token)174 VTKM_CONT static WritePortalType CreateWritePortal(vtkm::cont::internal::Buffer* buffers,
175 vtkm::cont::DeviceAdapterId device,
176 vtkm::cont::Token& token)
177 {
178 return WritePortalType(
179 ComponentsStorage::CreateWritePortal(ComponentsBuffers(buffers), device, token),
180 OffsetsStorage::CreateReadPortal(OffsetsBuffers(buffers), device, token));
181 }
182
CreateBuffers(const vtkm::cont::ArrayHandle<ComponentType,ComponentsStorageTag> & componentsArray,const vtkm::cont::ArrayHandle<vtkm::Id,OffsetsStorageTag> & offsetsArray)183 VTKM_CONT static std::vector<vtkm::cont::internal::Buffer> CreateBuffers(
184 const vtkm::cont::ArrayHandle<ComponentType, ComponentsStorageTag>& componentsArray,
185 const vtkm::cont::ArrayHandle<vtkm::Id, OffsetsStorageTag>& offsetsArray)
186 {
187 std::vector<vtkm::cont::internal::Buffer> destBuffer(
188 static_cast<std::size_t>(GetNumberOfBuffers()));
189 auto destIter = destBuffer.begin();
190
191 destIter =
192 std::copy_n(componentsArray.GetBuffers(), ComponentsStorage::GetNumberOfBuffers(), destIter);
193 destIter =
194 std::copy_n(offsetsArray.GetBuffers(), OffsetsStorage::GetNumberOfBuffers(), destIter);
195
196 return destBuffer;
197 }
198
GetComponentsArray(const vtkm::cont::internal::Buffer * buffers)199 VTKM_CONT static vtkm::cont::ArrayHandle<ComponentType, ComponentsStorageTag> GetComponentsArray(
200 const vtkm::cont::internal::Buffer* buffers)
201 {
202 return vtkm::cont::ArrayHandle<ComponentType, ComponentsStorageTag>(ComponentsBuffers(buffers));
203 }
204
GetOffsetsArray(const vtkm::cont::internal::Buffer * buffers)205 VTKM_CONT static vtkm::cont::ArrayHandle<vtkm::Id, OffsetsStorageTag> GetOffsetsArray(
206 const vtkm::cont::internal::Buffer* buffers)
207 {
208 return vtkm::cont::ArrayHandle<vtkm::Id, OffsetsStorageTag>(OffsetsBuffers(buffers));
209 }
210 };
211
212 } // namespace internal
213
214 /// \brief Fancy array handle that groups values into vectors of different sizes.
215 ///
216 /// It is sometimes the case that you need to run a worklet with an input or
217 /// output that has a different number of values per instance. For example, the
218 /// cells of a CellCetExplicit can have different numbers of points in each
219 /// cell. If inputting or outputting cells of this type, each instance of the
220 /// worklet might need a \c Vec of a different length. This fance array handle
221 /// takes an array of values and an array of offsets and groups the consecutive
222 /// values in Vec-like objects. The values are treated as tightly packed, so
223 /// that each Vec contains the values from one offset to the next. The last
224 /// value contains values from the last offset to the end of the array.
225 ///
226 /// For example, if you have an array handle with the 9 values
227 /// 0,1,2,3,4,5,6,7,8 an offsets array handle with the 4 values 0,4,6,9 and give
228 /// them to an \c ArrayHandleGroupVecVariable, you get an array that looks like
229 /// it contains three values of Vec-like objects with the data [0,1,2,3],
230 /// [4,5], and [6,7,8].
231 ///
232 /// Note that this version of \c ArrayHandle breaks some of the assumptions
233 /// about \c ArrayHandle a little bit. Typically, there is exactly one type for
234 /// every value in the array, and this value is also the same between the
235 /// control and execution environment. However, this class uses \c
236 /// VecFromPortal it implement a Vec-like class that has a variable number of
237 /// values, and this type can change between control and execution
238 /// environments.
239 ///
240 /// The offsets array is often derived from a list of sizes for each of the
241 /// entries. You can use the convenience function \c
242 /// ConvertNumComponentsToOffsets to take an array of sizes (i.e. the number of
243 /// components for each entry) and get an array of offsets needed for \c
244 /// ArrayHandleGroupVecVariable.
245 ///
246 template <typename ComponentsArrayHandleType, typename OffsetsArrayHandleType>
247 class ArrayHandleGroupVecVariable
248 : public vtkm::cont::ArrayHandle<
249 vtkm::VecFromPortal<typename ComponentsArrayHandleType::WritePortalType>,
250 vtkm::cont::StorageTagGroupVecVariable<typename ComponentsArrayHandleType::StorageTag,
251 typename OffsetsArrayHandleType::StorageTag>>
252 {
253 VTKM_IS_ARRAY_HANDLE(ComponentsArrayHandleType);
254 VTKM_IS_ARRAY_HANDLE(OffsetsArrayHandleType);
255
256 VTKM_STATIC_ASSERT_MSG(
257 (std::is_same<vtkm::Id, typename OffsetsArrayHandleType::ValueType>::value),
258 "ArrayHandleGroupVecVariable's offsets array must contain vtkm::Id values.");
259
260 public:
261 VTKM_ARRAY_HANDLE_SUBCLASS(
262 ArrayHandleGroupVecVariable,
263 (ArrayHandleGroupVecVariable<ComponentsArrayHandleType, OffsetsArrayHandleType>),
264 (vtkm::cont::ArrayHandle<
265 vtkm::VecFromPortal<typename ComponentsArrayHandleType::WritePortalType>,
266 vtkm::cont::StorageTagGroupVecVariable<typename ComponentsArrayHandleType::StorageTag,
267 typename OffsetsArrayHandleType::StorageTag>>));
268
269 using ComponentType = typename ComponentsArrayHandleType::ValueType;
270
271 private:
272 using StorageType = vtkm::cont::internal::Storage<ValueType, StorageTag>;
273
274 public:
275 VTKM_CONT
ArrayHandleGroupVecVariable(const ComponentsArrayHandleType & componentsArray,const OffsetsArrayHandleType & offsetsArray)276 ArrayHandleGroupVecVariable(const ComponentsArrayHandleType& componentsArray,
277 const OffsetsArrayHandleType& offsetsArray)
278 : Superclass(StorageType::CreateBuffers(componentsArray, offsetsArray))
279 {
280 }
281
GetComponentsArray()282 VTKM_CONT ComponentsArrayHandleType GetComponentsArray() const
283 {
284 return StorageType::GetComponentsArray(this->GetBuffers());
285 }
286
GetOffsetsArray()287 VTKM_CONT OffsetsArrayHandleType GetOffsetsArray() const
288 {
289 return StorageType::GetOffsetsArray(this->GetBuffers());
290 }
291 };
292
293 /// \c make_ArrayHandleGroupVecVariable is convenience function to generate an
294 /// ArrayHandleGroupVecVariable. It takes in an ArrayHandle of values and an
295 /// array handle of offsets and returns an array handle with consecutive
296 /// entries grouped in a Vec.
297 ///
298 template <typename ComponentsArrayHandleType, typename OffsetsArrayHandleType>
299 VTKM_CONT vtkm::cont::ArrayHandleGroupVecVariable<ComponentsArrayHandleType, OffsetsArrayHandleType>
make_ArrayHandleGroupVecVariable(const ComponentsArrayHandleType & componentsArray,const OffsetsArrayHandleType & offsetsArray)300 make_ArrayHandleGroupVecVariable(const ComponentsArrayHandleType& componentsArray,
301 const OffsetsArrayHandleType& offsetsArray)
302 {
303 return vtkm::cont::ArrayHandleGroupVecVariable<ComponentsArrayHandleType, OffsetsArrayHandleType>(
304 componentsArray, offsetsArray);
305 }
306
307 /// \c ConvertNumComponentsToOffsets takes an array of Vec sizes (i.e. the number of components in
308 /// each Vec) and returns an array of offsets to a packed array of such Vecs. The resulting array
309 /// can be used with \c ArrayHandleGroupVecVariable.
310 ///
311 /// \param numComponentsArray the input array that specifies the number of components in each group
312 /// Vec.
313 ///
314 /// \param offsetsArray (optional) the output \c ArrayHandle, which must have a value type of \c
315 /// vtkm::Id. If the output \c ArrayHandle is not given, it is returned.
316 ///
317 /// \param componentsArraySize (optional) a reference to a \c vtkm::Id and is filled with the expected
318 /// size of the component values array.
319 ///
320 /// \param device (optional) specifies the device on which to run the conversion.
321 ///
322 template <typename NumComponentsArrayType, typename OffsetsStorage>
323 VTKM_CONT void ConvertNumComponentsToOffsets(
324 const NumComponentsArrayType& numComponentsArray,
325 vtkm::cont::ArrayHandle<vtkm::Id, OffsetsStorage>& offsetsArray,
326 vtkm::Id& componentsArraySize,
327 vtkm::cont::DeviceAdapterId device = vtkm::cont::DeviceAdapterTagAny())
328 {
329 using namespace vtkm::cont;
330 VTKM_IS_ARRAY_HANDLE(NumComponentsArrayType);
331
332 VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
333
334 Algorithm::ScanExtended(device, make_ArrayHandleCast<vtkm::Id>(numComponentsArray), offsetsArray);
335
336 componentsArraySize = ArrayGetValue(offsetsArray.GetNumberOfValues() - 1, offsetsArray);
337 }
338
339 template <typename NumComponentsArrayType, typename OffsetsStorage>
340 VTKM_CONT void ConvertNumComponentsToOffsets(
341 const NumComponentsArrayType& numComponentsArray,
342 vtkm::cont::ArrayHandle<vtkm::Id, OffsetsStorage>& offsetsArray,
343 vtkm::cont::DeviceAdapterId device = vtkm::cont::DeviceAdapterTagAny())
344 {
345 VTKM_IS_ARRAY_HANDLE(NumComponentsArrayType);
346
347 VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
348
349 vtkm::cont::Algorithm::ScanExtended(
350 device, vtkm::cont::make_ArrayHandleCast<vtkm::Id>(numComponentsArray), offsetsArray);
351 }
352
353 template <typename NumComponentsArrayType>
354 VTKM_CONT vtkm::cont::ArrayHandle<vtkm::Id> ConvertNumComponentsToOffsets(
355 const NumComponentsArrayType& numComponentsArray,
356 vtkm::Id& componentsArraySize,
357 vtkm::cont::DeviceAdapterId device = vtkm::cont::DeviceAdapterTagAny())
358 {
359 VTKM_IS_ARRAY_HANDLE(NumComponentsArrayType);
360
361 vtkm::cont::ArrayHandle<vtkm::Id> offsetsArray;
362 vtkm::cont::ConvertNumComponentsToOffsets(
363 numComponentsArray, offsetsArray, componentsArraySize, device);
364 return offsetsArray;
365 }
366
367 template <typename NumComponentsArrayType>
368 VTKM_CONT vtkm::cont::ArrayHandle<vtkm::Id> ConvertNumComponentsToOffsets(
369 const NumComponentsArrayType& numComponentsArray,
370 vtkm::cont::DeviceAdapterId device = vtkm::cont::DeviceAdapterTagAny())
371 {
372 VTKM_IS_ARRAY_HANDLE(NumComponentsArrayType);
373
374 vtkm::Id dummy;
375 return vtkm::cont::ConvertNumComponentsToOffsets(numComponentsArray, dummy, device);
376 }
377 }
378 } // namespace vtkm::cont
379
380 //=============================================================================
381 // Specializations of worklet arguments using ArrayHandleGropuVecVariable
382 #include <vtkm/exec/arg/FetchTagArrayDirectOutArrayHandleGroupVecVariable.h>
383
384 //=============================================================================
385 // Specializations of serialization related classes
386 /// @cond SERIALIZATION
387 namespace vtkm
388 {
389 namespace cont
390 {
391
392 template <typename SAH, typename OAH>
393 struct SerializableTypeString<vtkm::cont::ArrayHandleGroupVecVariable<SAH, OAH>>
394 {
395 static VTKM_CONT const std::string& Get()
396 {
397 static std::string name = "AH_GroupVecVariable<" + SerializableTypeString<SAH>::Get() + "," +
398 SerializableTypeString<OAH>::Get() + ">";
399 return name;
400 }
401 };
402
403 template <typename SP, typename SST, typename OST>
404 struct SerializableTypeString<
405 vtkm::cont::ArrayHandle<vtkm::VecFromPortal<SP>,
406 vtkm::cont::StorageTagGroupVecVariable<SST, OST>>>
407 : SerializableTypeString<
408 vtkm::cont::ArrayHandleGroupVecVariable<vtkm::cont::ArrayHandle<typename SP::ValueType, SST>,
409 vtkm::cont::ArrayHandle<vtkm::Id, OST>>>
410 {
411 };
412 }
413 } // vtkm::cont
414
415 namespace mangled_diy_namespace
416 {
417
418 template <typename SAH, typename OAH>
419 struct Serialization<vtkm::cont::ArrayHandleGroupVecVariable<SAH, OAH>>
420 {
421 private:
422 using Type = vtkm::cont::ArrayHandleGroupVecVariable<SAH, OAH>;
423 using BaseType = vtkm::cont::ArrayHandle<typename Type::ValueType, typename Type::StorageTag>;
424
425 public:
426 static VTKM_CONT void save(BinaryBuffer& bb, const BaseType& obj)
427 {
428 vtkmdiy::save(bb, Type(obj).GetComponentsArray());
429 vtkmdiy::save(bb, Type(obj).GetOffsetsArray());
430 }
431
432 static VTKM_CONT void load(BinaryBuffer& bb, BaseType& obj)
433 {
434 SAH src;
435 OAH off;
436
437 vtkmdiy::load(bb, src);
438 vtkmdiy::load(bb, off);
439
440 obj = vtkm::cont::make_ArrayHandleGroupVecVariable(src, off);
441 }
442 };
443
444 template <typename SP, typename SST, typename OST>
445 struct Serialization<vtkm::cont::ArrayHandle<vtkm::VecFromPortal<SP>,
446 vtkm::cont::StorageTagGroupVecVariable<SST, OST>>>
447 : Serialization<
448 vtkm::cont::ArrayHandleGroupVecVariable<vtkm::cont::ArrayHandle<typename SP::ValueType, SST>,
449 vtkm::cont::ArrayHandle<vtkm::Id, OST>>>
450 {
451 };
452 } // diy
453 /// @endcond SERIALIZATION
454
455 #endif //vtk_m_cont_ArrayHandleGroupVecVariable_h
456