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  {
37  public:
38  using value_type = Scalar;
39  private:
42 
43  Kokkos::Array<TensorDataType,Parameters::MaxTensorComponents> tensorDataFamilies_;
44  VectorDataType vectorData_;
45 
46  int numTensorDataFamilies_ = -1;
47 
48  Kokkos::View<ordinal_type*,DeviceType> ordinalFilter_;
49  public:
52  :
53  tensorDataFamilies_({tensorData}),
54  numTensorDataFamilies_(1)
55  {}
56 
58  BasisValues(std::vector<TensorDataType> tensorDataFamilies)
59  :
60  numTensorDataFamilies_(tensorDataFamilies.size())
61  {
62  for (int family=0; family<numTensorDataFamilies_; family++)
63  {
64  tensorDataFamilies_[family] = tensorDataFamilies[family];
65  }
66  }
67 
70  :
71  vectorData_(vectorData)
72  {}
73 
76  :
77  numTensorDataFamilies_(0)
78  {}
79 
80 
82  template<typename OtherDeviceType, class = typename std::enable_if<!std::is_same<DeviceType, OtherDeviceType>::value>::type>
84  :
85  vectorData_(basisValues.vectorData()),
86  numTensorDataFamilies_(basisValues.numTensorDataFamilies())
87  {
88  auto otherFamilies = basisValues.tensorDataFamilies();
89  for (int family=0; family<numTensorDataFamilies_; family++)
90  {
91  tensorDataFamilies_[family] = TensorData<Scalar,DeviceType>(otherFamilies[family]);
92  }
93  auto otherOrdinalFilter = basisValues.ordinalFilter();
94  ordinalFilter_ = Kokkos::View<ordinal_type*,DeviceType>("BasisValues::ordinalFilter_",otherOrdinalFilter.extent(0));
95 
96  Kokkos::deep_copy(ordinalFilter_, otherOrdinalFilter);
97  }
98 
100  BasisValues<Scalar,DeviceType> basisValuesForFields(const int &fieldStartOrdinal, const int &numFields)
101  {
102  int familyStartOrdinal = -1, familyEndOrdinal = -1;
103  const int familyCount = this->numFamilies();
104  int fieldsSoFar = 0;
105  for (int i=0; i<familyCount; i++)
106  {
107  const bool startMatches = (fieldsSoFar == fieldStartOrdinal);
108  familyStartOrdinal = startMatches ? i : familyStartOrdinal;
109  fieldsSoFar += numFieldsInFamily(i);
110  const bool endMatches = (fieldsSoFar - fieldStartOrdinal == numFields);
111  familyEndOrdinal = endMatches ? i : familyEndOrdinal;
112  }
113  INTREPID2_TEST_FOR_EXCEPTION(familyStartOrdinal == -1, std::invalid_argument, "fieldStartOrdinal does not align with the start of a family.");
114  INTREPID2_TEST_FOR_EXCEPTION(familyEndOrdinal == -1, std::invalid_argument, "fieldStartOrdinal + numFields does not align with the end of a family.");
115 
116  const int numFamiliesInFieldSpan = familyEndOrdinal - familyStartOrdinal + 1;
117  if (numTensorDataFamilies_ > 0)
118  {
119  std::vector<TensorDataType> tensorDataFamilies(numFamiliesInFieldSpan);
120  for (int i=familyStartOrdinal; i<=familyEndOrdinal; i++)
121  {
122  tensorDataFamilies[i-familyStartOrdinal] = tensorDataFamilies_[i];
123  }
125  }
126  else
127  {
128  const int componentCount = vectorData_.numComponents();
129  std::vector< std::vector<TensorData<Scalar,DeviceType> > > vectorComponents(numFamiliesInFieldSpan, std::vector<TensorData<Scalar,DeviceType> >(componentCount));
130  for (int i=familyStartOrdinal; i<=familyEndOrdinal; i++)
131  {
132  for (int j=0; j<componentCount; j++)
133  {
134  vectorComponents[i-familyStartOrdinal][j] = vectorData_.getComponent(i,j);
135  }
136  }
137  return BasisValues<Scalar,DeviceType>(vectorComponents);
138  }
139  }
140 
142  KOKKOS_INLINE_FUNCTION
143  int familyFieldOrdinalOffset(const int &familyOrdinal) const
144  {
145  if (vectorData_.isValid())
146  {
147  return vectorData_.familyFieldOrdinalOffset(familyOrdinal);
148  }
149  else
150  {
151  int offset = 0;
152  for (int i=0; i<familyOrdinal; i++)
153  {
154  offset += tensorDataFamilies_[i].extent_int(0); // (F,P,…)
155  }
156  return offset;
157  }
158  }
159 
162  {
163  INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE(numTensorDataFamilies_ != 1, std::invalid_argument, "this method is not supported when numTensorDataFamilies_ != 1");
164  return tensorDataFamilies_[0];
165  }
166 
168  const TensorDataType & tensorData(const int &familyOrdinal) const
169  {
170  INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE(familyOrdinal >= numTensorDataFamilies_, std::invalid_argument, "familyOrdinal too large");
171  INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE(familyOrdinal < 0, std::invalid_argument, "familyOrdinal may not be less than 0");
172  return tensorDataFamilies_[familyOrdinal];
173  }
174 
176  KOKKOS_INLINE_FUNCTION
177  int numFamilies() const
178  {
179  if (vectorData_.isValid())
180  {
181  return vectorData_.numFamilies();
182  }
183  else
184  {
185  return numTensorDataFamilies_;
186  }
187  }
188 
189  KOKKOS_INLINE_FUNCTION
190  int numTensorDataFamilies() const
191  {
192  return numTensorDataFamilies_;
193  }
194 
195  KOKKOS_INLINE_FUNCTION
196  int numFieldsInFamily(int familyOrdinal) const
197  {
198  if (vectorData_.isValid())
199  {
200  return vectorData_.numFieldsInFamily(familyOrdinal);
201  }
202  else
203  {
204  return tensorDataFamilies_[familyOrdinal].extent_int(0); // (F,P,…)
205  }
206  }
207 
209  const Kokkos::Array<TensorDataType,Parameters::MaxTensorComponents> & tensorDataFamilies() const
210  {
211  return tensorDataFamilies_;
212  }
213 
215  const VectorDataType & vectorData() const
216  {
217  return vectorData_;
218  }
219 
221  KOKKOS_INLINE_FUNCTION
222  Scalar operator()(const int &fieldOrdinal, const int &pointOrdinal) const
223  {
224  const int &tensorFieldOrdinal = (ordinalFilter_.extent(0) > 0) ? ordinalFilter_(fieldOrdinal) : fieldOrdinal;
225  if (numTensorDataFamilies_ == 1)
226  {
227 #ifdef HAVE_INTREPID2_DEBUG
228  INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE(! tensorDataFamilies_[0].isValid(), std::invalid_argument, "TensorData object not initialized!");
229 #endif
230  return tensorDataFamilies_[0](tensorFieldOrdinal, pointOrdinal);
231  }
232  else
233  {
234  int familyForField = -1;
235  int previousFamilyEnd = -1;
236  int fieldAdjustment = 0;
237  // this loop is written in such a way as to avoid branching for CUDA performance
238  for (int family=0; family<numTensorDataFamilies_; family++)
239  {
240  const int familyFieldCount = tensorDataFamilies_[family].extent_int(0);
241  const bool fieldInRange = (tensorFieldOrdinal > previousFamilyEnd) && (tensorFieldOrdinal <= previousFamilyEnd + familyFieldCount);
242  familyForField = fieldInRange ? family : familyForField;
243  fieldAdjustment = fieldInRange ? previousFamilyEnd + 1 : fieldAdjustment;
244  previousFamilyEnd += familyFieldCount;
245  }
246 #ifdef HAVE_INTREPID2_DEBUG
247  INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE( familyForField == -1, std::invalid_argument, "fieldOrdinal appears to be out of range");
248 #endif
249  return tensorDataFamilies_[familyForField](tensorFieldOrdinal-fieldAdjustment,pointOrdinal);
250  }
251  }
252 
254  KOKKOS_INLINE_FUNCTION
255  Scalar operator()(const int &fieldOrdinal, const int &pointOrdinal, const int &dim) const
256  {
257 #ifdef HAVE_INTREPID2_DEBUG
258  INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE(! vectorData_.isValid(), std::invalid_argument, "VectorData object not initialized!");
259 #endif
260  const int &tensorFieldOrdinal = (ordinalFilter_.extent(0) > 0) ? ordinalFilter_(fieldOrdinal) : fieldOrdinal;
261  return vectorData_(tensorFieldOrdinal, pointOrdinal, dim);
262  }
263 
265  KOKKOS_INLINE_FUNCTION
266  Scalar operator()(const int &cellOrdinal, const int &fieldOrdinal, const int &pointOrdinal, const int &dim) const
267  {
268  INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE(true, std::invalid_argument, "CVFEM support not yet implemented in BasisValues");
269  return 0;
270  }
271 
272  KOKKOS_INLINE_FUNCTION
273  int extent_int(const int &i) const
274  {
275  // shape is (F,P) or (F,P,D)
276  if (i == 0) // field dimension
277  {
278  if (ordinalFilter_.extent_int(0) == 0)
279  {
280  int numFields = 0;
281  for (int familyOrdinal=0; familyOrdinal<numFamilies(); familyOrdinal++)
282  {
283  numFields += numFieldsInFamily(familyOrdinal);
284  }
285  return numFields;
286  }
287  else
288  {
289  return ordinalFilter_.extent_int(0);
290  }
291  }
292  else
293  {
294  if (vectorData_.isValid())
295  {
296  return vectorData_.extent_int(i);
297  }
298  else if (tensorDataFamilies_[0].isValid())
299  {
300  return tensorDataFamilies_[0].extent_int(i);
301  }
302  else
303  {
304  return 0;
305  }
306  }
307  }
308 
309 
310  KOKKOS_INLINE_FUNCTION
311  size_t extent(const int &i) const
312  {
313  return static_cast<size_t>(extent_int(i));
314  }
315 
316  KOKKOS_INLINE_FUNCTION
317  size_t rank() const
318  {
319  if (vectorData_.isValid())
320  {
321  return vectorData_.rank();
322  }
323  else if (tensorDataFamilies_[0].isValid())
324  {
325  return tensorDataFamilies_[0].rank();
326  }
327  else
328  {
329  return 0;
330  }
331  }
332 
333  void setOrdinalFilter(Kokkos::View<ordinal_type*,DeviceType> ordinalFilter)
334  {
335  ordinalFilter_ = ordinalFilter;
336  }
337 
338  Kokkos::View<ordinal_type*,DeviceType> ordinalFilter() const
339  {
340  return ordinalFilter_;
341  }
342  };
343 
344  template<class Scalar, typename DeviceType>
345  KOKKOS_INLINE_FUNCTION unsigned rank(const BasisValues<Scalar,DeviceType> &basisValues)
346  {
347  return basisValues.rank();
348  }
349 } // namespace Intrepid2
350 
351 #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...