1 //============================================================================
2 //  Copyright (c) Kitware, Inc.
3 //  All rights reserved.
4 //  See LICENSE.txt for details.
5 //  This software is distributed WITHOUT ANY WARRANTY; without even
6 //  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
7 //  PURPOSE.  See the above copyright notice for more information.
8 //
9 //  Copyright 2014 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
10 //  Copyright 2014 UT-Battelle, LLC.
11 //  Copyright 2014 Los Alamos National Security.
12 //
13 //  Under the terms of Contract DE-NA0003525 with NTESS,
14 //  the U.S. Government retains certain rights in this software.
15 //
16 //  Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
17 //  Laboratory (LANL), the U.S. Government retains certain rights in
18 //  this software.
19 //============================================================================
20 #ifndef vtk_m_cont_Field_h
21 #define vtk_m_cont_Field_h
22 
23 #include <vtkm/cont/vtkm_cont_export.h>
24 
25 #include <vtkm/Range.h>
26 #include <vtkm/Types.h>
27 
28 #include <vtkm/cont/ArrayHandle.h>
29 #include <vtkm/cont/ArrayPortalToIterators.h>
30 #include <vtkm/cont/ArrayRangeCompute.h>
31 #include <vtkm/cont/DynamicArrayHandle.h>
32 
33 namespace vtkm
34 {
35 namespace cont
36 {
37 
38 namespace internal
39 {
40 
41 class ComputeRange
42 {
43 public:
ComputeRange(ArrayHandle<vtkm::Range> & range)44   ComputeRange(ArrayHandle<vtkm::Range>& range)
45     : Range(&range)
46   {
47   }
48 
49   template <typename ArrayHandleType>
operator()50   void operator()(const ArrayHandleType& input) const
51   {
52     *this->Range = vtkm::cont::ArrayRangeCompute(input);
53   }
54 
55 private:
56   vtkm::cont::ArrayHandle<vtkm::Range>* Range;
57 };
58 
59 } // namespace internal
60 
61 /// A \c Field encapsulates an array on some piece of the mesh, such as
62 /// the points, a cell set, a point logical dimension, or the whole mesh.
63 ///
64 class VTKM_CONT_EXPORT Field
65 {
66 public:
67   enum struct Association
68   {
69     ANY,
70     WHOLE_MESH,
71     POINTS,
72     CELL_SET,
73     LOGICAL_DIM
74   };
75 
76   /// constructors for points / whole mesh
77   VTKM_CONT
Field(std::string name,Association association,const vtkm::cont::DynamicArrayHandle & data)78   Field(std::string name, Association association, const vtkm::cont::DynamicArrayHandle& data)
79     : Name(name)
80     , FieldAssociation(association)
81     , AssocCellSetName()
82     , AssocLogicalDim(-1)
83     , Data(data)
84     , Range()
85     , ModifiedFlag(true)
86   {
87     VTKM_ASSERT(this->FieldAssociation == Association::WHOLE_MESH ||
88                 this->FieldAssociation == Association::POINTS);
89   }
90 
91   template <typename T, typename Storage>
Field(std::string name,Association association,const ArrayHandle<T,Storage> & data)92   VTKM_CONT Field(std::string name, Association association, const ArrayHandle<T, Storage>& data)
93     : Name(name)
94     , FieldAssociation(association)
95     , AssocCellSetName()
96     , AssocLogicalDim(-1)
97     , Data(data)
98     , Range()
99     , ModifiedFlag(true)
100   {
101     VTKM_ASSERT((this->FieldAssociation == Association::WHOLE_MESH) ||
102                 (this->FieldAssociation == Association::POINTS));
103   }
104 
105   /// constructors for cell set associations
106   VTKM_CONT
Field(std::string name,Association association,const std::string & cellSetName,const vtkm::cont::DynamicArrayHandle & data)107   Field(std::string name,
108         Association association,
109         const std::string& cellSetName,
110         const vtkm::cont::DynamicArrayHandle& data)
111     : Name(name)
112     , FieldAssociation(association)
113     , AssocCellSetName(cellSetName)
114     , AssocLogicalDim(-1)
115     , Data(data)
116     , Range()
117     , ModifiedFlag(true)
118   {
119     VTKM_ASSERT(this->FieldAssociation == Association::CELL_SET);
120   }
121 
122   template <typename T, typename Storage>
Field(std::string name,Association association,const std::string & cellSetName,const vtkm::cont::ArrayHandle<T,Storage> & data)123   VTKM_CONT Field(std::string name,
124                   Association association,
125                   const std::string& cellSetName,
126                   const vtkm::cont::ArrayHandle<T, Storage>& data)
127     : Name(name)
128     , FieldAssociation(association)
129     , AssocCellSetName(cellSetName)
130     , AssocLogicalDim(-1)
131     , Data(data)
132     , Range()
133     , ModifiedFlag(true)
134   {
135     VTKM_ASSERT(this->FieldAssociation == Association::CELL_SET);
136   }
137 
138   /// constructors for logical dimension associations
139   VTKM_CONT
Field(std::string name,Association association,vtkm::IdComponent logicalDim,const vtkm::cont::DynamicArrayHandle & data)140   Field(std::string name,
141         Association association,
142         vtkm::IdComponent logicalDim,
143         const vtkm::cont::DynamicArrayHandle& data)
144     : Name(name)
145     , FieldAssociation(association)
146     , AssocCellSetName()
147     , AssocLogicalDim(logicalDim)
148     , Data(data)
149     , Range()
150     , ModifiedFlag(true)
151   {
152     VTKM_ASSERT(this->FieldAssociation == Association::LOGICAL_DIM);
153   }
154 
155   template <typename T, typename Storage>
Field(std::string name,Association association,vtkm::IdComponent logicalDim,const vtkm::cont::ArrayHandle<T,Storage> & data)156   VTKM_CONT Field(std::string name,
157                   Association association,
158                   vtkm::IdComponent logicalDim,
159                   const vtkm::cont::ArrayHandle<T, Storage>& data)
160     : Name(name)
161     , FieldAssociation(association)
162     , AssocLogicalDim(logicalDim)
163     , Data(data)
164     , Range()
165     , ModifiedFlag(true)
166   {
167     VTKM_ASSERT(this->FieldAssociation == Association::LOGICAL_DIM);
168   }
169 
170   VTKM_CONT
Field()171   Field()
172     : Name()
173     , FieldAssociation(Association::ANY)
174     , AssocCellSetName()
175     , AssocLogicalDim()
176     , Data()
177     , Range()
178     , ModifiedFlag(true)
179   {
180     //Generate an empty field
181   }
182 
183   VTKM_CONT
184   virtual ~Field();
185 
186   VTKM_CONT
187   Field& operator=(const vtkm::cont::Field& src) = default;
188 
189   VTKM_CONT
GetName()190   const std::string& GetName() const { return this->Name; }
191 
192   VTKM_CONT
GetAssociation()193   Association GetAssociation() const { return this->FieldAssociation; }
194 
195   VTKM_CONT
GetAssocCellSet()196   std::string GetAssocCellSet() const { return this->AssocCellSetName; }
197 
198   VTKM_CONT
GetAssocLogicalDim()199   vtkm::IdComponent GetAssocLogicalDim() const { return this->AssocLogicalDim; }
200 
201   template <typename TypeList, typename StorageList>
GetRange(TypeList,StorageList)202   VTKM_CONT const vtkm::cont::ArrayHandle<vtkm::Range>& GetRange(TypeList, StorageList) const
203   {
204     VTKM_IS_LIST_TAG(TypeList);
205     VTKM_IS_LIST_TAG(StorageList);
206 
207     return this->GetRangeImpl(TypeList(), StorageList());
208   }
209 
210   VTKM_CONT
211   const vtkm::cont::ArrayHandle<vtkm::Range>& GetRange(VTKM_DEFAULT_TYPE_LIST_TAG,
212                                                        VTKM_DEFAULT_STORAGE_LIST_TAG) const;
213 
214   template <typename TypeList, typename StorageList>
GetRange(vtkm::Range * range,TypeList,StorageList)215   VTKM_CONT void GetRange(vtkm::Range* range, TypeList, StorageList) const
216   {
217     VTKM_IS_LIST_TAG(TypeList);
218     VTKM_IS_LIST_TAG(StorageList);
219 
220     this->GetRange(TypeList(), StorageList());
221 
222     vtkm::Id length = this->Range.GetNumberOfValues();
223     for (vtkm::Id i = 0; i < length; ++i)
224     {
225       range[i] = this->Range.GetPortalConstControl().Get(i);
226     }
227   }
228 
229   template <typename TypeList>
GetRange(TypeList)230   VTKM_CONT const vtkm::cont::ArrayHandle<vtkm::Range>& GetRange(TypeList) const
231   {
232     VTKM_IS_LIST_TAG(TypeList);
233 
234     return this->GetRange(TypeList(), VTKM_DEFAULT_STORAGE_LIST_TAG());
235   }
236 
237   template <typename TypeList>
GetRange(vtkm::Range * range,TypeList)238   VTKM_CONT void GetRange(vtkm::Range* range, TypeList) const
239   {
240     VTKM_IS_LIST_TAG(TypeList);
241 
242     this->GetRange(range, TypeList(), VTKM_DEFAULT_STORAGE_LIST_TAG());
243   }
244 
245   VTKM_CONT
246   const vtkm::cont::ArrayHandle<vtkm::Range>& GetRange() const;
247 
248   VTKM_CONT
249   void GetRange(vtkm::Range* range) const;
250 
251   const vtkm::cont::DynamicArrayHandle& GetData() const;
252 
253   vtkm::cont::DynamicArrayHandle& GetData();
254 
255   template <typename T, typename StorageTag>
SetData(const vtkm::cont::ArrayHandle<T,StorageTag> & newdata)256   VTKM_CONT void SetData(const vtkm::cont::ArrayHandle<T, StorageTag>& newdata)
257   {
258     this->Data = newdata;
259     this->ModifiedFlag = true;
260   }
261 
262   VTKM_CONT
SetData(const vtkm::cont::DynamicArrayHandle & newdata)263   void SetData(const vtkm::cont::DynamicArrayHandle& newdata)
264   {
265     this->Data = newdata;
266     this->ModifiedFlag = true;
267   }
268 
269   template <typename T>
CopyData(const T * ptr,vtkm::Id nvals)270   VTKM_CONT void CopyData(const T* ptr, vtkm::Id nvals)
271   {
272     this->Data = vtkm::cont::make_ArrayHandle(ptr, nvals, true);
273     this->ModifiedFlag = true;
274   }
275 
276   VTKM_CONT
277   virtual void PrintSummary(std::ostream& out) const;
278 
279   VTKM_CONT
ReleaseResourcesExecution()280   virtual void ReleaseResourcesExecution()
281   {
282     // TODO: Call ReleaseResourcesExecution on the data when
283     // the DynamicArrayHandle class is able to do so.
284     this->Range.ReleaseResourcesExecution();
285   }
286 
287 private:
288   std::string Name; ///< name of field
289 
290   Association FieldAssociation;
291   std::string AssocCellSetName;      ///< only populate if assoc is cells
292   vtkm::IdComponent AssocLogicalDim; ///< only populate if assoc is logical dim
293 
294   vtkm::cont::DynamicArrayHandle Data;
295   mutable vtkm::cont::ArrayHandle<vtkm::Range> Range;
296   mutable bool ModifiedFlag;
297 
298   template <typename TypeList, typename StorageList>
GetRangeImpl(TypeList,StorageList)299   VTKM_CONT const vtkm::cont::ArrayHandle<vtkm::Range>& GetRangeImpl(TypeList, StorageList) const
300   {
301     VTKM_IS_LIST_TAG(TypeList);
302     VTKM_IS_LIST_TAG(StorageList);
303 
304     if (this->ModifiedFlag)
305     {
306       internal::ComputeRange computeRange(this->Range);
307       this->Data.ResetTypeAndStorageLists(TypeList(), StorageList()).CastAndCall(computeRange);
308       this->ModifiedFlag = false;
309     }
310 
311     return this->Range;
312   }
313 };
314 
315 template <typename Functor, typename... Args>
CastAndCall(const vtkm::cont::Field & field,Functor && f,Args &&...args)316 void CastAndCall(const vtkm::cont::Field& field, Functor&& f, Args&&... args)
317 {
318   field.GetData().CastAndCall(std::forward<Functor>(f), std::forward<Args>(args)...);
319 }
320 
321 //@{
322 /// Convenience functions to build fields from C style arrays and std::vector
323 template <typename T>
324 vtkm::cont::Field make_Field(std::string name,
325                              Field::Association association,
326                              const T* data,
327                              vtkm::Id size,
328                              vtkm::CopyFlag copy = vtkm::CopyFlag::Off)
329 {
330   return vtkm::cont::Field(name, association, vtkm::cont::make_ArrayHandle(data, size, copy));
331 }
332 
333 template <typename T>
334 vtkm::cont::Field make_Field(std::string name,
335                              Field::Association association,
336                              const std::vector<T>& data,
337                              vtkm::CopyFlag copy = vtkm::CopyFlag::Off)
338 {
339   return vtkm::cont::Field(name, association, vtkm::cont::make_ArrayHandle(data, copy));
340 }
341 
342 template <typename T>
343 vtkm::cont::Field make_Field(std::string name,
344                              Field::Association association,
345                              const std::string& cellSetName,
346                              const T* data,
347                              vtkm::Id size,
348                              vtkm::CopyFlag copy = vtkm::CopyFlag::Off)
349 {
350   return vtkm::cont::Field(
351     name, association, cellSetName, vtkm::cont::make_ArrayHandle(data, size, copy));
352 }
353 
354 template <typename T>
355 vtkm::cont::Field make_Field(std::string name,
356                              Field::Association association,
357                              const std::string& cellSetName,
358                              const std::vector<T>& data,
359                              vtkm::CopyFlag copy = vtkm::CopyFlag::Off)
360 {
361   return vtkm::cont::Field(
362     name, association, cellSetName, vtkm::cont::make_ArrayHandle(data, copy));
363 }
364 
365 template <typename T>
366 vtkm::cont::Field make_Field(std::string name,
367                              Field::Association association,
368                              vtkm::IdComponent logicalDim,
369                              const T* data,
370                              vtkm::Id size,
371                              vtkm::CopyFlag copy = vtkm::CopyFlag::Off)
372 {
373   return vtkm::cont::Field(
374     name, association, logicalDim, vtkm::cont::make_ArrayHandle(data, size, copy));
375 }
376 
377 template <typename T>
378 vtkm::cont::Field make_Field(std::string name,
379                              Field::Association association,
380                              vtkm::IdComponent logicalDim,
381                              const std::vector<T>& data,
382                              vtkm::CopyFlag copy = vtkm::CopyFlag::Off)
383 {
384   return vtkm::cont::Field(name, association, logicalDim, vtkm::cont::make_ArrayHandle(data, copy));
385 }
386 //@}
387 
388 namespace internal
389 {
390 
391 template <>
392 struct DynamicTransformTraits<vtkm::cont::Field>
393 {
394   using DynamicTag = vtkm::cont::internal::DynamicTransformTagCastAndCall;
395 };
396 
397 } // namespace internal
398 } // namespace cont
399 } // namespace vtkm
400 
401 //=============================================================================
402 // Specializations of serialization related classes
403 namespace vtkm
404 {
405 namespace cont
406 {
407 
408 template <typename TypeList = VTKM_DEFAULT_TYPE_LIST_TAG,
409           typename StorageList = VTKM_DEFAULT_STORAGE_LIST_TAG>
410 struct SerializableField
411 {
412   SerializableField() = default;
413 
414   explicit SerializableField(const vtkm::cont::Field& field)
415     : Field(field)
416   {
417   }
418 
419   vtkm::cont::Field Field;
420 };
421 }
422 } // vtkm::cont
423 
424 namespace diy
425 {
426 
427 template <typename TypeList, typename StorageList>
428 struct Serialization<vtkm::cont::SerializableField<TypeList, StorageList>>
429 {
430 private:
431   using Type = vtkm::cont::SerializableField<TypeList, StorageList>;
432 
433 public:
434   static VTKM_CONT void save(BinaryBuffer& bb, const Type& serializable)
435   {
436     const auto& field = serializable.Field;
437 
438     diy::save(bb, field.GetName());
439     diy::save(bb, static_cast<int>(field.GetAssociation()));
440     if (field.GetAssociation() == vtkm::cont::Field::Association::CELL_SET)
441     {
442       diy::save(bb, field.GetAssocCellSet());
443     }
444     else if (field.GetAssociation() == vtkm::cont::Field::Association::LOGICAL_DIM)
445     {
446       diy::save(bb, field.GetAssocLogicalDim());
447     }
448     diy::save(bb, field.GetData().ResetTypeAndStorageLists(TypeList{}, StorageList{}));
449   }
450 
451   static VTKM_CONT void load(BinaryBuffer& bb, Type& serializable)
452   {
453     auto& field = serializable.Field;
454 
455     std::string name;
456     diy::load(bb, name);
457     int assocVal = 0;
458     diy::load(bb, assocVal);
459 
460     auto assoc = static_cast<vtkm::cont::Field::Association>(assocVal);
461     vtkm::cont::DynamicArrayHandleBase<TypeList, StorageList> data;
462     if (assoc == vtkm::cont::Field::Association::CELL_SET)
463     {
464       std::string assocCellSetName;
465       diy::load(bb, assocCellSetName);
466       diy::load(bb, data);
467       field =
468         vtkm::cont::Field(name, assoc, assocCellSetName, vtkm::cont::DynamicArrayHandle(data));
469     }
470     else if (assoc == vtkm::cont::Field::Association::LOGICAL_DIM)
471     {
472       vtkm::IdComponent assocLogicalDim;
473       diy::load(bb, assocLogicalDim);
474       diy::load(bb, data);
475       field = vtkm::cont::Field(name, assoc, assocLogicalDim, vtkm::cont::DynamicArrayHandle(data));
476     }
477     else
478     {
479       diy::load(bb, data);
480       field = vtkm::cont::Field(name, assoc, vtkm::cont::DynamicArrayHandle(data));
481     }
482   }
483 };
484 
485 } // diy
486 
487 #endif //vtk_m_cont_Field_h
488