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
17
18#ifndef Intrepid2_BasisValues_h
19#define Intrepid2_BasisValues_h
20
32namespace 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
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 */
View-like interface to tensor data; tensor components are stored separately and multiplied together a...
#define INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE(test, x, msg)
Reference-space field values for a basis, designed to support typical vector-valued bases.
The data containers in Intrepid2 that support sum factorization and other reduced-data optimizations ...
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...
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
BasisValues(const BasisValues< Scalar, OtherDeviceType > &basisValues)
copy-like constructor for differing execution spaces. This does a deep copy of underlying views.
BasisValues(TensorDataType tensorData)
Constructor for scalar-valued BasisValues with a single family of values.
const Kokkos::Array< TensorDataType, Parameters::MaxTensorComponents > & tensorDataFamilies() const
TensorDataFamilies accessor.
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
const VectorDataType & vectorData() const
VectorData accessor.
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...
BasisValues()
Default constructor.
const TensorDataType & tensorData(const int &familyOrdinal) const
TensorData accessor for multi-family scalar data.
KOKKOS_INLINE_FUNCTION int numFamilies() const
For valid vectorData, returns the number of families in vectorData; otherwise, returns number of Tens...
KOKKOS_INLINE_FUNCTION int familyFieldOrdinalOffset(const int &familyOrdinal) const
Returns the field ordinal offset for the specified family.
BasisValues(VectorDataType vectorData)
Constructor for vector-valued BasisValues.
BasisValues(std::vector< TensorDataType > tensorDataFamilies)
Constructor for scalar-valued BasisValues, with potentially multiple families of values....
TensorDataType & tensorData()
TensorData accessor for single-family scalar data.
View-like interface to tensor data; tensor components are stored separately and multiplied together a...
Reference-space field values for a basis, designed to support typical vector-valued bases.
KOKKOS_INLINE_FUNCTION int numFieldsInFamily(const unsigned &familyOrdinal) const
returns the number of fields in the specified family
KOKKOS_INLINE_FUNCTION unsigned rank() const
Returns the rank of this container, which is 3.
KOKKOS_INLINE_FUNCTION int numComponents() const
returns the number of components
KOKKOS_INLINE_FUNCTION int familyFieldOrdinalOffset(const int &familyOrdinal) const
Returns the field ordinal offset for the specified family.
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 constexpr bool isValid() const
returns true for containers that have data; false for those that don't (e.g., those that have been co...
KOKKOS_INLINE_FUNCTION int numFamilies() const
returns the number of families
KOKKOS_INLINE_FUNCTION int extent_int(const int &r) const
Returns the extent in the specified dimension as an int.