Intrepid2
Intrepid2_BasisValues.hpp
Go to the documentation of this file.
1 // @HEADER
2 // *****************************************************************************
3 // Intrepid2 Package
4 //
5 // Copyright 2007 NTESS and the Intrepid2 contributors.
6 // SPDX-License-Identifier: BSD-3-Clause
7 // *****************************************************************************
8 // @HEADER
9 
15 #include "Intrepid2_TensorData.hpp"
16 #include "Intrepid2_VectorData.hpp"
17 
18 #ifndef Intrepid2_BasisValues_h
19 #define Intrepid2_BasisValues_h
20 
32 namespace Intrepid2
33 {
34  template<class Scalar, typename DeviceType>
36  {
39 
40  Kokkos::Array<TensorDataType,Parameters::MaxTensorComponents> tensorDataFamilies_;
41  VectorDataType vectorData_;
42 
43  int numTensorDataFamilies_ = -1;
44 
45  Kokkos::View<ordinal_type*,DeviceType> ordinalFilter_;
46  public:
49  :
50  tensorDataFamilies_({tensorData}),
51  numTensorDataFamilies_(1)
52  {}
53 
55  BasisValues(std::vector<TensorDataType> tensorDataFamilies)
56  :
57  numTensorDataFamilies_(tensorDataFamilies.size())
58  {
59  for (int family=0; family<numTensorDataFamilies_; family++)
60  {
61  tensorDataFamilies_[family] = tensorDataFamilies[family];
62  }
63  }
64 
67  :
68  vectorData_(vectorData)
69  {}
70 
73  :
74  numTensorDataFamilies_(0)
75  {}
76 
77 
79  template<typename OtherDeviceType, class = typename std::enable_if<!std::is_same<DeviceType, OtherDeviceType>::value>::type>
81  :
82  vectorData_(basisValues.vectorData()),
83  numTensorDataFamilies_(basisValues.numTensorDataFamilies())
84  {
85  auto otherFamilies = basisValues.tensorDataFamilies();
86  for (int family=0; family<numTensorDataFamilies_; family++)
87  {
88  tensorDataFamilies_[family] = TensorData<Scalar,DeviceType>(otherFamilies[family]);
89  }
90  auto otherOrdinalFilter = basisValues.ordinalFilter();
91  ordinalFilter_ = Kokkos::View<ordinal_type*,DeviceType>("BasisValues::ordinalFilter_",otherOrdinalFilter.extent(0));
92 
93  Kokkos::deep_copy(ordinalFilter_, otherOrdinalFilter);
94  }
95 
97  BasisValues<Scalar,DeviceType> basisValuesForFields(const int &fieldStartOrdinal, const int &numFields)
98  {
99  int familyStartOrdinal = -1, familyEndOrdinal = -1;
100  const int familyCount = this->numFamilies();
101  int fieldsSoFar = 0;
102  for (int i=0; i<familyCount; i++)
103  {
104  const bool startMatches = (fieldsSoFar == fieldStartOrdinal);
105  familyStartOrdinal = startMatches ? i : familyStartOrdinal;
106  fieldsSoFar += numFieldsInFamily(i);
107  const bool endMatches = (fieldsSoFar - fieldStartOrdinal == numFields);
108  familyEndOrdinal = endMatches ? i : familyEndOrdinal;
109  }
110  INTREPID2_TEST_FOR_EXCEPTION(familyStartOrdinal == -1, std::invalid_argument, "fieldStartOrdinal does not align with the start of a family.");
111  INTREPID2_TEST_FOR_EXCEPTION(familyEndOrdinal == -1, std::invalid_argument, "fieldStartOrdinal + numFields does not align with the end of a family.");
112 
113  const int numFamiliesInFieldSpan = familyEndOrdinal - familyStartOrdinal + 1;
114  if (numTensorDataFamilies_ > 0)
115  {
116  std::vector<TensorDataType> tensorDataFamilies(numFamiliesInFieldSpan);
117  for (int i=familyStartOrdinal; i<=familyEndOrdinal; i++)
118  {
119  tensorDataFamilies[i-familyStartOrdinal] = tensorDataFamilies_[i];
120  }
122  }
123  else
124  {
125  const int componentCount = vectorData_.numComponents();
126  std::vector< std::vector<TensorData<Scalar,DeviceType> > > vectorComponents(numFamiliesInFieldSpan, std::vector<TensorData<Scalar,DeviceType> >(componentCount));
127  for (int i=familyStartOrdinal; i<=familyEndOrdinal; i++)
128  {
129  for (int j=0; j<componentCount; j++)
130  {
131  vectorComponents[i-familyStartOrdinal][j] = vectorData_.getComponent(i,j);
132  }
133  }
134  return BasisValues<Scalar,DeviceType>(vectorComponents);
135  }
136  }
137 
139  KOKKOS_INLINE_FUNCTION
140  int familyFieldOrdinalOffset(const int &familyOrdinal) const
141  {
142  if (vectorData_.isValid())
143  {
144  return vectorData_.familyFieldOrdinalOffset(familyOrdinal);
145  }
146  else
147  {
148  int offset = 0;
149  for (int i=0; i<familyOrdinal; i++)
150  {
151  offset += tensorDataFamilies_[i].extent_int(0); // (F,P,…)
152  }
153  return offset;
154  }
155  }
156 
159  {
160  INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE(numTensorDataFamilies_ != 1, std::invalid_argument, "this method is not supported when numTensorDataFamilies_ != 1");
161  return tensorDataFamilies_[0];
162  }
163 
165  const TensorDataType & tensorData(const int &familyOrdinal) const
166  {
167  INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE(familyOrdinal >= numTensorDataFamilies_, std::invalid_argument, "familyOrdinal too large");
168  INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE(familyOrdinal < 0, std::invalid_argument, "familyOrdinal may not be less than 0");
169  return tensorDataFamilies_[familyOrdinal];
170  }
171 
173  KOKKOS_INLINE_FUNCTION
174  int numFamilies() const
175  {
176  if (vectorData_.isValid())
177  {
178  return vectorData_.numFamilies();
179  }
180  else
181  {
182  return numTensorDataFamilies_;
183  }
184  }
185 
186  KOKKOS_INLINE_FUNCTION
187  int numTensorDataFamilies() const
188  {
189  return numTensorDataFamilies_;
190  }
191 
192  KOKKOS_INLINE_FUNCTION
193  int numFieldsInFamily(int familyOrdinal) const
194  {
195  if (vectorData_.isValid())
196  {
197  return vectorData_.numFieldsInFamily(familyOrdinal);
198  }
199  else
200  {
201  return tensorDataFamilies_[familyOrdinal].extent_int(0); // (F,P,…)
202  }
203  }
204 
206  const Kokkos::Array<TensorDataType,Parameters::MaxTensorComponents> & tensorDataFamilies() const
207  {
208  return tensorDataFamilies_;
209  }
210 
212  const VectorDataType & vectorData() const
213  {
214  return vectorData_;
215  }
216 
218  KOKKOS_INLINE_FUNCTION
219  Scalar operator()(const int &fieldOrdinal, const int &pointOrdinal) const
220  {
221  const int &tensorFieldOrdinal = (ordinalFilter_.extent(0) > 0) ? ordinalFilter_(fieldOrdinal) : fieldOrdinal;
222  if (numTensorDataFamilies_ == 1)
223  {
224 #ifdef HAVE_INTREPID2_DEBUG
225  INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE(! tensorDataFamilies_[0].isValid(), std::invalid_argument, "TensorData object not initialized!");
226 #endif
227  return tensorDataFamilies_[0](tensorFieldOrdinal, pointOrdinal);
228  }
229  else
230  {
231  int familyForField = -1;
232  int previousFamilyEnd = -1;
233  int fieldAdjustment = 0;
234  // this loop is written in such a way as to avoid branching for CUDA performance
235  for (int family=0; family<numTensorDataFamilies_; family++)
236  {
237  const int familyFieldCount = tensorDataFamilies_[family].extent_int(0);
238  const bool fieldInRange = (tensorFieldOrdinal > previousFamilyEnd) && (tensorFieldOrdinal <= previousFamilyEnd + familyFieldCount);
239  familyForField = fieldInRange ? family : familyForField;
240  fieldAdjustment = fieldInRange ? previousFamilyEnd + 1 : fieldAdjustment;
241  previousFamilyEnd += familyFieldCount;
242  }
243 #ifdef HAVE_INTREPID2_DEBUG
244  INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE( familyForField == -1, std::invalid_argument, "fieldOrdinal appears to be out of range");
245 #endif
246  return tensorDataFamilies_[familyForField](tensorFieldOrdinal-fieldAdjustment,pointOrdinal);
247  }
248  }
249 
251  KOKKOS_INLINE_FUNCTION
252  Scalar operator()(const int &fieldOrdinal, const int &pointOrdinal, const int &dim) const
253  {
254 #ifdef HAVE_INTREPID2_DEBUG
255  INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE(! vectorData_.isValid(), std::invalid_argument, "VectorData object not initialized!");
256 #endif
257  const int &tensorFieldOrdinal = (ordinalFilter_.extent(0) > 0) ? ordinalFilter_(fieldOrdinal) : fieldOrdinal;
258  return vectorData_(tensorFieldOrdinal, pointOrdinal, dim);
259  }
260 
262  KOKKOS_INLINE_FUNCTION
263  Scalar operator()(const int &cellOrdinal, const int &fieldOrdinal, const int &pointOrdinal, const int &dim) const
264  {
265  INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE(true, std::invalid_argument, "CVFEM support not yet implemented in BasisValues");
266  return 0;
267  }
268 
269  KOKKOS_INLINE_FUNCTION
270  int extent_int(const int &i) const
271  {
272  // shape is (F,P) or (F,P,D)
273  if (i == 0) // field dimension
274  {
275  if (ordinalFilter_.extent_int(0) == 0)
276  {
277  int numFields = 0;
278  for (int familyOrdinal=0; familyOrdinal<numFamilies(); familyOrdinal++)
279  {
280  numFields += numFieldsInFamily(familyOrdinal);
281  }
282  return numFields;
283  }
284  else
285  {
286  return ordinalFilter_.extent_int(0);
287  }
288  }
289  else
290  {
291  if (vectorData_.isValid())
292  {
293  return vectorData_.extent_int(i);
294  }
295  else if (tensorDataFamilies_[0].isValid())
296  {
297  return tensorDataFamilies_[0].extent_int(i);
298  }
299  else
300  {
301  return 0;
302  }
303  }
304  }
305 
306 
307  KOKKOS_INLINE_FUNCTION
308  size_t extent(const int &i) const
309  {
310  return static_cast<size_t>(extent_int(i));
311  }
312 
313  KOKKOS_INLINE_FUNCTION
314  size_t rank() const
315  {
316  if (vectorData_.isValid())
317  {
318  return vectorData_.rank();
319  }
320  else if (tensorDataFamilies_[0].isValid())
321  {
322  return tensorDataFamilies_[0].rank();
323  }
324  else
325  {
326  return 0;
327  }
328  }
329 
330  void setOrdinalFilter(Kokkos::View<ordinal_type*,DeviceType> ordinalFilter)
331  {
332  ordinalFilter_ = ordinalFilter;
333  }
334 
335  Kokkos::View<ordinal_type*,DeviceType> ordinalFilter() const
336  {
337  return ordinalFilter_;
338  }
339  };
340 
341  template<class Scalar, typename DeviceType>
342  KOKKOS_INLINE_FUNCTION unsigned rank(const BasisValues<Scalar,DeviceType> &basisValues)
343  {
344  return basisValues.rank();
345  }
346 } // namespace Intrepid2
347 
348 #endif /* Intrepid2_BasisValues_h */
KOKKOS_INLINE_FUNCTION int familyFieldOrdinalOffset(const int &familyOrdinal) const
Returns the field ordinal offset for the specified family.
KOKKOS_INLINE_FUNCTION int numFieldsInFamily(const unsigned &familyOrdinal) const
returns the number of fields in the specified family
BasisValues()
Default constructor.
#define INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE(test, x, msg)
BasisValues< Scalar, DeviceType > basisValuesForFields(const int &fieldStartOrdinal, const int &numFields)
field start and length must align with families in vectorData_ or tensorDataFamilies_ (whichever is v...
const VectorDataType & vectorData() const
VectorData accessor.
BasisValues(const BasisValues< Scalar, OtherDeviceType > &basisValues)
copy-like constructor for differing execution spaces. This does a deep copy of underlying views...
KOKKOS_INLINE_FUNCTION int numFamilies() const
returns the number of families
TensorDataType & tensorData()
TensorData accessor for single-family scalar data.
KOKKOS_INLINE_FUNCTION Scalar operator()(const int &fieldOrdinal, const int &pointOrdinal, const int &dim) const
operator() for (F,P,D) vector data; throws an exception if this is not a vector-valued container ...
The data containers in Intrepid2 that support sum factorization and other reduced-data optimizations ...
BasisValues(TensorDataType tensorData)
Constructor for scalar-valued BasisValues with a single family of values.
KOKKOS_INLINE_FUNCTION Scalar operator()(const int &fieldOrdinal, const int &pointOrdinal) const
operator() for (F,P) scalar data; throws an exception if this is not a scalar-valued container ...
Reference-space field values for a basis, designed to support typical vector-valued bases...
KOKKOS_INLINE_FUNCTION int numFamilies() const
For valid vectorData, returns the number of families in vectorData; otherwise, returns number of Tens...
KOKKOS_INLINE_FUNCTION const TensorData< Scalar, DeviceType > & getComponent(const int &componentOrdinal) const
Single-argument component accessor for the axial-component or the single-family case; in this case...
KOKKOS_INLINE_FUNCTION int extent_int(const int &r) const
Returns the extent in the specified dimension as an int.
const TensorDataType & tensorData(const int &familyOrdinal) const
TensorData accessor for multi-family scalar data.
BasisValues(std::vector< TensorDataType > tensorDataFamilies)
Constructor for scalar-valued BasisValues, with potentially multiple families of values. (Used, e.g., for op = DIV and functionSpace = HDIV.)
BasisValues(VectorDataType vectorData)
Constructor for vector-valued BasisValues.
const Kokkos::Array< TensorDataType, Parameters::MaxTensorComponents > & tensorDataFamilies() const
TensorDataFamilies accessor.
KOKKOS_INLINE_FUNCTION constexpr bool isValid() const
returns true for containers that have data; false for those that don&#39;t (e.g., those that have been co...
KOKKOS_INLINE_FUNCTION int familyFieldOrdinalOffset(const int &familyOrdinal) const
Returns the field ordinal offset for the specified family.
KOKKOS_INLINE_FUNCTION unsigned rank() const
Returns the rank of this container, which is 3.
View-like interface to tensor data; tensor components are stored separately and multiplied together a...
KOKKOS_INLINE_FUNCTION Scalar operator()(const int &cellOrdinal, const int &fieldOrdinal, const int &pointOrdinal, const int &dim) const
operator() for (C,F,P,D) data, which arises in CVFEM; at present unimplemented, and only declared her...
View-like interface to tensor data; tensor components are stored separately and multiplied together a...
KOKKOS_INLINE_FUNCTION int numComponents() const
returns the number of components
Reference-space field values for a basis, designed to support typical vector-valued bases...