Intrepid2
Intrepid2_Data.hpp
Go to the documentation of this file.
1//
2// Intrepid2_Data.hpp
3// QuadraturePerformance
4//
5// Created by Roberts, Nathan V on 8/24/20.
6//
7
8#ifndef Intrepid2_Data_h
9#define Intrepid2_Data_h
10
15#include "Intrepid2_ScalarView.hpp"
16#include "Intrepid2_Utils.hpp"
17
22
23namespace Intrepid2 {
24
33template<class DataScalar,typename DeviceType>
34class ZeroView {
35public:
36 static ScalarView<DataScalar,DeviceType> zeroView()
37 {
38 static ScalarView<DataScalar,DeviceType> zeroView = ScalarView<DataScalar,DeviceType>("zero",1);
39 static bool havePushedFinalizeHook = false;
40 if (!havePushedFinalizeHook)
41 {
42 Kokkos::push_finalize_hook( [=] {
43 zeroView = ScalarView<DataScalar,DeviceType>();
44 });
45 havePushedFinalizeHook = true;
46 }
47 return zeroView;
48 }
49};
50
68 template<class DataScalar,typename DeviceType>
69 class Data {
70 public:
71 using value_type = DataScalar;
72 using execution_space = typename DeviceType::execution_space;
73
74 using reference_type = typename ScalarView<DataScalar,DeviceType>::reference_type;
75 using const_reference_type = typename ScalarView<const DataScalar,DeviceType>::reference_type;
76 private:
77 ordinal_type dataRank_;
78 Kokkos::View<DataScalar*, DeviceType> data1_; // the rank 1 data that is explicitly stored
79 Kokkos::View<DataScalar**, DeviceType> data2_; // the rank 2 data that is explicitly stored
80 Kokkos::View<DataScalar***, DeviceType> data3_; // the rank 3 data that is explicitly stored
81 Kokkos::View<DataScalar****, DeviceType> data4_; // the rank 4 data that is explicitly stored
82 Kokkos::View<DataScalar*****, DeviceType> data5_; // the rank 5 data that is explicitly stored
83 Kokkos::View<DataScalar******, DeviceType> data6_; // the rank 6 data that is explicitly stored
84 Kokkos::View<DataScalar*******, DeviceType> data7_; // the rank 7 data that is explicitly stored
85 Kokkos::Array<int,7> extents_; // logical extents in each dimension
86 Kokkos::Array<DataVariationType,7> variationType_; // for each dimension, whether the data varies in that dimension
87 Kokkos::Array<int,7> variationModulus_; // for each dimension, a value by which indices should be modulused (only used when variationType_ is MODULAR)
88 int blockPlusDiagonalLastNonDiagonal_ = -1; // last row/column that is part of the non-diagonal part of the matrix indicated by BLOCK_PLUS_DIAGONAL (if any dimensions are thus marked)
89
90 bool hasNontrivialModulusUNUSED_; // this is a little nutty, but having this UNUSED member variable improves performance, probably by shifting the alignment of underlyingMatchesLogical_. This is true with nvcc; it may also be true with Apple clang
91 bool underlyingMatchesLogical_; // if true, this Data object has the same rank and extent as the underlying view
92 Kokkos::Array<ordinal_type,7> activeDims_;
93 int numActiveDims_; // how many of the 7 entries are actually filled in
94
95 ordinal_type rank_;
96
97 // we use (const_)reference_type as the return for operator() for performance reasons, especially significant when using Sacado types
98 using return_type = const_reference_type;
99
100 ScalarView<DataScalar,DeviceType> zeroView_; // one-entry (zero); used to allow getEntry() to return 0 for off-diagonal entries in BLOCK_PLUS_DIAGONAL
101
103 KOKKOS_INLINE_FUNCTION
104 static int blockPlusDiagonalNumNondiagonalEntries(const int &lastNondiagonal)
105 {
106 return (lastNondiagonal + 1) * (lastNondiagonal + 1);
107 }
108
110 KOKKOS_INLINE_FUNCTION
111 static int blockPlusDiagonalBlockEntryIndex(const int &lastNondiagonal, const int &numNondiagonalEntries, const int &i, const int &j)
112 {
113 return i * (lastNondiagonal + 1) + j;
114 }
115
117 KOKKOS_INLINE_FUNCTION
118 static int blockPlusDiagonalDiagonalEntryIndex(const int &lastNondiagonal, const int &numNondiagonalEntries, const int &i)
119 {
120 return i - (lastNondiagonal + 1) + numNondiagonalEntries;
121 }
122
124 KOKKOS_INLINE_FUNCTION
125 int getUnderlyingViewExtent(const int &dim) const
126 {
127 switch (dataRank_)
128 {
129 case 1: return data1_.extent_int(dim);
130 case 2: return data2_.extent_int(dim);
131 case 3: return data3_.extent_int(dim);
132 case 4: return data4_.extent_int(dim);
133 case 5: return data5_.extent_int(dim);
134 case 6: return data6_.extent_int(dim);
135 case 7: return data7_.extent_int(dim);
136 default: return -1;
137 }
138 }
139
142 {
143 zeroView_ = ZeroView<DataScalar,DeviceType>::zeroView(); // one-entry (zero); used to allow getEntry() to return 0 for off-diagonal entries in BLOCK_PLUS_DIAGONAL
144 // check that rank is compatible with the claimed extents:
145 for (int d=rank_; d<7; d++)
146 {
147 INTREPID2_TEST_FOR_EXCEPTION(extents_[d] > 1, std::invalid_argument, "Nominal extents may not be > 1 in dimensions beyond the rank of the container");
148 }
149
150 numActiveDims_ = 0;
151 int blockPlusDiagonalCount = 0;
152 underlyingMatchesLogical_ = true;
153 for (ordinal_type i=0; i<7; i++)
154 {
155 if (variationType_[i] == GENERAL)
156 {
157 if (extents_[i] != 0)
158 {
159 variationModulus_[i] = extents_[i];
160 }
161 else
162 {
163 variationModulus_[i] = 1;
164 }
165 activeDims_[numActiveDims_] = i;
166 numActiveDims_++;
167 }
168 else if (variationType_[i] == MODULAR)
169 {
170 underlyingMatchesLogical_ = false;
171 if (extents_[i] != getUnderlyingViewExtent(numActiveDims_))
172 {
173 const int dataExtent = getUnderlyingViewExtent(numActiveDims_);
174 const int logicalExtent = extents_[i];
175 const int modulus = dataExtent;
176
177 INTREPID2_TEST_FOR_EXCEPTION( dataExtent * (logicalExtent / dataExtent) != logicalExtent, std::invalid_argument, "data extent must evenly divide logical extent");
178
179 variationModulus_[i] = modulus;
180 }
181 else
182 {
183 variationModulus_[i] = extents_[i];
184 }
185 activeDims_[numActiveDims_] = i;
186 numActiveDims_++;
187 }
188 else if (variationType_[i] == BLOCK_PLUS_DIAGONAL)
189 {
190 underlyingMatchesLogical_ = false;
191 blockPlusDiagonalCount++;
192 if (blockPlusDiagonalCount == 1) // first dimension thus marked --> active
193 {
194
195#ifdef HAVE_INTREPID2_DEBUG
196 const int numNondiagonalEntries = blockPlusDiagonalNumNondiagonalEntries(blockPlusDiagonalLastNonDiagonal_);
197 const int dataExtent = getUnderlyingViewExtent(numActiveDims_); // flat storage of all matrix entries
198 const int logicalExtent = extents_[i];
199 const int numDiagonalEntries = logicalExtent - (blockPlusDiagonalLastNonDiagonal_ + 1);
200 const int expectedDataExtent = numNondiagonalEntries + numDiagonalEntries;
201 INTREPID2_TEST_FOR_EXCEPTION(dataExtent != expectedDataExtent, std::invalid_argument, ("BLOCK_PLUS_DIAGONAL data extent of " + std::to_string(dataExtent) + " does not match expected based on blockPlusDiagonalLastNonDiagonal setting of " + std::to_string(blockPlusDiagonalLastNonDiagonal_)).c_str());
202#endif
203
204 activeDims_[numActiveDims_] = i;
205 numActiveDims_++;
206 }
207 variationModulus_[i] = getUnderlyingViewExtent(numActiveDims_);
208 INTREPID2_TEST_FOR_EXCEPTION(variationType_[i+1] != BLOCK_PLUS_DIAGONAL, std::invalid_argument, "BLOCK_PLUS_DIAGONAL ranks must be contiguous");
209 i++; // skip over the next BLOCK_PLUS_DIAGONAL
210 variationModulus_[i] = 1; // trivial modulus (should not ever be used)
211 INTREPID2_TEST_FOR_EXCEPTION(blockPlusDiagonalCount > 1, std::invalid_argument, "BLOCK_PLUS_DIAGONAL can only apply to two ranks");
212 }
213 else // CONSTANT
214 {
215 if (i < rank_)
216 {
217 underlyingMatchesLogical_ = false;
218 }
219 variationModulus_[i] = 1; // trivial modulus
220 }
221 }
222
223 if (rank_ != dataRank_)
224 {
225 underlyingMatchesLogical_ = false;
226 }
227
228 for (int d=numActiveDims_; d<7; d++)
229 {
230 // for *inactive* dims, the activeDims_ map just is the identity
231 // (this allows getEntry() to work even when the logical rank of the Data object is lower than that of the underlying View. This can happen for gradients in 1D.)
232 activeDims_[d] = d;
233 }
234 for (int d=0; d<7; d++)
235 {
236 INTREPID2_TEST_FOR_EXCEPTION(variationModulus_[d] == 0, std::logic_error, "variationModulus should not ever be 0");
237 }
238 }
239
240 public:
242 template<class UnaryOperator>
243 void applyOperator(UnaryOperator unaryOperator)
244 {
245 using ExecutionSpace = typename DeviceType::execution_space;
246
247 switch (dataRank_)
248 {
249 case 1:
250 {
251 const int dataRank = 1;
252 auto view = getUnderlyingView<dataRank>();
253
254 const int dataExtent = this->getDataExtent(0);
255 Kokkos::RangePolicy<ExecutionSpace> policy(ExecutionSpace(),0,dataExtent);
256 Kokkos::parallel_for("apply operator in-place", policy,
257 KOKKOS_LAMBDA (const int &i0) {
258 view(i0) = unaryOperator(view(i0));
259 });
260
261 }
262 break;
263 case 2:
264 {
265 const int dataRank = 2;
266 auto policy = dataExtentRangePolicy<dataRank>();
267 auto view = getUnderlyingView<dataRank>();
268
269 Kokkos::parallel_for("apply operator in-place", policy,
270 KOKKOS_LAMBDA (const int &i0, const int &i1) {
271 view(i0,i1) = unaryOperator(view(i0,i1));
272 });
273 }
274 break;
275 case 3:
276 {
277 const int dataRank = 3;
278 auto policy = dataExtentRangePolicy<dataRank>();
279 auto view = getUnderlyingView<dataRank>();
280
281 Kokkos::parallel_for("apply operator in-place", policy,
282 KOKKOS_LAMBDA (const int &i0, const int &i1, const int &i2) {
283 view(i0,i1,i2) = unaryOperator(view(i0,i1,i2));
284 });
285 }
286 break;
287 case 4:
288 {
289 const int dataRank = 4;
290 auto policy = dataExtentRangePolicy<dataRank>();
291 auto view = getUnderlyingView<dataRank>();
292
293 Kokkos::parallel_for("apply operator in-place", policy,
294 KOKKOS_LAMBDA (const int &i0, const int &i1, const int &i2, const int &i3) {
295 view(i0,i1,i2,i3) = unaryOperator(view(i0,i1,i2,i3));
296 });
297 }
298 break;
299 case 5:
300 {
301 const int dataRank = 5;
302 auto policy = dataExtentRangePolicy<dataRank>();
303 auto view = getUnderlyingView<dataRank>();
304
305 Kokkos::parallel_for("apply operator in-place", policy,
306 KOKKOS_LAMBDA (const int &i0, const int &i1, const int &i2, const int &i3, const int &i4) {
307 view(i0,i1,i2,i3,i4) = unaryOperator(view(i0,i1,i2,i3,i4));
308 });
309 }
310 break;
311 case 6:
312 {
313 const int dataRank = 6;
314 auto policy = dataExtentRangePolicy<dataRank>();
315 auto view = getUnderlyingView<dataRank>();
316
317 Kokkos::parallel_for("apply operator in-place", policy,
318 KOKKOS_LAMBDA (const int &i0, const int &i1, const int &i2, const int &i3, const int &i4, const int &i5) {
319 view(i0,i1,i2,i3,i4,i5) = unaryOperator(view(i0,i1,i2,i3,i4,i5));
320 });
321 }
322 break;
323 case 7:
324 {
325 const int dataRank = 7;
326 auto policy6 = dataExtentRangePolicy<6>();
327 auto view = getUnderlyingView<dataRank>();
328
329 const int dim_i6 = view.extent_int(6);
330
331 Kokkos::parallel_for("apply operator in-place", policy6,
332 KOKKOS_LAMBDA (const int &i0, const int &i1, const int &i2, const int &i3, const int &i4, const int &i5) {
333 for (int i6=0; i6<dim_i6; i6++)
334 {
335 view(i0,i1,i2,i3,i4,i5,i6) = unaryOperator(view(i0,i1,i2,i3,i4,i5,i6));
336 }
337 });
338 }
339 break;
340 default:
341 INTREPID2_TEST_FOR_EXCEPTION(true,std::invalid_argument,"Unsupported data rank");
342 }
343 }
344
346 template<class ...IntArgs>
347 KOKKOS_INLINE_FUNCTION
348 reference_type getWritableEntryWithPassThroughOption(const bool &passThroughBlockDiagonalArgs, const IntArgs... intArgs) const
349 {
350 #ifdef INTREPID2_HAVE_DEBUG
351 INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE(numArgs != rank_, std::invalid_argument, "getWritableEntry() should have the same number of arguments as the logical rank.");
352 #endif
353 constexpr int numArgs = sizeof...(intArgs);
354 if (underlyingMatchesLogical_)
355 {
356 // in this case, we require that numArgs == dataRank_
357 return getUnderlyingView<numArgs>()(intArgs...);
358 }
359
360 // extract the type of the first argument; use that for the arrays below
361 using int_type = std::tuple_element_t<0, std::tuple<IntArgs...>>;
362
363 const Kokkos::Array<int_type, numArgs+1> args {intArgs...,0}; // we pad with one extra entry (0) to avoid gcc compiler warnings about references beyond the bounds of the array (the [d+1]'s below)
364 Kokkos::Array<int_type, 7> refEntry;
365 for (int d=0; d<numArgs; d++)
366 {
367 switch (variationType_[d])
368 {
369 case CONSTANT: refEntry[d] = 0; break;
370 case GENERAL: refEntry[d] = args[d]; break;
371 case MODULAR: refEntry[d] = args[d] % variationModulus_[d]; break;
373 {
374 if (passThroughBlockDiagonalArgs)
375 {
376 refEntry[d] = args[d];
377 refEntry[d+1] = args[d+1]; // this had better be == 0
378 INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE(args[d+1] != 0, std::invalid_argument, "getWritableEntry() called with passThroughBlockDiagonalArgs = true, but nonzero second matrix argument.");
379 }
380 else
381 {
382 const int numNondiagonalEntries = blockPlusDiagonalNumNondiagonalEntries(blockPlusDiagonalLastNonDiagonal_);
383
384 const int_type &i = args[d];
385 if (d+1 >= numArgs)
386 {
387 INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE(true, std::invalid_argument, "BLOCK_PLUS_DIAGONAL must be present for two dimensions; here, encountered only one");
388 }
389 else
390 {
391 const int_type &j = args[d+1];
392
393 if ((i > static_cast<int_type>(blockPlusDiagonalLastNonDiagonal_)) || (j > static_cast<int_type>(blockPlusDiagonalLastNonDiagonal_)))
394 {
395 if (i != j)
396 {
397 // off diagonal: zero
398 return zeroView_(0); // NOTE: this branches in an argument-dependent way; this is not great for CUDA performance. When using BLOCK_PLUS_DIAGONAL, should generally avoid calls to this getEntry() method. (Use methods that directly take advantage of the data packing instead.)
399 }
400 else
401 {
402 refEntry[d] = blockPlusDiagonalDiagonalEntryIndex(blockPlusDiagonalLastNonDiagonal_, numNondiagonalEntries, i);
403 }
404 }
405 else
406 {
407 refEntry[d] = blockPlusDiagonalBlockEntryIndex(blockPlusDiagonalLastNonDiagonal_, numNondiagonalEntries, i, j);
408 }
409
410 // skip next d (this is required also to be BLOCK_PLUS_DIAGONAL, and we've consumed its arg as j above)
411 refEntry[d+1] = 0;
412 }
413 }
414 d++;
415 }
416 }
417 }
418 // refEntry should be zero-filled beyond numArgs, for cases when rank_ < dataRank_ (this only is allowed if the extra dimensions each has extent 1).
419 for (int d=numArgs; d<7; d++)
420 {
421 refEntry[d] = 0;
422 }
423
424 if (dataRank_ == 1)
425 {
426 return data1_(refEntry[activeDims_[0]]);
427 }
428 else if (dataRank_ == 2)
429 {
430 return data2_(refEntry[activeDims_[0]],refEntry[activeDims_[1]]);
431 }
432 else if (dataRank_ == 3)
433 {
434 return data3_(refEntry[activeDims_[0]],refEntry[activeDims_[1]],refEntry[activeDims_[2]]);
435 }
436 else if (dataRank_ == 4)
437 {
438 return data4_(refEntry[activeDims_[0]],refEntry[activeDims_[1]],refEntry[activeDims_[2]],refEntry[activeDims_[3]]);
439 }
440 else if (dataRank_ == 5)
441 {
442 return data5_(refEntry[activeDims_[0]],refEntry[activeDims_[1]],refEntry[activeDims_[2]],refEntry[activeDims_[3]],
443 refEntry[activeDims_[4]]);
444 }
445 else if (dataRank_ == 6)
446 {
447 return data6_(refEntry[activeDims_[0]],refEntry[activeDims_[1]],refEntry[activeDims_[2]],refEntry[activeDims_[3]],
448 refEntry[activeDims_[4]],refEntry[activeDims_[5]]);
449 }
450 else // dataRank_ == 7
451 {
452 return data7_(refEntry[activeDims_[0]],refEntry[activeDims_[1]],refEntry[activeDims_[2]],refEntry[activeDims_[3]],
453 refEntry[activeDims_[4]],refEntry[activeDims_[5]],refEntry[activeDims_[6]]);
454 }
455
456 }
457
459 template<class ...IntArgs>
460 KOKKOS_INLINE_FUNCTION
461 reference_type getWritableEntry(const IntArgs... intArgs) const
462 {
463 return getWritableEntryWithPassThroughOption(false, intArgs...);
464 }
465 public:
467 template<class ToContainer, class FromContainer>
468 static void copyContainer(ToContainer to, FromContainer from)
469 {
470// std::cout << "Entered copyContainer().\n";
471 auto policy = Kokkos::MDRangePolicy<execution_space,Kokkos::Rank<6>>({0,0,0,0,0,0},{from.extent_int(0),from.extent_int(1),from.extent_int(2), from.extent_int(3), from.extent_int(4), from.extent_int(5)});
472
473 Kokkos::parallel_for("copyContainer", policy,
474 KOKKOS_LAMBDA (const int &i0, const int &i1, const int &i2, const int &i3, const int &i4, const int &i5) {
475 for (int i6=0; i6<from.extent_int(6); i6++)
476 {
477 to.access(i0,i1,i2,i3,i4,i5,i6) = from.access(i0,i1,i2,i3,i4,i5,i6);
478 }
479 });
480 }
481
483 void allocateAndCopyFromDynRankView(ScalarView<DataScalar,DeviceType> data)
484 {
485// std::cout << "Entered allocateAndCopyFromDynRankView().\n";
486 switch (dataRank_)
487 {
488 case 1: data1_ = Kokkos::View<DataScalar*, DeviceType>("Intrepid2 Data", data.extent_int(0)); break;
489 case 2: data2_ = Kokkos::View<DataScalar**, DeviceType>("Intrepid2 Data", data.extent_int(0), data.extent_int(1)); break;
490 case 3: data3_ = Kokkos::View<DataScalar***, DeviceType>("Intrepid2 Data", data.extent_int(0), data.extent_int(1), data.extent_int(2)); break;
491 case 4: data4_ = Kokkos::View<DataScalar****, DeviceType>("Intrepid2 Data", data.extent_int(0), data.extent_int(1), data.extent_int(2), data.extent_int(3)); break;
492 case 5: data5_ = Kokkos::View<DataScalar*****, DeviceType>("Intrepid2 Data", data.extent_int(0), data.extent_int(1), data.extent_int(2), data.extent_int(3), data.extent_int(4)); break;
493 case 6: data6_ = Kokkos::View<DataScalar******, DeviceType>("Intrepid2 Data", data.extent_int(0), data.extent_int(1), data.extent_int(2), data.extent_int(3), data.extent_int(4), data.extent_int(5)); break;
494 case 7: data7_ = Kokkos::View<DataScalar*******, DeviceType>("Intrepid2 Data", data.extent_int(0), data.extent_int(1), data.extent_int(2), data.extent_int(3), data.extent_int(4), data.extent_int(5), data.extent_int(6)); break;
495 default: INTREPID2_TEST_FOR_EXCEPTION(true, std::invalid_argument, "Invalid data rank");
496 }
497
498 switch (dataRank_)
499 {
500 case 1: copyContainer(data1_,data); break;
501 case 2: copyContainer(data2_,data); break;
502 case 3: copyContainer(data3_,data); break;
503 case 4: copyContainer(data4_,data); break;
504 case 5: copyContainer(data5_,data); break;
505 case 6: copyContainer(data6_,data); break;
506 case 7: copyContainer(data7_,data); break;
507 default: INTREPID2_TEST_FOR_EXCEPTION(true, std::invalid_argument, "Invalid data rank");
508 }
509 }
510
512 Data(std::vector<DimensionInfo> dimInfoVector)
513 :
514 // initialize member variables as if default constructor; if dimInfoVector is empty, we want default constructor behavior.
515 dataRank_(0), extents_({0,0,0,0,0,0,0}), variationType_({CONSTANT,CONSTANT,CONSTANT,CONSTANT,CONSTANT,CONSTANT,CONSTANT}), blockPlusDiagonalLastNonDiagonal_(-1), rank_(dimInfoVector.size())
516 {
517 // If dimInfoVector is empty, the member initialization above is correct; otherwise, we set as below.
518 // Either way, once members are initialized, we must call setActiveDims().
519 if (dimInfoVector.size() != 0)
520 {
521 std::vector<int> dataExtents;
522
523 bool blockPlusDiagonalEncountered = false;
524 for (int d=0; d<rank_; d++)
525 {
526 const DimensionInfo & dimInfo = dimInfoVector[d];
527 extents_[d] = dimInfo.logicalExtent;
528 variationType_[d] = dimInfo.variationType;
529 const bool isBlockPlusDiagonal = (variationType_[d] == BLOCK_PLUS_DIAGONAL);
530 const bool isSecondBlockPlusDiagonal = isBlockPlusDiagonal && blockPlusDiagonalEncountered;
531 if (isBlockPlusDiagonal)
532 {
533 blockPlusDiagonalEncountered = true;
534 blockPlusDiagonalLastNonDiagonal_ = dimInfo.blockPlusDiagonalLastNonDiagonal;
535 }
536 if ((variationType_[d] != CONSTANT) && (!isSecondBlockPlusDiagonal))
537 {
538 dataExtents.push_back(dimInfo.dataExtent);
539 }
540 }
541 if (dataExtents.size() == 0)
542 {
543 // constant data
544 dataExtents.push_back(1);
545 }
546 dataRank_ = dataExtents.size();
547 switch (dataRank_)
548 {
549 case 1: data1_ = Kokkos::View<DataScalar*, DeviceType>("Intrepid2 Data", dataExtents[0]); break;
550 case 2: data2_ = Kokkos::View<DataScalar**, DeviceType>("Intrepid2 Data", dataExtents[0], dataExtents[1]); break;
551 case 3: data3_ = Kokkos::View<DataScalar***, DeviceType>("Intrepid2 Data", dataExtents[0], dataExtents[1], dataExtents[2]); break;
552 case 4: data4_ = Kokkos::View<DataScalar****, DeviceType>("Intrepid2 Data", dataExtents[0], dataExtents[1], dataExtents[2], dataExtents[3]); break;
553 case 5: data5_ = Kokkos::View<DataScalar*****, DeviceType>("Intrepid2 Data", dataExtents[0], dataExtents[1], dataExtents[2], dataExtents[3], dataExtents[4]); break;
554 case 6: data6_ = Kokkos::View<DataScalar******, DeviceType>("Intrepid2 Data", dataExtents[0], dataExtents[1], dataExtents[2], dataExtents[3], dataExtents[4], dataExtents[5]); break;
555 case 7: data7_ = Kokkos::View<DataScalar*******, DeviceType>("Intrepid2 Data", dataExtents[0], dataExtents[1], dataExtents[2], dataExtents[3], dataExtents[4], dataExtents[5], dataExtents[6]); break;
556 default: INTREPID2_TEST_FOR_EXCEPTION(true, std::invalid_argument, "Invalid data rank");
557 }
558 }
560 }
561
563 Data(const ScalarView<DataScalar,DeviceType> &data, int rank, Kokkos::Array<int,7> extents, Kokkos::Array<DataVariationType,7> variationType, const int blockPlusDiagonalLastNonDiagonal = -1)
564 :
565 dataRank_(data.rank()), extents_(extents), variationType_(variationType), blockPlusDiagonalLastNonDiagonal_(blockPlusDiagonalLastNonDiagonal), rank_(rank)
566 {
569 }
570
572 template<typename OtherDeviceType, class = typename std::enable_if< std::is_same<typename DeviceType::memory_space, typename OtherDeviceType::memory_space>::value>::type,
573 class = typename std::enable_if<!std::is_same<DeviceType,OtherDeviceType>::value>::type>
574 Data(const Data<DataScalar,OtherDeviceType> &data)
575 :
576 dataRank_(data.getUnderlyingViewRank()), extents_(data.getExtents()), variationType_(data.getVariationTypes()), blockPlusDiagonalLastNonDiagonal_(data.blockPlusDiagonalLastNonDiagonal()), rank_(data.rank())
577 {
578// std::cout << "Entered copy-like Data constructor.\n";
579 if (dataRank_ != 0) // dataRank_ == 0 indicates an invalid Data object (a placeholder, can indicate zero value)
580 {
581 const auto view = data.getUnderlyingView();
582 switch (dataRank_)
583 {
584 case 1: data1_ = data.getUnderlyingView1(); break;
585 case 2: data2_ = data.getUnderlyingView2(); break;
586 case 3: data3_ = data.getUnderlyingView3(); break;
587 case 4: data4_ = data.getUnderlyingView4(); break;
588 case 5: data5_ = data.getUnderlyingView5(); break;
589 case 6: data6_ = data.getUnderlyingView6(); break;
590 case 7: data7_ = data.getUnderlyingView7(); break;
591 default: INTREPID2_TEST_FOR_EXCEPTION(true, std::invalid_argument, "Invalid data rank");
592 }
593 }
595 }
596
598 template<typename OtherDeviceType, class = typename std::enable_if<!std::is_same<typename DeviceType::memory_space, typename OtherDeviceType::memory_space>::value>::type>
600 :
601 dataRank_(data.getUnderlyingViewRank()), extents_(data.getExtents()), variationType_(data.getVariationTypes()), blockPlusDiagonalLastNonDiagonal_(data.blockPlusDiagonalLastNonDiagonal()), rank_(data.rank())
602 {
603// std::cout << "Entered copy-like Data constructor.\n";
604 if (dataRank_ != 0) // dataRank_ == 0 indicates an invalid Data object (a placeholder, can indicate zero value)
605 {
606 const auto view = data.getUnderlyingView();
607 switch (dataRank_)
608 {
609 case 1: data1_ = Kokkos::View<DataScalar*, DeviceType>("Intrepid2 Data", view.extent_int(0)); break;
610 case 2: data2_ = Kokkos::View<DataScalar**, DeviceType>("Intrepid2 Data", view.extent_int(0), view.extent_int(1)); break;
611 case 3: data3_ = Kokkos::View<DataScalar***, DeviceType>("Intrepid2 Data", view.extent_int(0), view.extent_int(1), view.extent_int(2)); break;
612 case 4: data4_ = Kokkos::View<DataScalar****, DeviceType>("Intrepid2 Data", view.extent_int(0), view.extent_int(1), view.extent_int(2), view.extent_int(3)); break;
613 case 5: data5_ = Kokkos::View<DataScalar*****, DeviceType>("Intrepid2 Data", view.extent_int(0), view.extent_int(1), view.extent_int(2), view.extent_int(3), view.extent_int(4)); break;
614 case 6: data6_ = Kokkos::View<DataScalar******, DeviceType>("Intrepid2 Data", view.extent_int(0), view.extent_int(1), view.extent_int(2), view.extent_int(3), view.extent_int(4), view.extent_int(5)); break;
615 case 7: data7_ = Kokkos::View<DataScalar*******, DeviceType>("Intrepid2 Data", view.extent_int(0), view.extent_int(1), view.extent_int(2), view.extent_int(3), view.extent_int(4), view.extent_int(5), view.extent_int(6)); break;
616 default: INTREPID2_TEST_FOR_EXCEPTION(true, std::invalid_argument, "Invalid data rank");
617 }
618
619 // copy
620 // (Note: Kokkos::deep_copy() will not generally work if the layouts are different; that's why we do a manual copy here once we have the data on the host):
621 // first, mirror and copy dataView; then copy to the appropriate data_ member
622 using MemorySpace = typename DeviceType::memory_space;
623 switch (dataRank_)
624 {
625 case 1: {auto dataViewMirror = Kokkos::create_mirror_view_and_copy(MemorySpace(), data.getUnderlyingView1()); copyContainer(data1_, dataViewMirror);} break;
626 case 2: {auto dataViewMirror = Kokkos::create_mirror_view_and_copy(MemorySpace(), data.getUnderlyingView2()); copyContainer(data2_, dataViewMirror);} break;
627 case 3: {auto dataViewMirror = Kokkos::create_mirror_view_and_copy(MemorySpace(), data.getUnderlyingView3()); copyContainer(data3_, dataViewMirror);} break;
628 case 4: {auto dataViewMirror = Kokkos::create_mirror_view_and_copy(MemorySpace(), data.getUnderlyingView4()); copyContainer(data4_, dataViewMirror);} break;
629 case 5: {auto dataViewMirror = Kokkos::create_mirror_view_and_copy(MemorySpace(), data.getUnderlyingView5()); copyContainer(data5_, dataViewMirror);} break;
630 case 6: {auto dataViewMirror = Kokkos::create_mirror_view_and_copy(MemorySpace(), data.getUnderlyingView6()); copyContainer(data6_, dataViewMirror);} break;
631 case 7: {auto dataViewMirror = Kokkos::create_mirror_view_and_copy(MemorySpace(), data.getUnderlyingView7()); copyContainer(data7_, dataViewMirror);} break;
632 default: INTREPID2_TEST_FOR_EXCEPTION(true, std::invalid_argument, "Invalid data rank");
633 }
634 }
636 }
637
639// Data(const Data<DataScalar,ExecSpaceType> &data)
640// :
641// dataRank_(data.getUnderlyingViewRank()), extents_(data.getExtents()), variationType_(data.getVariationTypes()), blockPlusDiagonalLastNonDiagonal_(data.blockPlusDiagonalLastNonDiagonal()), rank_(data.rank())
642// {
643// std::cout << "Entered Data copy constructor.\n";
644// if (dataRank_ != 0) // dataRank_ == 0 indicates an invalid Data object (a placeholder, can indicate zero value)
645// {
646// const auto view = data.getUnderlyingView();
647// switch (dataRank_)
648// {
649// case 1: data1_ = Kokkos::View<DataScalar*, DeviceType>("Intrepid2 Data - explicit copy constructor(for debugging)", view.extent_int(0)); break;
650// case 2: data2_ = Kokkos::View<DataScalar**, DeviceType>("Intrepid2 Data - explicit copy constructor(for debugging)", view.extent_int(0), view.extent_int(1)); break;
651// case 3: data3_ = Kokkos::View<DataScalar***, DeviceType>("Intrepid2 Data - explicit copy constructor(for debugging)", view.extent_int(0), view.extent_int(1), view.extent_int(2)); break;
652// case 4: data4_ = Kokkos::View<DataScalar****, DeviceType>("Intrepid2 Data - explicit copy constructor(for debugging)", view.extent_int(0), view.extent_int(1), view.extent_int(2), view.extent_int(3)); break;
653// case 5: data5_ = Kokkos::View<DataScalar*****, DeviceType>("Intrepid2 Data - explicit copy constructor(for debugging)", view.extent_int(0), view.extent_int(1), view.extent_int(2), view.extent_int(3), view.extent_int(4)); break;
654// case 6: data6_ = Kokkos::View<DataScalar******, DeviceType>("Intrepid2 Data - explicit copy constructor(for debugging)", view.extent_int(0), view.extent_int(1), view.extent_int(2), view.extent_int(3), view.extent_int(4), view.extent_int(5)); break;
655// case 7: data7_ = Kokkos::View<DataScalar*******, DeviceType>("Intrepid2 Data - explicit copy constructor(for debugging)", view.extent_int(0), view.extent_int(1), view.extent_int(2), view.extent_int(3), view.extent_int(4), view.extent_int(5), view.extent_int(6)); break;
656// default: INTREPID2_TEST_FOR_EXCEPTION(true, std::invalid_argument, "Invalid data rank");
657// }
658//
659// // copy
660// // (Note: Kokkos::deep_copy() will not generally work if the layouts are different; that's why we do a manual copy here once we have the data on the host):
661// // first, mirror and copy dataView; then copy to the appropriate data_ member
662// using MemorySpace = typename DeviceType::memory_space;
663// switch (dataRank_)
664// {
665// case 1: {auto dataViewMirror = Kokkos::create_mirror_view_and_copy(MemorySpace(), data.getUnderlyingView1()); copyContainer(data1_, dataViewMirror);} break;
666// case 2: {auto dataViewMirror = Kokkos::create_mirror_view_and_copy(MemorySpace(), data.getUnderlyingView2()); copyContainer(data2_, dataViewMirror);} break;
667// case 3: {auto dataViewMirror = Kokkos::create_mirror_view_and_copy(MemorySpace(), data.getUnderlyingView3()); copyContainer(data3_, dataViewMirror);} break;
668// case 4: {auto dataViewMirror = Kokkos::create_mirror_view_and_copy(MemorySpace(), data.getUnderlyingView4()); copyContainer(data4_, dataViewMirror);} break;
669// case 5: {auto dataViewMirror = Kokkos::create_mirror_view_and_copy(MemorySpace(), data.getUnderlyingView5()); copyContainer(data5_, dataViewMirror);} break;
670// case 6: {auto dataViewMirror = Kokkos::create_mirror_view_and_copy(MemorySpace(), data.getUnderlyingView6()); copyContainer(data6_, dataViewMirror);} break;
671// case 7: {auto dataViewMirror = Kokkos::create_mirror_view_and_copy(MemorySpace(), data.getUnderlyingView7()); copyContainer(data7_, dataViewMirror);} break;
672// default: INTREPID2_TEST_FOR_EXCEPTION(true, std::invalid_argument, "Invalid data rank");
673// }
674// }
675//
676// setActiveDims();
677// }
678
680 Data(ScalarView<DataScalar,DeviceType> data)
681 :
682 Data(data,
683 data.rank(),
684 Kokkos::Array<int,7> {data.extent_int(0),data.extent_int(1),data.extent_int(2),data.extent_int(3),data.extent_int(4),data.extent_int(5),data.extent_int(6)},
685 Kokkos::Array<DataVariationType,7> {GENERAL,GENERAL,GENERAL,GENERAL,GENERAL,GENERAL,GENERAL}, -1)
686 {}
687
689 template<size_t rank, class ...DynRankViewProperties>
690 Data(const Kokkos::DynRankView<DataScalar,DeviceType, DynRankViewProperties...> &data, Kokkos::Array<int,rank> extents, Kokkos::Array<DataVariationType,rank> variationType, const int blockPlusDiagonalLastNonDiagonal = -1)
691 :
692 dataRank_(data.rank()), extents_({1,1,1,1,1,1,1}), variationType_({CONSTANT,CONSTANT,CONSTANT,CONSTANT,CONSTANT,CONSTANT,CONSTANT}), blockPlusDiagonalLastNonDiagonal_(blockPlusDiagonalLastNonDiagonal), rank_(rank)
693 {
694// std::cout << "Entered a DynRankView Data() constructor.\n";
696 for (unsigned d=0; d<rank; d++)
697 {
698 extents_[d] = extents[d];
699 variationType_[d] = variationType[d];
700 }
702 }
703
704 template<size_t rank, class ...ViewProperties>
705 Data(Kokkos::View<DataScalar*,DeviceType, ViewProperties...> data, Kokkos::Array<int,rank> extents, Kokkos::Array<DataVariationType,rank> variationType, const int blockPlusDiagonalLastNonDiagonal = -1)
706 :
707 dataRank_(data.rank), extents_({1,1,1,1,1,1,1}), variationType_({CONSTANT,CONSTANT,CONSTANT,CONSTANT,CONSTANT,CONSTANT,CONSTANT}), blockPlusDiagonalLastNonDiagonal_(blockPlusDiagonalLastNonDiagonal), rank_(rank)
708 {
709 data1_ = data;
710 for (unsigned d=0; d<rank; d++)
711 {
712 extents_[d] = extents[d];
713 variationType_[d] = variationType[d];
714 }
716 }
717
718 template<size_t rank, class ...ViewProperties>
719 Data(Kokkos::View<DataScalar**,DeviceType, ViewProperties...> data, Kokkos::Array<int,rank> extents, Kokkos::Array<DataVariationType,rank> variationType, const int blockPlusDiagonalLastNonDiagonal = -1)
720 :
721 dataRank_(data.rank), extents_({1,1,1,1,1,1,1}), variationType_({CONSTANT,CONSTANT,CONSTANT,CONSTANT,CONSTANT,CONSTANT,CONSTANT}), blockPlusDiagonalLastNonDiagonal_(blockPlusDiagonalLastNonDiagonal), rank_(rank)
722 {
723 data2_ = data;
724 for (unsigned d=0; d<rank; d++)
725 {
726 extents_[d] = extents[d];
727 variationType_[d] = variationType[d];
728 }
730 }
731
732 template<size_t rank, class ...ViewProperties>
733 Data(Kokkos::View<DataScalar***,DeviceType, ViewProperties...> data, Kokkos::Array<int,rank> extents, Kokkos::Array<DataVariationType,rank> variationType, const int blockPlusDiagonalLastNonDiagonal = -1)
734 :
735 dataRank_(data.rank), extents_({1,1,1,1,1,1,1}), variationType_({CONSTANT,CONSTANT,CONSTANT,CONSTANT,CONSTANT,CONSTANT,CONSTANT}), blockPlusDiagonalLastNonDiagonal_(blockPlusDiagonalLastNonDiagonal), rank_(rank)
736 {
737 data3_ = data;
738 for (unsigned d=0; d<rank; d++)
739 {
740 extents_[d] = extents[d];
741 variationType_[d] = variationType[d];
742 }
744 }
745
746 template<size_t rank, class ...ViewProperties>
747 Data(Kokkos::View<DataScalar****,DeviceType, ViewProperties...> data, Kokkos::Array<int,rank> extents, Kokkos::Array<DataVariationType,rank> variationType, const int blockPlusDiagonalLastNonDiagonal = -1)
748 :
749 dataRank_(data.rank), extents_({1,1,1,1,1,1,1}), variationType_({CONSTANT,CONSTANT,CONSTANT,CONSTANT,CONSTANT,CONSTANT,CONSTANT}), blockPlusDiagonalLastNonDiagonal_(blockPlusDiagonalLastNonDiagonal), rank_(rank)
750 {
751 data4_ = data;
752 for (unsigned d=0; d<rank; d++)
753 {
754 extents_[d] = extents[d];
755 variationType_[d] = variationType[d];
756 }
758 }
759
760 template<size_t rank, class ...ViewProperties>
761 Data(Kokkos::View<DataScalar*****,DeviceType, ViewProperties...> data, Kokkos::Array<int,rank> extents, Kokkos::Array<DataVariationType,rank> variationType, const int blockPlusDiagonalLastNonDiagonal = -1)
762 :
763 dataRank_(data.rank), extents_({1,1,1,1,1,1,1}), variationType_({CONSTANT,CONSTANT,CONSTANT,CONSTANT,CONSTANT,CONSTANT,CONSTANT}), blockPlusDiagonalLastNonDiagonal_(blockPlusDiagonalLastNonDiagonal), rank_(rank)
764 {
765 data5_ = data;
766 for (unsigned d=0; d<rank; d++)
767 {
768 extents_[d] = extents[d];
769 variationType_[d] = variationType[d];
770 }
772 }
773
774 template<size_t rank, class ...ViewProperties>
775 Data(Kokkos::View<DataScalar******,DeviceType, ViewProperties...> data, Kokkos::Array<int,rank> extents, Kokkos::Array<DataVariationType,rank> variationType, const int blockPlusDiagonalLastNonDiagonal = -1)
776 :
777 dataRank_(data.rank), extents_({1,1,1,1,1,1,1}), variationType_({CONSTANT,CONSTANT,CONSTANT,CONSTANT,CONSTANT,CONSTANT,CONSTANT}), blockPlusDiagonalLastNonDiagonal_(blockPlusDiagonalLastNonDiagonal), rank_(rank)
778 {
779 data6_ = data;
780 for (unsigned d=0; d<rank; d++)
781 {
782 extents_[d] = extents[d];
783 variationType_[d] = variationType[d];
784 }
786 }
787
788 template<size_t rank, class ...ViewProperties>
789 Data(Kokkos::View<DataScalar*******,DeviceType, ViewProperties...> data, Kokkos::Array<int,rank> extents, Kokkos::Array<DataVariationType,rank> variationType, const int blockPlusDiagonalLastNonDiagonal = -1)
790 :
791 dataRank_(data.rank), extents_({1,1,1,1,1,1,1}), variationType_({CONSTANT,CONSTANT,CONSTANT,CONSTANT,CONSTANT,CONSTANT,CONSTANT}), blockPlusDiagonalLastNonDiagonal_(blockPlusDiagonalLastNonDiagonal), rank_(rank)
792 {
793 data7_ = data;
794 for (unsigned d=0; d<rank; d++)
795 {
796 extents_[d] = extents[d];
797 variationType_[d] = variationType[d];
798 }
800 }
801
803 template<class ViewScalar, class ...ViewProperties>
804 Data(const unsigned rank, Kokkos::View<ViewScalar,DeviceType, ViewProperties...> data, Kokkos::Array<int,7> extents, Kokkos::Array<DataVariationType,7> variationType, const int blockPlusDiagonalLastNonDiagonal = -1)
805 :
806 dataRank_(data.rank), extents_({1,1,1,1,1,1,1}), variationType_({CONSTANT,CONSTANT,CONSTANT,CONSTANT,CONSTANT,CONSTANT,CONSTANT}), blockPlusDiagonalLastNonDiagonal_(blockPlusDiagonalLastNonDiagonal), rank_(rank)
807 {
808 setUnderlyingView<data.rank>(data);
809 for (unsigned d=0; d<rank; d++)
810 {
811 extents_[d] = extents[d];
812 variationType_[d] = variationType[d];
813 }
815 }
816
818 template<size_t rank>
819 Data(DataScalar constantValue, Kokkos::Array<int,rank> extents)
820 :
821 dataRank_(1), extents_({1,1,1,1,1,1,1}), variationType_({CONSTANT,CONSTANT,CONSTANT,CONSTANT,CONSTANT,CONSTANT,CONSTANT}), blockPlusDiagonalLastNonDiagonal_(-1), rank_(rank)
822 {
823 data1_ = Kokkos::View<DataScalar*,DeviceType>("Constant Data",1);
824 Kokkos::deep_copy(data1_, constantValue);
825 for (unsigned d=0; d<rank; d++)
826 {
827 extents_[d] = extents[d];
828 }
830 }
831
834 :
835 dataRank_(0), extents_({0,0,0,0,0,0,0}), variationType_({CONSTANT,CONSTANT,CONSTANT,CONSTANT,CONSTANT,CONSTANT,CONSTANT}), blockPlusDiagonalLastNonDiagonal_(-1), rank_(0)
836 {
838 }
839
841 KOKKOS_INLINE_FUNCTION
843 {
844 return blockPlusDiagonalLastNonDiagonal_;
845 }
846
848 KOKKOS_INLINE_FUNCTION
849 Kokkos::Array<int,7> getExtents() const
850 {
851 return extents_;
852 }
853
855 KOKKOS_INLINE_FUNCTION
856 DimensionInfo getDimensionInfo(const int &dim) const
857 {
858 DimensionInfo dimInfo;
859
860 dimInfo.logicalExtent = extent_int(dim);
861 dimInfo.variationType = variationType_[dim];
862 dimInfo.dataExtent = getDataExtent(dim);
863 dimInfo.variationModulus = variationModulus_[dim];
864
865 if (dimInfo.variationType == BLOCK_PLUS_DIAGONAL)
866 {
867 dimInfo.blockPlusDiagonalLastNonDiagonal = blockPlusDiagonalLastNonDiagonal_;
868 }
869 return dimInfo;
870 }
871
873 KOKKOS_INLINE_FUNCTION
874 DimensionInfo combinedDataDimensionInfo(const Data &otherData, const int &dim) const
875 {
876 const DimensionInfo myDimInfo = getDimensionInfo(dim);
877 const DimensionInfo otherDimInfo = otherData.getDimensionInfo(dim);
878
879 return combinedDimensionInfo(myDimInfo, otherDimInfo);
880 }
881
883 template<int rank>
884 KOKKOS_INLINE_FUNCTION
885 enable_if_t<rank==1, const Kokkos::View<typename RankExpander<DataScalar, rank>::value_type, DeviceType> &>
887 {
888 #ifdef HAVE_INTREPID2_DEBUG
889 INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE(dataRank_ != rank, std::invalid_argument, "getUnderlyingView() called for rank that does not match dataRank_");
890 #endif
891 return data1_;
892 }
893
895 template<int rank>
896 KOKKOS_INLINE_FUNCTION
897 enable_if_t<rank==2, const Kokkos::View<typename RankExpander<DataScalar, rank>::value_type, DeviceType> &>
899 {
900 #ifdef HAVE_INTREPID2_DEBUG
901 INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE(dataRank_ != rank, std::invalid_argument, "getUnderlyingView() called for rank that does not match dataRank_");
902 #endif
903 return data2_;
904 }
905
907 template<int rank>
908 KOKKOS_INLINE_FUNCTION
909 enable_if_t<rank==3, const Kokkos::View<typename RankExpander<DataScalar, rank>::value_type, DeviceType> &>
911 {
912 #ifdef HAVE_INTREPID2_DEBUG
913 INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE(dataRank_ != rank, std::invalid_argument, "getUnderlyingView() called for rank that does not match dataRank_");
914 #endif
915 return data3_;
916 }
917
919 template<int rank>
920 KOKKOS_INLINE_FUNCTION
921 enable_if_t<rank==4, const Kokkos::View<typename RankExpander<DataScalar, rank>::value_type, DeviceType> &>
923 {
924 #ifdef HAVE_INTREPID2_DEBUG
925 INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE(dataRank_ != rank, std::invalid_argument, "getUnderlyingView() called for rank that does not match dataRank_");
926 #endif
927 return data4_;
928 }
929
931 template<int rank>
932 KOKKOS_INLINE_FUNCTION
933 enable_if_t<rank==5, const Kokkos::View<typename RankExpander<DataScalar, rank>::value_type, DeviceType> &>
935 {
936 #ifdef HAVE_INTREPID2_DEBUG
937 INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE(dataRank_ != rank, std::invalid_argument, "getUnderlyingView() called for rank that does not match dataRank_");
938 #endif
939 return data5_;
940 }
941
943 template<int rank>
944 KOKKOS_INLINE_FUNCTION
945 enable_if_t<rank==6, const Kokkos::View<typename RankExpander<DataScalar, rank>::value_type, DeviceType> &>
947 {
948 #ifdef HAVE_INTREPID2_DEBUG
949 INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE(dataRank_ != rank, std::invalid_argument, "getUnderlyingView() called for rank that does not match dataRank_");
950 #endif
951 return data6_;
952 }
953
955 template<int rank>
956 KOKKOS_INLINE_FUNCTION
957 enable_if_t<rank==7, const Kokkos::View<typename RankExpander<DataScalar, rank>::value_type, DeviceType> &>
959 {
960 #ifdef HAVE_INTREPID2_DEBUG
961 INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE(dataRank_ != rank, std::invalid_argument, "getUnderlyingView() called for rank that does not match dataRank_");
962 #endif
963 return data7_;
964 }
965
967 KOKKOS_INLINE_FUNCTION
968 const Kokkos::View<DataScalar*, DeviceType> & getUnderlyingView1() const
969 {
970 return getUnderlyingView<1>();
971 }
972
974 KOKKOS_INLINE_FUNCTION
975 const Kokkos::View<DataScalar**, DeviceType> & getUnderlyingView2() const
976 {
977 return getUnderlyingView<2>();
978 }
979
981 KOKKOS_INLINE_FUNCTION
982 const Kokkos::View<DataScalar***, DeviceType> & getUnderlyingView3() const
983 {
984 return getUnderlyingView<3>();
985 }
986
988 KOKKOS_INLINE_FUNCTION
989 const Kokkos::View<DataScalar****, DeviceType> & getUnderlyingView4() const
990 {
991 return getUnderlyingView<4>();
992 }
993
995 KOKKOS_INLINE_FUNCTION
996 const Kokkos::View<DataScalar*****, DeviceType> & getUnderlyingView5() const
997 {
998 return getUnderlyingView<5>();
999 }
1000
1002 KOKKOS_INLINE_FUNCTION
1003 const Kokkos::View<DataScalar******, DeviceType> & getUnderlyingView6() const
1004 {
1005 return getUnderlyingView<6>();
1006 }
1007
1009 KOKKOS_INLINE_FUNCTION
1010 const Kokkos::View<DataScalar*******, DeviceType> & getUnderlyingView7() const
1011 {
1012 return getUnderlyingView<7>();
1013 }
1014
1016 KOKKOS_INLINE_FUNCTION
1017 void setUnderlyingView1(const Kokkos::View<DataScalar*, DeviceType> & view)
1018 {
1019 data1_ = view;
1020 }
1021
1023 KOKKOS_INLINE_FUNCTION
1024 void setUnderlyingView2(const Kokkos::View<DataScalar**, DeviceType> & view)
1025 {
1026 data2_ = view;
1027 }
1028
1030 KOKKOS_INLINE_FUNCTION
1031 void setUnderlyingView3(const Kokkos::View<DataScalar***, DeviceType> & view)
1032 {
1033 data3_ = view;
1034 }
1035
1037 KOKKOS_INLINE_FUNCTION
1038 void setUnderlyingView4(const Kokkos::View<DataScalar****, DeviceType> & view)
1039 {
1040 data4_ = view;
1041 }
1042
1044 KOKKOS_INLINE_FUNCTION
1045 void setUnderlyingView5(const Kokkos::View<DataScalar*****, DeviceType> & view)
1046 {
1047 data5_ = view;
1048 }
1049
1051 KOKKOS_INLINE_FUNCTION
1052 void setUnderlyingView6(const Kokkos::View<DataScalar******, DeviceType> & view)
1053 {
1054 data6_ = view;
1055 }
1056
1058 KOKKOS_INLINE_FUNCTION
1059 void setUnderlyingView7(const Kokkos::View<DataScalar*******, DeviceType> & view)
1060 {
1061 data7_ = view;
1062 }
1063
1064 template<int underlyingRank, class ViewScalar>
1065 KOKKOS_INLINE_FUNCTION
1066 void setUnderlyingView(const Kokkos::View<ViewScalar, DeviceType> & view)
1067 {
1068 if constexpr (underlyingRank == 1)
1069 {
1070 setUnderlyingView1(view);
1071 }
1072 else if constexpr (underlyingRank == 2)
1073 {
1074 setUnderlyingView2(view);
1075 }
1076 else if constexpr (underlyingRank == 3)
1077 {
1078 setUnderlyingView3(view);
1079 }
1080 else if constexpr (underlyingRank == 4)
1081 {
1082 setUnderlyingView4(view);
1083 }
1084 else if constexpr (underlyingRank == 5)
1085 {
1086 setUnderlyingView5(view);
1087 }
1088 else if constexpr (underlyingRank == 6)
1089 {
1090 setUnderlyingView6(view);
1091 }
1092 else if constexpr (underlyingRank == 7)
1093 {
1094 setUnderlyingView7(view);
1095 }
1096 else
1097 {
1098 INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE(true, std::invalid_argument, "implementation for specialization missing");
1099 }
1100 }
1101
1103 ScalarView<DataScalar,DeviceType> getUnderlyingView() const
1104 {
1105 switch (dataRank_)
1106 {
1107 case 1: return data1_;
1108 case 2: return data2_;
1109 case 3: return data3_;
1110 case 4: return data4_;
1111 case 5: return data5_;
1112 case 6: return data6_;
1113 case 7: return data7_;
1114 default: INTREPID2_TEST_FOR_EXCEPTION(true, std::invalid_argument, "Invalid data rank");
1115 }
1116 }
1117
1119 KOKKOS_INLINE_FUNCTION
1120 ordinal_type getUnderlyingViewRank() const
1121 {
1122 return dataRank_;
1123 }
1124
1126 KOKKOS_INLINE_FUNCTION
1127 ordinal_type getUnderlyingViewSize() const
1128 {
1129 ordinal_type size = 1;
1130 for (ordinal_type r=0; r<dataRank_; r++)
1131 {
1132 size *= getUnderlyingViewExtent(r);
1133 }
1134 return size;
1135 }
1136
1138 ScalarView<DataScalar,DeviceType> allocateDynRankViewMatchingUnderlying() const
1139 {
1140 switch (dataRank_)
1141 {
1142 case 1: return getMatchingViewWithLabel(data1_, "Intrepid2 Data", data1_.extent_int(0));
1143 case 2: return getMatchingViewWithLabel(data2_, "Intrepid2 Data", data2_.extent_int(0), data2_.extent_int(1));
1144 case 3: return getMatchingViewWithLabel(data3_, "Intrepid2 Data", data3_.extent_int(0), data3_.extent_int(1), data3_.extent_int(2));
1145 case 4: return getMatchingViewWithLabel(data4_, "Intrepid2 Data", data4_.extent_int(0), data4_.extent_int(1), data4_.extent_int(2), data4_.extent_int(3));
1146 case 5: return getMatchingViewWithLabel(data5_, "Intrepid2 Data", data5_.extent_int(0), data5_.extent_int(1), data5_.extent_int(2), data5_.extent_int(3), data5_.extent_int(4));
1147 case 6: return getMatchingViewWithLabel(data6_, "Intrepid2 Data", data6_.extent_int(0), data6_.extent_int(1), data6_.extent_int(2), data6_.extent_int(3), data6_.extent_int(4), data6_.extent_int(5));
1148 case 7: return getMatchingViewWithLabel(data7_, "Intrepid2 Data", data7_.extent_int(0), data7_.extent_int(1), data7_.extent_int(2), data7_.extent_int(3), data7_.extent_int(4), data7_.extent_int(5), data7_.extent_int(6));
1149 default: INTREPID2_TEST_FOR_EXCEPTION(true, std::invalid_argument, "Invalid data rank");
1150 }
1151 }
1152
1154 template<class ... DimArgs>
1155 ScalarView<DataScalar,DeviceType> allocateDynRankViewMatchingUnderlying(DimArgs... dims) const
1156 {
1157 switch (dataRank_)
1158 {
1159 case 1: return getMatchingViewWithLabel(data1_, "Intrepid2 Data", dims...);
1160 case 2: return getMatchingViewWithLabel(data2_, "Intrepid2 Data", dims...);
1161 case 3: return getMatchingViewWithLabel(data3_, "Intrepid2 Data", dims...);
1162 case 4: return getMatchingViewWithLabel(data4_, "Intrepid2 Data", dims...);
1163 case 5: return getMatchingViewWithLabel(data5_, "Intrepid2 Data", dims...);
1164 case 6: return getMatchingViewWithLabel(data6_, "Intrepid2 Data", dims...);
1165 case 7: return getMatchingViewWithLabel(data7_, "Intrepid2 Data", dims...);
1166 default: INTREPID2_TEST_FOR_EXCEPTION(true, std::invalid_argument, "Invalid data rank");
1167 }
1168 }
1169
1171 void clear() const
1172 {
1173 switch (dataRank_)
1174 {
1175 case 1: Kokkos::deep_copy(data1_, 0.0); break;
1176 case 2: Kokkos::deep_copy(data2_, 0.0); break;
1177 case 3: Kokkos::deep_copy(data3_, 0.0); break;
1178 case 4: Kokkos::deep_copy(data4_, 0.0); break;
1179 case 5: Kokkos::deep_copy(data5_, 0.0); break;
1180 case 6: Kokkos::deep_copy(data6_, 0.0); break;
1181 case 7: Kokkos::deep_copy(data7_, 0.0); break;
1182 default: INTREPID2_TEST_FOR_EXCEPTION(true, std::invalid_argument, "Invalid data rank");
1183 }
1184 }
1185
1187 void copyDataFromDynRankViewMatchingUnderlying(const ScalarView<DataScalar,DeviceType> &dynRankView) const
1188 {
1189// std::cout << "Entered copyDataFromDynRankViewMatchingUnderlying().\n";
1190 switch (dataRank_)
1191 {
1192 case 1: copyContainer(data1_,dynRankView); break;
1193 case 2: copyContainer(data2_,dynRankView); break;
1194 case 3: copyContainer(data3_,dynRankView); break;
1195 case 4: copyContainer(data4_,dynRankView); break;
1196 case 5: copyContainer(data5_,dynRankView); break;
1197 case 6: copyContainer(data6_,dynRankView); break;
1198 case 7: copyContainer(data7_,dynRankView); break;
1199 default: INTREPID2_TEST_FOR_EXCEPTION(true, std::invalid_argument, "Invalid data rank");
1200 }
1201 }
1202
1204 KOKKOS_INLINE_FUNCTION int getDataExtent(const ordinal_type &d) const
1205 {
1206 for (int i=0; i<numActiveDims_; i++)
1207 {
1208 if (activeDims_[i] == d)
1209 {
1210 return getUnderlyingViewExtent(i);
1211 }
1212 else if (activeDims_[i] > d)
1213 {
1214 return 1; // data does not vary in the specified dimension
1215 }
1216 }
1217 return 1; // data does not vary in the specified dimension
1218 }
1219
1231 KOKKOS_INLINE_FUNCTION
1232 int getVariationModulus(const int &d) const
1233 {
1234 return variationModulus_[d];
1235 }
1236
1238 KOKKOS_INLINE_FUNCTION
1239 const Kokkos::Array<DataVariationType,7> & getVariationTypes() const
1240 {
1241 return variationType_;
1242 }
1243
1245 template<class ...IntArgs>
1246 KOKKOS_INLINE_FUNCTION
1247 return_type getEntryWithPassThroughOption(const bool &passThroughBlockDiagonalArgs, const IntArgs&... intArgs) const
1248 {
1249 return getWritableEntryWithPassThroughOption(passThroughBlockDiagonalArgs, intArgs...);
1250 }
1251
1253 template<class ...IntArgs>
1254 KOKKOS_INLINE_FUNCTION
1255 return_type getEntry(const IntArgs&... intArgs) const
1256 {
1257 return getEntryWithPassThroughOption(false, intArgs...);
1258 }
1259
1260 template <bool...> struct bool_pack;
1261
1262 template <bool... v>
1263 using all_true = std::is_same<bool_pack<true, v...>, bool_pack<v..., true>>;
1264
1265 template <class ...IntArgs>
1266 using valid_args = all_true<std::is_integral<IntArgs>{}...>;
1267
1268 static_assert(valid_args<int,long,unsigned>::value, "valid args works");
1269
1271 template <class ...IntArgs>
1272 KOKKOS_INLINE_FUNCTION
1273#ifndef __INTEL_COMPILER
1274 // icc has a bug that prevents compilation with this enable_if_t
1275 // (possibly the same as https://community.intel.com/t5/Intel-C-Compiler/Intel-Compiler-bug-while-deducing-template-arguments-inside/m-p/1164358)
1276 // so with icc we'll just skip the argument type/count check
1277 enable_if_t<valid_args<IntArgs...>::value && (sizeof...(IntArgs) <= 7),return_type>
1278#else
1279 return_type
1280#endif
1281 operator()(const IntArgs&... intArgs) const {
1282 return getEntry(intArgs...);
1283 }
1284
1286 KOKKOS_INLINE_FUNCTION
1287 int extent_int(const int& r) const
1288 {
1289 return extents_[r];
1290 }
1291
1292 template <typename iType>
1293 KOKKOS_INLINE_FUNCTION constexpr
1294 typename std::enable_if<std::is_integral<iType>::value, size_t>::type
1295 extent(const iType& r) const {
1296 return extents_[r];
1297 }
1298
1300 KOKKOS_INLINE_FUNCTION bool isDiagonal() const
1301 {
1302 if (blockPlusDiagonalLastNonDiagonal_ >= 1) return false;
1303 int numBlockPlusDiagonalTypes = 0;
1304 for (unsigned r = 0; r<variationType_.size(); r++)
1305 {
1306 const auto &entryType = variationType_[r];
1307 if (entryType == BLOCK_PLUS_DIAGONAL) numBlockPlusDiagonalTypes++;
1308 }
1309 // 2 BLOCK_PLUS_DIAGONAL entries, combined with blockPlusDiagonalLastNonDiagonal being -1 or 0 indicates diagonal
1310 if (numBlockPlusDiagonalTypes == 2) return true;
1311 else if (numBlockPlusDiagonalTypes == 0) return false; // no BLOCK_PLUS_DIAGONAL --> not a diagonal matrix
1312 else INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE(true, std::invalid_argument, "Unexpected number of ranks marked as BLOCK_PLUS_DIAGONAL (should be 0 or 2)");
1313 return false; // statement should be unreachable; included because compilers don't necessarily recognize that fact...
1314 }
1315
1320 {
1321 return Data<DataScalar,DeviceType>(value, this->getExtents());
1322 }
1323
1330 {
1331 INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE(A.rank() != B.rank(), std::invalid_argument, "A and B must have the same logical shape");
1332 const int rank = A.rank();
1333 std::vector<DimensionInfo> dimInfo(rank);
1334 for (int d=0; d<rank; d++)
1335 {
1336 INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE(A.extent_int(d) != B.extent_int(d), std::invalid_argument, "A and B must have the same logical shape");
1337 dimInfo[d] = A.combinedDataDimensionInfo(B, d);
1338 }
1339 Data<DataScalar,DeviceType> result(dimInfo);
1340 return result;
1341 }
1342
1349 static Data<DataScalar,DeviceType> allocateMatMatResult( const bool transposeA, const Data<DataScalar,DeviceType> &A_MatData, const bool transposeB, const Data<DataScalar,DeviceType> &B_MatData )
1350 {
1351 // we treat last two logical dimensions of matData as the matrix; last dimension of vecData as the vector
1352 INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE(A_MatData.rank() != B_MatData.rank(), std::invalid_argument, "AmatData and BmatData have incompatible ranks");
1353
1354 const int D1_DIM = A_MatData.rank() - 2;
1355 const int D2_DIM = A_MatData.rank() - 1;
1356
1357 const int A_rows = A_MatData.extent_int(D1_DIM);
1358 const int A_cols = A_MatData.extent_int(D2_DIM);
1359 const int B_rows = B_MatData.extent_int(D1_DIM);
1360 const int B_cols = B_MatData.extent_int(D2_DIM);
1361
1362 const int leftRows = transposeA ? A_cols : A_rows;
1363 const int leftCols = transposeA ? A_rows : A_cols;
1364 const int rightRows = transposeB ? B_cols : B_rows;
1365 const int rightCols = transposeB ? B_rows : B_cols;
1366
1367 INTREPID2_TEST_FOR_EXCEPTION(leftCols != rightRows, std::invalid_argument, "incompatible matrix dimensions");
1368
1369 Kokkos::Array<int,7> resultExtents; // logical extents
1370 Kokkos::Array<DataVariationType,7> resultVariationTypes; // for each dimension, whether the data varies in that dimension
1371
1372 resultExtents[D1_DIM] = leftRows;
1373 resultExtents[D2_DIM] = rightCols;
1374 int resultBlockPlusDiagonalLastNonDiagonal = -1;
1375 if ( (A_MatData.getVariationTypes()[D1_DIM] == BLOCK_PLUS_DIAGONAL) && (B_MatData.getVariationTypes()[D1_DIM] == BLOCK_PLUS_DIAGONAL) )
1376 {
1377 // diagonal times diagonal is diagonal; the result will have the maximum of A and B's non-diagonal block size
1378 resultVariationTypes[D1_DIM] = BLOCK_PLUS_DIAGONAL;
1379 resultVariationTypes[D2_DIM] = BLOCK_PLUS_DIAGONAL;
1380 resultBlockPlusDiagonalLastNonDiagonal = std::max(A_MatData.blockPlusDiagonalLastNonDiagonal(), B_MatData.blockPlusDiagonalLastNonDiagonal());
1381 }
1382
1383 const int resultRank = A_MatData.rank();
1384
1385 auto A_VariationTypes = A_MatData.getVariationTypes();
1386 auto B_VariationTypes = B_MatData.getVariationTypes();
1387
1388 Kokkos::Array<int,7> resultActiveDims;
1389 Kokkos::Array<int,7> resultDataDims;
1390 int resultNumActiveDims = 0; // how many of the 7 entries are actually filled in
1391 // the following loop is over the dimensions *prior* to matrix dimensions
1392 for (int i=0; i<resultRank-2; i++)
1393 {
1394 INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE(A_MatData.extent_int(i) != B_MatData.extent_int(i), std::invalid_argument, "A and B extents must match in each non-matrix dimension");
1395
1396 resultExtents[i] = A_MatData.extent_int(i);
1397
1398 const DataVariationType &A_VariationType = A_VariationTypes[i];
1399 const DataVariationType &B_VariationType = B_VariationTypes[i];
1400
1401 // BLOCK_PLUS_DIAGONAL should only occur in matData, and only in the matrix (final) dimensions
1402 INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE(A_VariationType == BLOCK_PLUS_DIAGONAL, std::invalid_argument, "unsupported variationType");
1403 INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE(B_VariationType == BLOCK_PLUS_DIAGONAL, std::invalid_argument, "unsupported variationType");
1404
1405 int dataSize = 0;
1406 DataVariationType resultVariationType;
1407 if ((A_VariationType == GENERAL) || (B_VariationType == GENERAL))
1408 {
1409 resultVariationType = GENERAL;
1410 dataSize = resultExtents[i];
1411 }
1412 else if ((B_VariationType == CONSTANT) && (A_VariationType == CONSTANT))
1413 {
1414 resultVariationType = CONSTANT;
1415 dataSize = 1;
1416 }
1417 else if ((B_VariationType == MODULAR) && (A_VariationType == CONSTANT))
1418 {
1419 resultVariationType = MODULAR;
1420 dataSize = B_MatData.getVariationModulus(i);
1421 }
1422 else if ((B_VariationType == CONSTANT) && (A_VariationType == MODULAR))
1423 {
1424 resultVariationType = MODULAR;
1425 dataSize = A_MatData.getVariationModulus(i);
1426 }
1427 else
1428 {
1429 // both are modular. We allow this if they agree on the modulus
1430 auto A_Modulus = A_MatData.getVariationModulus(i);
1431 auto B_Modulus = B_MatData.getVariationModulus(i);
1432 INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE(A_Modulus != B_Modulus, std::invalid_argument, "If both matrices have variation type MODULAR, they must agree on the modulus");
1433 resultVariationType = MODULAR;
1434 dataSize = A_Modulus;
1435 }
1436 resultVariationTypes[i] = resultVariationType;
1437
1438 if (resultVariationType != CONSTANT)
1439 {
1440 resultActiveDims[resultNumActiveDims] = i;
1441 resultDataDims[resultNumActiveDims] = dataSize;
1442 resultNumActiveDims++;
1443 }
1444 }
1445
1446 // set things for final dimensions:
1447 resultExtents[D1_DIM] = leftRows;
1448 resultExtents[D2_DIM] = rightCols;
1449
1450 if ( (A_MatData.getVariationTypes()[D1_DIM] == BLOCK_PLUS_DIAGONAL) && (B_MatData.getVariationTypes()[D1_DIM] == BLOCK_PLUS_DIAGONAL) )
1451 {
1452 // diagonal times diagonal is diagonal; the result will have the maximum of A and B's non-diagonal block size
1453 resultVariationTypes[D1_DIM] = BLOCK_PLUS_DIAGONAL;
1454 resultVariationTypes[D2_DIM] = BLOCK_PLUS_DIAGONAL;
1455 resultBlockPlusDiagonalLastNonDiagonal = std::max(A_MatData.blockPlusDiagonalLastNonDiagonal(), B_MatData.blockPlusDiagonalLastNonDiagonal());
1456
1457 resultActiveDims[resultNumActiveDims] = resultRank - 2;
1458
1459 const int numDiagonalEntries = leftRows - (resultBlockPlusDiagonalLastNonDiagonal + 1);
1460 const int numNondiagonalEntries = (resultBlockPlusDiagonalLastNonDiagonal + 1) * (resultBlockPlusDiagonalLastNonDiagonal + 1);
1461
1462 resultDataDims[resultNumActiveDims] = numDiagonalEntries + numNondiagonalEntries;
1463 resultNumActiveDims++;
1464 }
1465 else
1466 {
1467 // pretty much the only variation types that make sense for matrix dims are GENERAL and BLOCK_PLUS_DIAGONAL
1468 resultVariationTypes[D1_DIM] = GENERAL;
1469 resultVariationTypes[D2_DIM] = GENERAL;
1470
1471 resultActiveDims[resultNumActiveDims] = resultRank - 2;
1472 resultActiveDims[resultNumActiveDims+1] = resultRank - 1;
1473
1474 resultDataDims[resultNumActiveDims] = leftRows;
1475 resultDataDims[resultNumActiveDims+1] = rightCols;
1476 resultNumActiveDims += 2;
1477 }
1478
1479 for (int i=resultRank; i<7; i++)
1480 {
1481 resultVariationTypes[i] = CONSTANT;
1482 resultExtents[i] = 1;
1483 }
1484
1485 ScalarView<DataScalar,DeviceType> data;
1486 if (resultNumActiveDims == 1)
1487 {
1488 auto viewToMatch = A_MatData.getUnderlyingView1(); // new view will match this one in layout and fad dimension, if any
1489 data = getMatchingViewWithLabel(viewToMatch, "Data mat-mat result", resultDataDims[0]);
1490 }
1491 else if (resultNumActiveDims == 2)
1492 {
1493 auto viewToMatch = A_MatData.getUnderlyingView2(); // new view will match this one in layout and fad dimension, if any
1494 data = getMatchingViewWithLabel(viewToMatch, "Data mat-mat result", resultDataDims[0], resultDataDims[1]);
1495 }
1496 else if (resultNumActiveDims == 3)
1497 {
1498 auto viewToMatch = A_MatData.getUnderlyingView3(); // new view will match this one in layout and fad dimension, if any
1499 data = getMatchingViewWithLabel(viewToMatch, "Data mat-mat result", resultDataDims[0], resultDataDims[1], resultDataDims[2]);
1500 }
1501 else if (resultNumActiveDims == 4)
1502 {
1503 auto viewToMatch = A_MatData.getUnderlyingView4(); // new view will match this one in layout and fad dimension, if any
1504 data = getMatchingViewWithLabel(viewToMatch, "Data mat-mat result", resultDataDims[0], resultDataDims[1], resultDataDims[2],
1505 resultDataDims[3]);
1506 }
1507 else if (resultNumActiveDims == 5)
1508 {
1509 auto viewToMatch = A_MatData.getUnderlyingView5(); // new view will match this one in layout and fad dimension, if any
1510 data = getMatchingViewWithLabel(viewToMatch, "Data mat-mat result", resultDataDims[0], resultDataDims[1], resultDataDims[2],
1511 resultDataDims[3], resultDataDims[4]);
1512 }
1513 else if (resultNumActiveDims == 6)
1514 {
1515 auto viewToMatch = A_MatData.getUnderlyingView6(); // new view will match this one in layout and fad dimension, if any
1516 data = getMatchingViewWithLabel(viewToMatch, "Data mat-mat result", resultDataDims[0], resultDataDims[1], resultDataDims[2],
1517 resultDataDims[3], resultDataDims[4], resultDataDims[5]);
1518 }
1519 else // resultNumActiveDims == 7
1520 {
1521 auto viewToMatch = A_MatData.getUnderlyingView7(); // new view will match this one in layout and fad dimension, if any
1522 data = getMatchingViewWithLabel(viewToMatch, "Data mat-mat result", resultDataDims[0], resultDataDims[1], resultDataDims[2],
1523 resultDataDims[3], resultDataDims[4], resultDataDims[5], resultDataDims[6]);
1524 }
1525
1526 return Data<DataScalar,DeviceType>(data,resultRank,resultExtents,resultVariationTypes,resultBlockPlusDiagonalLastNonDiagonal);
1527 }
1528
1532 {
1533 // we treat last two logical dimensions of matData as the matrix; last dimension of vecData as the vector
1534 INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE(matData.rank() != vecData.rank() + 1, std::invalid_argument, "matData and vecData have incompatible ranks");
1535 const int vecDim = vecData.extent_int(vecData.rank() - 1);
1536 const int matRows = matData.extent_int(matData.rank() - 2);
1537 const int matCols = matData.extent_int(matData.rank() - 1);
1538
1539 const int resultRank = vecData.rank();
1540
1541 INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE(matCols != vecDim, std::invalid_argument, "matData column count != vecData dimension");
1542
1543 Kokkos::Array<int,7> resultExtents; // logical extents
1544 Kokkos::Array<DataVariationType,7> resultVariationTypes; // for each dimension, whether the data varies in that dimension
1545 auto vecVariationTypes = vecData.getVariationTypes();
1546 auto matVariationTypes = matData.getVariationTypes();
1547
1548 Kokkos::Array<int,7> resultActiveDims;
1549 Kokkos::Array<int,7> resultDataDims;
1550 int resultNumActiveDims = 0; // how many of the 7 entries are actually filled in
1551 // the following loop is over the dimensions *prior* to matrix/vector dimensions
1552 for (int i=0; i<resultRank-1; i++)
1553 {
1554 resultExtents[i] = vecData.extent_int(i);
1555 INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE(vecData.extent_int(i) != matData.extent_int(i), std::invalid_argument, "matData and vecData extents must match in each non-matrix/vector dimension");
1556
1557 const DataVariationType &vecVariationType = vecVariationTypes[i];
1558 const DataVariationType &matVariationType = matVariationTypes[i];
1559
1560 // BLOCK_PLUS_DIAGONAL should only occur in matData, and only in the matrix (final) dimensions
1561 INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE(vecVariationType == BLOCK_PLUS_DIAGONAL, std::invalid_argument, "unsupported variationType");
1562 INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE(matVariationType == BLOCK_PLUS_DIAGONAL, std::invalid_argument, "unsupported variationType");
1563
1564 int dataSize = 0;
1565 DataVariationType resultVariationType;
1566 if ((vecVariationType == GENERAL) || (matVariationType == GENERAL))
1567 {
1568 resultVariationType = GENERAL;
1569 dataSize = resultExtents[i];
1570 }
1571 else if ((matVariationType == CONSTANT) && (vecVariationType == CONSTANT))
1572 {
1573 resultVariationType = CONSTANT;
1574 dataSize = 1;
1575 }
1576 else if ((matVariationType == MODULAR) && (vecVariationType == CONSTANT))
1577 {
1578 resultVariationType = MODULAR;
1579 dataSize = matData.getVariationModulus(i);
1580 }
1581 else if ((matVariationType == CONSTANT) && (vecVariationType == MODULAR))
1582 {
1583 resultVariationType = MODULAR;
1584 dataSize = matData.getVariationModulus(i);
1585 }
1586 else
1587 {
1588 // both are modular. We allow this if they agree on the modulus
1589 auto matModulus = matData.getVariationModulus(i);
1590 auto vecModulus = vecData.getVariationModulus(i);
1591 INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE(matModulus != vecModulus, std::invalid_argument, "If matrix and vector both have variation type MODULAR, they must agree on the modulus");
1592 resultVariationType = MODULAR;
1593 dataSize = matModulus;
1594 }
1595 resultVariationTypes[i] = resultVariationType;
1596
1597 if (resultVariationType != CONSTANT)
1598 {
1599 resultActiveDims[resultNumActiveDims] = i;
1600 resultDataDims[resultNumActiveDims] = dataSize;
1601 resultNumActiveDims++;
1602 }
1603 }
1604 // for the final dimension, the variation type is always GENERAL
1605 // (Some combinations, e.g. CONSTANT/CONSTANT *would* generate a CONSTANT result, but constant matrices don't make a lot of sense beyond 1x1 matrices…)
1606 resultVariationTypes[resultNumActiveDims] = GENERAL;
1607 resultActiveDims[resultNumActiveDims] = resultRank - 1;
1608 resultDataDims[resultNumActiveDims] = matRows;
1609 resultExtents[resultRank-1] = matRows;
1610 resultNumActiveDims++;
1611
1612 for (int i=resultRank; i<7; i++)
1613 {
1614 resultVariationTypes[i] = CONSTANT;
1615 resultExtents[i] = 1;
1616 }
1617
1618 ScalarView<DataScalar,DeviceType> data;
1619 if (resultNumActiveDims == 1)
1620 {
1621 data = matData.allocateDynRankViewMatchingUnderlying(resultDataDims[0]);
1622 }
1623 else if (resultNumActiveDims == 2)
1624 {
1625 data = matData.allocateDynRankViewMatchingUnderlying(resultDataDims[0], resultDataDims[1]);
1626 }
1627 else if (resultNumActiveDims == 3)
1628 {
1629 data = matData.allocateDynRankViewMatchingUnderlying(resultDataDims[0], resultDataDims[1], resultDataDims[2]);
1630 }
1631 else if (resultNumActiveDims == 4)
1632 {
1633 data = matData.allocateDynRankViewMatchingUnderlying(resultDataDims[0], resultDataDims[1], resultDataDims[2],
1634 resultDataDims[3]);
1635 }
1636 else if (resultNumActiveDims == 5)
1637 {
1638 data = matData.allocateDynRankViewMatchingUnderlying(resultDataDims[0], resultDataDims[1], resultDataDims[2],
1639 resultDataDims[3], resultDataDims[4]);
1640 }
1641 else if (resultNumActiveDims == 6)
1642 {
1643 data = matData.allocateDynRankViewMatchingUnderlying(resultDataDims[0], resultDataDims[1], resultDataDims[2],
1644 resultDataDims[3], resultDataDims[4], resultDataDims[5]);
1645 }
1646 else // resultNumActiveDims == 7
1647 {
1648 data = matData.allocateDynRankViewMatchingUnderlying(resultDataDims[0], resultDataDims[1], resultDataDims[2],
1649 resultDataDims[3], resultDataDims[4], resultDataDims[5], resultDataDims[6]);
1650 }
1651
1652 return Data<DataScalar,DeviceType>(data,resultRank,resultExtents,resultVariationTypes);
1653 }
1654
1656 template<int rank>
1657 enable_if_t<(rank!=1) && (rank!=7), Kokkos::MDRangePolicy<typename DeviceType::execution_space,Kokkos::Rank<rank>> >
1659 {
1660 using ExecutionSpace = typename DeviceType::execution_space;
1661 Kokkos::Array<int,rank> startingOrdinals;
1662 Kokkos::Array<int,rank> extents;
1663
1664 for (int d=0; d<rank; d++)
1665 {
1666 startingOrdinals[d] = 0;
1667 extents[d] = getDataExtent(d);
1668 }
1669 auto policy = Kokkos::MDRangePolicy<ExecutionSpace,Kokkos::Rank<rank>>(startingOrdinals,extents);
1670 return policy;
1671 }
1672
1674 template<int rank>
1675 enable_if_t<rank==7, Kokkos::MDRangePolicy<typename DeviceType::execution_space,Kokkos::Rank<6>> >
1677 {
1678 using ExecutionSpace = typename DeviceType::execution_space;
1679 Kokkos::Array<int,6> startingOrdinals;
1680 Kokkos::Array<int,6> extents;
1681
1682 for (int d=0; d<6; d++)
1683 {
1684 startingOrdinals[d] = 0;
1685 extents[d] = getDataExtent(d);
1686 }
1687 auto policy = Kokkos::MDRangePolicy<ExecutionSpace,Kokkos::Rank<6>>(startingOrdinals,extents);
1688 return policy;
1689 }
1690
1691 template<int rank>
1692 inline
1693 enable_if_t<rank==1, Kokkos::RangePolicy<typename DeviceType::execution_space> >
1695 {
1696 using ExecutionSpace = typename DeviceType::execution_space;
1697 Kokkos::RangePolicy<ExecutionSpace> policy(ExecutionSpace(),0,getDataExtent(0));
1698 return policy;
1699 }
1700
1702 Data shallowCopy(const int rank, const Kokkos::Array<int,7> &extents, const Kokkos::Array<DataVariationType,7> &variationTypes) const
1703 {
1704 switch (dataRank_)
1705 {
1706 case 1: return Data(rank, data1_, extents, variationTypes);
1707 case 2: return Data(rank, data2_, extents, variationTypes);
1708 case 3: return Data(rank, data3_, extents, variationTypes);
1709 case 4: return Data(rank, data4_, extents, variationTypes);
1710 case 5: return Data(rank, data5_, extents, variationTypes);
1711 case 6: return Data(rank, data6_, extents, variationTypes);
1712 case 7: return Data(rank, data7_, extents, variationTypes);
1713 default:
1714 INTREPID2_TEST_FOR_EXCEPTION(true, std::invalid_argument, "Unhandled dataRank_");
1715 }
1716 }
1717
1719 template<class BinaryOperator>
1720 void storeInPlaceCombination(const Data<DataScalar,DeviceType> &A, const Data<DataScalar,DeviceType> &B, BinaryOperator binaryOperator);
1721
1728
1735
1742
1749
1752 {
1753 // TODO: add a compile-time (SFINAE-type) guard against DataScalar types that do not support arithmetic operations. (We support Orientation as a DataScalar type; it might suffice just to compare DataScalar to Orientation, and eliminate this method for that case.)
1754 // TODO: check for invalidly shaped containers.
1755
1756 const int matRows = matData.extent_int(matData.rank() - 2);
1757 const int matCols = matData.extent_int(matData.rank() - 1);
1758
1759 // shallow copy of this to avoid implicit references to this in call to getWritableEntry() below
1760 Data<DataScalar,DeviceType> thisData = *this;
1761
1762 using ExecutionSpace = typename DeviceType::execution_space;
1763 // note the use of getDataExtent() below: we only range over the possibly-distinct entries
1764 if (rank_ == 3)
1765 {
1766 // typical case for e.g. gradient data: (C,P,D)
1767 auto policy = Kokkos::MDRangePolicy<ExecutionSpace,Kokkos::Rank<3>>({0,0,0},{getDataExtent(0),getDataExtent(1),matRows});
1768 Kokkos::parallel_for("compute mat-vec", policy,
1769 KOKKOS_LAMBDA (const int &cellOrdinal, const int &pointOrdinal, const int &i) {
1770 auto & val_i = thisData.getWritableEntry(cellOrdinal, pointOrdinal, i);
1771 val_i = 0;
1772 for (int j=0; j<matCols; j++)
1773 {
1774 val_i += matData(cellOrdinal,pointOrdinal,i,j) * vecData(cellOrdinal,pointOrdinal,j);
1775 }
1776 });
1777 }
1778 else if (rank_ == 2)
1779 {
1780 //
1781 auto policy = Kokkos::MDRangePolicy<ExecutionSpace,Kokkos::Rank<2>>({0,0},{getDataExtent(0),matRows});
1782 Kokkos::parallel_for("compute mat-vec", policy,
1783 KOKKOS_LAMBDA (const int &vectorOrdinal, const int &i) {
1784 auto & val_i = thisData.getWritableEntry(vectorOrdinal, i);
1785 val_i = 0;
1786 for (int j=0; j<matCols; j++)
1787 {
1788 val_i += matData(vectorOrdinal,i,j) * vecData(vectorOrdinal,j);
1789 }
1790 });
1791 }
1792 else if (rank_ == 1)
1793 {
1794 // single-vector case
1795 Kokkos::RangePolicy<ExecutionSpace> policy(0,matRows);
1796 Kokkos::parallel_for("compute mat-vec", policy,
1797 KOKKOS_LAMBDA (const int &i) {
1798 auto & val_i = thisData.getWritableEntry(i);
1799 val_i = 0;
1800 for (int j=0; j<matCols; j++)
1801 {
1802 val_i += matData(i,j) * vecData(j);
1803 }
1804 });
1805 }
1806 else
1807 {
1808 // TODO: handle other cases
1809 INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE(true, std::logic_error, "rank not yet supported");
1810 }
1811 }
1812
1819 void storeMatMat( const bool transposeA, const Data<DataScalar,DeviceType> &A_MatData, const bool transposeB, const Data<DataScalar,DeviceType> &B_MatData )
1820 {
1821 // TODO: add a compile-time (SFINAE-type) guard against DataScalar types that do not support arithmetic operations. (We support Orientation as a DataScalar type; it might suffice just to compare DataScalar to Orientation, and eliminate this method for that case.)
1822 // TODO: check for invalidly shaped containers.
1823
1824 // we treat last two logical dimensions of matData as the matrix; last dimension of vecData as the vector
1825 INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE(A_MatData.rank() != B_MatData.rank(), std::invalid_argument, "AmatData and BmatData have incompatible ranks");
1826
1827 const int D1_DIM = A_MatData.rank() - 2;
1828 const int D2_DIM = A_MatData.rank() - 1;
1829
1830 const int A_rows = A_MatData.extent_int(D1_DIM);
1831 const int A_cols = A_MatData.extent_int(D2_DIM);
1832 const int B_rows = B_MatData.extent_int(D1_DIM);
1833 const int B_cols = B_MatData.extent_int(D2_DIM);
1834
1835 const int leftRows = transposeA ? A_cols : A_rows;
1836 const int leftCols = transposeA ? A_rows : A_cols;
1837 const int rightCols = transposeB ? B_rows : B_cols;
1838
1839#ifdef INTREPID2_HAVE_DEBUG
1840 const int rightRows = transposeB ? B_cols : B_rows;
1841 INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE(leftCols != rightRows, std::invalid_argument, "inner dimensions do not match");
1842#endif
1843
1844 // shallow copy of this to avoid implicit references to this in call to getWritableEntry() below
1845 Data<DataScalar,DeviceType> thisData = *this;
1846
1847 using ExecutionSpace = typename DeviceType::execution_space;
1848
1849 const int diagonalStart = (variationType_[D1_DIM] == BLOCK_PLUS_DIAGONAL) ? blockPlusDiagonalLastNonDiagonal_ + 1 : leftRows;
1850 // note the use of getDataExtent() below: we only range over the possibly-distinct entries
1851 if (rank_ == 3)
1852 {
1853 // (C,D,D), say
1854 auto policy = Kokkos::RangePolicy<ExecutionSpace>(0,getDataExtent(0));
1855 Kokkos::parallel_for("compute mat-mat", policy,
1856 KOKKOS_LAMBDA (const int &matrixOrdinal) {
1857 for (int i=0; i<diagonalStart; i++)
1858 {
1859 for (int j=0; j<rightCols; j++)
1860 {
1861 auto & val_ij = thisData.getWritableEntry(matrixOrdinal, i, j);
1862 val_ij = 0;
1863 for (int k=0; k<leftCols; k++)
1864 {
1865 const auto & left = transposeA ? A_MatData(matrixOrdinal,k,i) : A_MatData(matrixOrdinal,i,k);
1866 const auto & right = transposeB ? B_MatData(matrixOrdinal,j,k) : B_MatData(matrixOrdinal,k,j);
1867 val_ij += left * right;
1868 }
1869 }
1870 }
1871 for (int i=diagonalStart; i<leftRows; i++)
1872 {
1873 auto & val_ii = thisData.getWritableEntry(matrixOrdinal, i, i);
1874 const auto & left = A_MatData(matrixOrdinal,i,i);
1875 const auto & right = B_MatData(matrixOrdinal,i,i);
1876 val_ii = left * right;
1877 }
1878 });
1879 }
1880 else if (rank_ == 4)
1881 {
1882 // (C,P,D,D), perhaps
1883 auto policy = Kokkos::MDRangePolicy<ExecutionSpace, Kokkos::Rank<2> >({0,0},{getDataExtent(0),getDataExtent(1)});
1884 if (underlyingMatchesLogical_) // receiving data object is completely expanded
1885 {
1886 Kokkos::parallel_for("compute mat-mat", policy,
1887 KOKKOS_LAMBDA (const int &cellOrdinal, const int &pointOrdinal) {
1888 for (int i=0; i<leftCols; i++)
1889 {
1890 for (int j=0; j<rightCols; j++)
1891 {
1892 auto & val_ij = thisData.getUnderlyingView4()(cellOrdinal,pointOrdinal, i, j);
1893 val_ij = 0;
1894 for (int k=0; k<leftCols; k++)
1895 {
1896 const auto & left = transposeA ? A_MatData(cellOrdinal,pointOrdinal,k,i) : A_MatData(cellOrdinal,pointOrdinal,i,k);
1897 const auto & right = transposeB ? B_MatData(cellOrdinal,pointOrdinal,j,k) : B_MatData(cellOrdinal,pointOrdinal,k,j);
1898 val_ij += left * right;
1899 }
1900 }
1901 }
1902 });
1903 }
1904 else
1905 {
1906 Kokkos::parallel_for("compute mat-mat", policy,
1907 KOKKOS_LAMBDA (const int &cellOrdinal, const int &pointOrdinal) {
1908 for (int i=0; i<diagonalStart; i++)
1909 {
1910 for (int j=0; j<rightCols; j++)
1911 {
1912 auto & val_ij = thisData.getWritableEntry(cellOrdinal,pointOrdinal, i, j);
1913 val_ij = 0;
1914 for (int k=0; k<leftCols; k++)
1915 {
1916 const auto & left = transposeA ? A_MatData(cellOrdinal,pointOrdinal,k,i) : A_MatData(cellOrdinal,pointOrdinal,i,k);
1917 const auto & right = transposeB ? B_MatData(cellOrdinal,pointOrdinal,j,k) : B_MatData(cellOrdinal,pointOrdinal,k,j);
1918 val_ij += left * right;
1919 }
1920 }
1921 }
1922 for (int i=diagonalStart; i<leftRows; i++)
1923 {
1924 auto & val_ii = thisData.getWritableEntry(cellOrdinal,pointOrdinal, i, i);
1925 const auto & left = A_MatData(cellOrdinal,pointOrdinal,i,i);
1926 const auto & right = B_MatData(cellOrdinal,pointOrdinal,i,i);
1927 val_ii = left * right;
1928 }
1929 });
1930 }
1931 }
1932 else
1933 {
1934 // TODO: handle other cases
1935 INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE(true, std::logic_error, "rank not yet supported");
1936 }
1937 }
1938
1940 KOKKOS_INLINE_FUNCTION constexpr bool isValid() const
1941 {
1942 return extents_[0] > 0;
1943 }
1944
1946 KOKKOS_INLINE_FUNCTION
1947 unsigned rank() const
1948 {
1949 return rank_;
1950 }
1951
1958 void setExtent(const ordinal_type &d, const ordinal_type &newExtent)
1959 {
1960 INTREPID2_TEST_FOR_EXCEPTION(variationType_[d] == BLOCK_PLUS_DIAGONAL, std::invalid_argument, "setExtent is not supported for BLOCK_PLUS_DIAGONAL dimensions");
1961
1962 if (variationType_[d] == MODULAR)
1963 {
1964 bool dividesEvenly = ((newExtent / variationModulus_[d]) * variationModulus_[d] == newExtent);
1965 INTREPID2_TEST_FOR_EXCEPTION(!dividesEvenly, std::invalid_argument, "when setExtent is called on dimenisions with MODULAR variation, the modulus must divide the new extent evenly");
1966 }
1967
1968 if ((newExtent != extents_[d]) && (variationType_[d] == GENERAL))
1969 {
1970 // then we need to resize; let's determine the full set of new extents
1971 std::vector<ordinal_type> newExtents(dataRank_,-1);
1972 for (int r=0; r<dataRank_; r++)
1973 {
1974 if (activeDims_[r] == d)
1975 {
1976 // this is the changed dimension
1977 newExtents[r] = newExtent;
1978 }
1979 else
1980 {
1981 // unchanged; copy from existing
1982 newExtents[r] = getUnderlyingViewExtent(r);
1983 }
1984 }
1985
1986 switch (dataRank_)
1987 {
1988 case 1: Kokkos::resize(data1_,newExtents[0]);
1989 break;
1990 case 2: Kokkos::resize(data2_,newExtents[0],newExtents[1]);
1991 break;
1992 case 3: Kokkos::resize(data3_,newExtents[0],newExtents[1],newExtents[2]);
1993 break;
1994 case 4: Kokkos::resize(data4_,newExtents[0],newExtents[1],newExtents[2],newExtents[3]);
1995 break;
1996 case 5: Kokkos::resize(data5_,newExtents[0],newExtents[1],newExtents[2],newExtents[3],newExtents[4]);
1997 break;
1998 case 6: Kokkos::resize(data6_,newExtents[0],newExtents[1],newExtents[2],newExtents[3],newExtents[4],newExtents[5]);
1999 break;
2000 case 7: Kokkos::resize(data7_,newExtents[0],newExtents[1],newExtents[2],newExtents[3],newExtents[4],newExtents[5],newExtents[6]);
2001 break;
2002 default: INTREPID2_TEST_FOR_EXCEPTION(true, std::logic_error, "Unexpected dataRank_ value");
2003 }
2004 }
2005
2006 extents_[d] = newExtent;
2007 }
2008
2010 KOKKOS_INLINE_FUNCTION
2012 {
2013 return underlyingMatchesLogical_;
2014 }
2015 };
2016}
2017
2018// we do ETI for doubles and default ExecutionSpace's device_type
2020
2021#include "Intrepid2_DataDef.hpp"
2022
2023#endif /* Intrepid2_Data_h */
Header file with various static argument-extractor classes. These are useful for writing efficient,...
Defines implementations for the Data class that are not present in the declaration.
Defines DimensionInfo struct that allows specification of a dimension within a Data object.
KOKKOS_INLINE_FUNCTION DimensionInfo combinedDimensionInfo(const DimensionInfo &myData, const DimensionInfo &otherData)
Returns DimensionInfo for a Data container that combines (through multiplication, say,...
Defines functors for use with Data objects: so far, we include simple arithmetical functors for sum,...
Defines DataVariationType enum that specifies the types of variation possible within a Data object.
@ GENERAL
arbitrary variation
@ BLOCK_PLUS_DIAGONAL
one of two dimensions in a matrix; bottom-right part of matrix is diagonal
@ MODULAR
varies according to modulus of the index
Header function for Intrepid2::Util class and other utility functions.
#define INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE(test, x, msg)
Kokkos::DynRankView< typename ViewType::value_type, typename DeduceLayout< ViewType >::result_layout, typename ViewType::device_type > getMatchingViewWithLabel(const ViewType &view, const std::string &label, DimArgs... dims)
Creates and returns a view that matches the provided view in Kokkos Layout.
Wrapper around a Kokkos::View that allows data that is constant or repeating in various logical dimen...
void storeInPlaceProduct(const Data< DataScalar, DeviceType > &A, const Data< DataScalar, DeviceType > &B)
stores the in-place (entrywise) product, A .* B, into this container.
static Data< DataScalar, DeviceType > allocateMatMatResult(const bool transposeA, const Data< DataScalar, DeviceType > &A_MatData, const bool transposeB, const Data< DataScalar, DeviceType > &B_MatData)
KOKKOS_INLINE_FUNCTION int getVariationModulus(const int &d) const
Variation modulus accessor.
KOKKOS_INLINE_FUNCTION void setUnderlyingView7(const Kokkos::View< DataScalar *******, DeviceType > &view)
sets the View that stores the unique data. For rank-7 underlying containers.
KOKKOS_INLINE_FUNCTION enable_if_t< rank==6, const Kokkos::View< typename RankExpander< DataScalar, rank >::value_type, DeviceType > & > getUnderlyingView() const
Returns the underlying view. Throws an exception if the underlying view is not rank 6.
KOKKOS_INLINE_FUNCTION void setUnderlyingView3(const Kokkos::View< DataScalar ***, DeviceType > &view)
sets the View that stores the unique data. For rank-3 underlying containers.
KOKKOS_INLINE_FUNCTION enable_if_t< rank==1, const Kokkos::View< typename RankExpander< DataScalar, rank >::value_type, DeviceType > & > getUnderlyingView() const
Returns the underlying view. Throws an exception if the underlying view is not rank 1.
KOKKOS_INLINE_FUNCTION reference_type getWritableEntry(const IntArgs... intArgs) const
Returns an l-value reference to the specified logical entry in the underlying view....
void copyDataFromDynRankViewMatchingUnderlying(const ScalarView< DataScalar, DeviceType > &dynRankView) const
Copies from the provided DynRankView into the underlying Kokkos::View container storing the unique da...
enable_if_t<(rank!=1) &&(rank!=7), Kokkos::MDRangePolicy< typename DeviceType::execution_space, Kokkos::Rank< rank > > > dataExtentRangePolicy()
returns an MDRangePolicy over the underlying data extents (but with the logical shape).
KOKKOS_INLINE_FUNCTION void setUnderlyingView1(const Kokkos::View< DataScalar *, DeviceType > &view)
sets the View that stores the unique data. For rank-1 underlying containers.
KOKKOS_INLINE_FUNCTION int extent_int(const int &r) const
Returns the logical extent in the specified dimension.
KOKKOS_INLINE_FUNCTION reference_type getWritableEntryWithPassThroughOption(const bool &passThroughBlockDiagonalArgs, const IntArgs... intArgs) const
Returns an l-value reference to the specified logical entry in the underlying view....
KOKKOS_INLINE_FUNCTION const Kokkos::View< DataScalar **, DeviceType > & getUnderlyingView2() const
returns the View that stores the unique data. For rank-2 underlying containers.
KOKKOS_INLINE_FUNCTION enable_if_t< rank==2, const Kokkos::View< typename RankExpander< DataScalar, rank >::value_type, DeviceType > & > getUnderlyingView() const
Returns the underlying view. Throws an exception if the underlying view is not rank 2.
Data(const unsigned rank, Kokkos::View< ViewScalar, DeviceType, ViewProperties... > data, Kokkos::Array< int, 7 > extents, Kokkos::Array< DataVariationType, 7 > variationType, const int blockPlusDiagonalLastNonDiagonal=-1)
constructor with run-time rank (requires full-length extents, variationType inputs; those beyond the ...
KOKKOS_INLINE_FUNCTION const Kokkos::View< DataScalar ****, DeviceType > & getUnderlyingView4() const
returns the View that stores the unique data. For rank-4 underlying containers.
ScalarView< DataScalar, DeviceType > getUnderlyingView() const
Returns a DynRankView constructed atop the same underlying data as the fixed-rank Kokkos::View used i...
KOKKOS_INLINE_FUNCTION constexpr bool isValid() const
returns true for containers that have data; false for those that don't (namely, those that have been ...
Data()
default constructor (empty data)
KOKKOS_INLINE_FUNCTION const Kokkos::View< DataScalar ***, DeviceType > & getUnderlyingView3() const
returns the View that stores the unique data. For rank-3 underlying containers.
void clear() const
Copies 0.0 to the underlying View.
KOKKOS_INLINE_FUNCTION enable_if_t< rank==7, const Kokkos::View< typename RankExpander< DataScalar, rank >::value_type, DeviceType > & > getUnderlyingView() const
Returns the underlying view. Throws an exception if the underlying view is not rank 7.
KOKKOS_INLINE_FUNCTION bool isDiagonal() const
returns true for containers that have two dimensions marked as BLOCK_PLUS_DIAGONAL for which the non-...
ScalarView< DataScalar, DeviceType > allocateDynRankViewMatchingUnderlying() const
Returns a DynRankView that matches the underlying Kokkos::View object in value_type,...
KOKKOS_INLINE_FUNCTION enable_if_t< rank==3, const Kokkos::View< typename RankExpander< DataScalar, rank >::value_type, DeviceType > & > getUnderlyingView() const
Returns the underlying view. Throws an exception if the underlying view is not rank 3.
KOKKOS_INLINE_FUNCTION return_type getEntry(const IntArgs &... intArgs) const
Returns a (read-only) value corresponding to the specified logical data location.
KOKKOS_INLINE_FUNCTION const Kokkos::View< DataScalar ******, DeviceType > & getUnderlyingView6() const
returns the View that stores the unique data. For rank-6 underlying containers.
Data(const ScalarView< DataScalar, DeviceType > &data, int rank, Kokkos::Array< int, 7 > extents, Kokkos::Array< DataVariationType, 7 > variationType, const int blockPlusDiagonalLastNonDiagonal=-1)
DynRankView constructor. Will copy to a View of appropriate rank.
static void copyContainer(ToContainer to, FromContainer from)
Generic data copying method to allow construction of Data object from DynRankViews for which deep_cop...
KOKKOS_INLINE_FUNCTION const int & blockPlusDiagonalLastNonDiagonal() const
For a Data object containing data with variation type BLOCK_PLUS_DIAGONAL, returns the row and column...
void storeInPlaceSum(const Data< DataScalar, DeviceType > &A, const Data< DataScalar, DeviceType > &B)
stores the in-place (entrywise) sum, A .+ B, into this container.
void applyOperator(UnaryOperator unaryOperator)
applies the specified unary operator to each entry
static KOKKOS_INLINE_FUNCTION int blockPlusDiagonalDiagonalEntryIndex(const int &lastNondiagonal, const int &numNondiagonalEntries, const int &i)
Returns flattened index of the specified (i,i) matrix entry, assuming that i > lastNondiagonal....
void storeMatVec(const Data< DataScalar, DeviceType > &matData, const Data< DataScalar, DeviceType > &vecData)
Places the result of a matrix-vector multiply corresponding to the two provided containers into this ...
static KOKKOS_INLINE_FUNCTION int blockPlusDiagonalNumNondiagonalEntries(const int &lastNondiagonal)
Returns the number of non-diagonal entries based on the last non-diagonal. Only applicable for BLOCK_...
Data(ScalarView< DataScalar, DeviceType > data)
copy constructor modeled after the copy-like constructor above. Not as efficient as the implicit copy...
KOKKOS_INLINE_FUNCTION ordinal_type getUnderlyingViewSize() const
returns the number of entries in the View that stores the unique data
KOKKOS_INLINE_FUNCTION enable_if_t< rank==5, const Kokkos::View< typename RankExpander< DataScalar, rank >::value_type, DeviceType > & > getUnderlyingView() const
Returns the underlying view. Throws an exception if the underlying view is not rank 5.
void storeInPlaceQuotient(const Data< DataScalar, DeviceType > &A, const Data< DataScalar, DeviceType > &B)
stores the in-place (entrywise) quotient, A ./ B, into this container.
static Data< DataScalar, DeviceType > allocateInPlaceCombinationResult(const Data< DataScalar, DeviceType > &A, const Data< DataScalar, DeviceType > &B)
KOKKOS_INLINE_FUNCTION const Kokkos::Array< DataVariationType, 7 > & getVariationTypes() const
Returns an array with the variation types in each logical dimension.
KOKKOS_INLINE_FUNCTION void setUnderlyingView5(const Kokkos::View< DataScalar *****, DeviceType > &view)
sets the View that stores the unique data. For rank-5 underlying containers.
KOKKOS_INLINE_FUNCTION const Kokkos::View< DataScalar *, DeviceType > & getUnderlyingView1() const
returns the View that stores the unique data. For rank-1 underlying containers.
KOKKOS_INLINE_FUNCTION int getDataExtent(const ordinal_type &d) const
returns the true extent of the data corresponding to the logical dimension provided; if the data does...
KOKKOS_INLINE_FUNCTION void setUnderlyingView6(const Kokkos::View< DataScalar ******, DeviceType > &view)
sets the View that stores the unique data. For rank-6 underlying containers.
KOKKOS_INLINE_FUNCTION const Kokkos::View< DataScalar *******, DeviceType > & getUnderlyingView7() const
returns the View that stores the unique data. For rank-7 underlying containers.
Data< DataScalar, DeviceType > allocateConstantData(const DataScalar &value)
KOKKOS_INLINE_FUNCTION void setUnderlyingView4(const Kokkos::View< DataScalar ****, DeviceType > &view)
sets the View that stores the unique data. For rank-4 underlying containers.
void storeMatMat(const bool transposeA, const Data< DataScalar, DeviceType > &A_MatData, const bool transposeB, const Data< DataScalar, DeviceType > &B_MatData)
KOKKOS_INLINE_FUNCTION Kokkos::Array< int, 7 > getExtents() const
Returns an array containing the logical extents in each dimension.
ScalarView< DataScalar, DeviceType > allocateDynRankViewMatchingUnderlying(DimArgs... dims) const
Returns a DynRankView that matches the underlying Kokkos::View object value_type and layout,...
KOKKOS_INLINE_FUNCTION enable_if_t< rank==4, const Kokkos::View< typename RankExpander< DataScalar, rank >::value_type, DeviceType > & > getUnderlyingView() const
Returns the underlying view. Throws an exception if the underlying view is not rank 4.
KOKKOS_INLINE_FUNCTION bool underlyingMatchesLogical() const
Returns true if the underlying container has exactly the same rank and extents as the logical contain...
KOKKOS_INLINE_FUNCTION ordinal_type getUnderlyingViewRank() const
returns the rank of the View that stores the unique data
void allocateAndCopyFromDynRankView(ScalarView< DataScalar, DeviceType > data)
allocate an underlying View that matches the provided DynRankView in dimensions, and copy....
void storeInPlaceDifference(const Data< DataScalar, DeviceType > &A, const Data< DataScalar, DeviceType > &B)
stores the in-place (entrywise) difference, A .- B, into this container.
static KOKKOS_INLINE_FUNCTION int blockPlusDiagonalBlockEntryIndex(const int &lastNondiagonal, const int &numNondiagonalEntries, const int &i, const int &j)
//! Returns flattened index of the specified (i,j) matrix entry, assuming that i,j ≤ lastNondiagonal....
KOKKOS_INLINE_FUNCTION int getUnderlyingViewExtent(const int &dim) const
Returns the extent of the underlying view in the specified dimension.
void setActiveDims()
class initialization method. Called by constructors.
KOKKOS_INLINE_FUNCTION return_type getEntryWithPassThroughOption(const bool &passThroughBlockDiagonalArgs, const IntArgs &... intArgs) const
Returns a (read-only) value corresponding to the specified logical data location. If passThroughBlock...
Data(const Data< DataScalar, OtherDeviceType > &data)
copy-like constructor for differing execution spaces. This does a deep_copy of the underlying view.
KOKKOS_INLINE_FUNCTION void setUnderlyingView2(const Kokkos::View< DataScalar **, DeviceType > &view)
sets the View that stores the unique data. For rank-2 underlying containers.
void setExtent(const ordinal_type &d, const ordinal_type &newExtent)
sets the logical extent in the specified dimension. If needed, the underlying data container is resiz...
void storeInPlaceCombination(const Data< DataScalar, DeviceType > &A, const Data< DataScalar, DeviceType > &B, BinaryOperator binaryOperator)
Places the result of an in-place combination (e.g., entrywise sum) into this data container.
KOKKOS_INLINE_FUNCTION DimensionInfo combinedDataDimensionInfo(const Data &otherData, const int &dim) const
Returns (DataVariationType, data extent) in the specified dimension for a Data container that combine...
static Data< DataScalar, DeviceType > allocateMatVecResult(const Data< DataScalar, DeviceType > &matData, const Data< DataScalar, DeviceType > &vecData)
KOKKOS_INLINE_FUNCTION DimensionInfo getDimensionInfo(const int &dim) const
Returns an object fully specifying the indicated dimension. This is used in determining appropriate s...
KOKKOS_INLINE_FUNCTION const Kokkos::View< DataScalar *****, DeviceType > & getUnderlyingView5() const
returns the View that stores the unique data. For rank-5 underlying containers.
Data(std::vector< DimensionInfo > dimInfoVector)
Constructor in terms of DimensionInfo for each logical dimension; does not require a View to be speci...
enable_if_t< rank==7, Kokkos::MDRangePolicy< typename DeviceType::execution_space, Kokkos::Rank< 6 > > > dataExtentRangePolicy()
returns an MDRangePolicy over the first six underlying data extents (but with the logical shape).
Data(DataScalar constantValue, Kokkos::Array< int, rank > extents)
constructor for everywhere-constant data
Data(const Kokkos::DynRankView< DataScalar, DeviceType, DynRankViewProperties... > &data, Kokkos::Array< int, rank > extents, Kokkos::Array< DataVariationType, rank > variationType, const int blockPlusDiagonalLastNonDiagonal=-1)
Constructor that accepts a DynRankView as an argument. The data belonging to the DynRankView will be ...
Data shallowCopy(const int rank, const Kokkos::Array< int, 7 > &extents, const Kokkos::Array< DataVariationType, 7 > &variationTypes) const
Creates a new Data object with the same underlying view, but with the specified logical rank,...
KOKKOS_INLINE_FUNCTION unsigned rank() const
Returns the logical rank of the Data container.
A singleton class for a DynRankView containing exactly one zero entry. (Technically,...
Struct expressing all variation information about a Data object in a single dimension,...