Intrepid2
Intrepid2_Data.hpp
Go to the documentation of this file.
1// @HEADER
2// *****************************************************************************
3// Intrepid2 Package
4//
5// Copyright 2007 NTESS and the Intrepid2 contributors.
6// SPDX-License-Identifier: BSD-3-Clause
7// *****************************************************************************
8// @HEADER
9//
10// Intrepid2_Data.hpp
11// QuadraturePerformance
12//
13// Created by Roberts, Nathan V on 8/24/20.
14//
15
16#ifndef Intrepid2_Data_h
17#define Intrepid2_Data_h
18
23#include "Intrepid2_ScalarView.hpp"
24#include "Intrepid2_Utils.hpp"
25
30
31namespace Intrepid2 {
32
41template<class DataScalar,typename DeviceType>
42class ZeroView {
43public:
44 static ScalarView<DataScalar,DeviceType> zeroView()
45 {
46 static ScalarView<DataScalar,DeviceType> zeroView = ScalarView<DataScalar,DeviceType>("zero",1);
47 static bool havePushedFinalizeHook = false;
48 if (!havePushedFinalizeHook)
49 {
50 Kokkos::push_finalize_hook( [=] {
51 zeroView = ScalarView<DataScalar,DeviceType>();
52 });
53 havePushedFinalizeHook = true;
54 }
55 return zeroView;
56 }
57};
58
76 template<class DataScalar,typename DeviceType>
77 class Data {
78 public:
79 using value_type = DataScalar;
80 using execution_space = typename DeviceType::execution_space;
81
82 using reference_type = typename ScalarView<DataScalar,DeviceType>::reference_type;
83 using const_reference_type = typename ScalarView<const DataScalar,DeviceType>::reference_type;
84 private:
85 ordinal_type dataRank_;
86 Kokkos::View<DataScalar*, DeviceType> data1_; // the rank 1 data that is explicitly stored
87 Kokkos::View<DataScalar**, DeviceType> data2_; // the rank 2 data that is explicitly stored
88 Kokkos::View<DataScalar***, DeviceType> data3_; // the rank 3 data that is explicitly stored
89 Kokkos::View<DataScalar****, DeviceType> data4_; // the rank 4 data that is explicitly stored
90 Kokkos::View<DataScalar*****, DeviceType> data5_; // the rank 5 data that is explicitly stored
91 Kokkos::View<DataScalar******, DeviceType> data6_; // the rank 6 data that is explicitly stored
92 Kokkos::View<DataScalar*******, DeviceType> data7_; // the rank 7 data that is explicitly stored
93 Kokkos::Array<int,7> extents_; // logical extents in each dimension
94 Kokkos::Array<DataVariationType,7> variationType_; // for each dimension, whether the data varies in that dimension
95 Kokkos::Array<int,7> variationModulus_; // for each dimension, a value by which indices should be modulused (only used when variationType_ is MODULAR)
96 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)
97
98 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
99 bool underlyingMatchesLogical_; // if true, this Data object has the same rank and extent as the underlying view
100 Kokkos::Array<ordinal_type,7> activeDims_;
101 int numActiveDims_; // how many of the 7 entries are actually filled in
102
103 ordinal_type rank_;
104
105 // we use (const_)reference_type as the return for operator() for performance reasons, especially significant when using Sacado types
106 using return_type = const_reference_type;
107
108 ScalarView<DataScalar,DeviceType> zeroView_; // one-entry (zero); used to allow getEntry() to return 0 for off-diagonal entries in BLOCK_PLUS_DIAGONAL
109
111 KOKKOS_INLINE_FUNCTION
112 static int blockPlusDiagonalNumNondiagonalEntries(const int &lastNondiagonal)
113 {
114 return (lastNondiagonal + 1) * (lastNondiagonal + 1);
115 }
116
118 KOKKOS_INLINE_FUNCTION
119 static int blockPlusDiagonalBlockEntryIndex(const int &lastNondiagonal, const int &numNondiagonalEntries, const int &i, const int &j)
120 {
121 return i * (lastNondiagonal + 1) + j;
122 }
123
125 KOKKOS_INLINE_FUNCTION
126 static int blockPlusDiagonalDiagonalEntryIndex(const int &lastNondiagonal, const int &numNondiagonalEntries, const int &i)
127 {
128 return i - (lastNondiagonal + 1) + numNondiagonalEntries;
129 }
130
132 KOKKOS_INLINE_FUNCTION
133 int getUnderlyingViewExtent(const int &dim) const
134 {
135 switch (dataRank_)
136 {
137 case 1: return data1_.extent_int(dim);
138 case 2: return data2_.extent_int(dim);
139 case 3: return data3_.extent_int(dim);
140 case 4: return data4_.extent_int(dim);
141 case 5: return data5_.extent_int(dim);
142 case 6: return data6_.extent_int(dim);
143 case 7: return data7_.extent_int(dim);
144 default: return -1;
145 }
146 }
147
150 {
151 zeroView_ = ZeroView<DataScalar,DeviceType>::zeroView(); // one-entry (zero); used to allow getEntry() to return 0 for off-diagonal entries in BLOCK_PLUS_DIAGONAL
152 // check that rank is compatible with the claimed extents:
153 for (int d=rank_; d<7; d++)
154 {
155 INTREPID2_TEST_FOR_EXCEPTION(extents_[d] > 1, std::invalid_argument, "Nominal extents may not be > 1 in dimensions beyond the rank of the container");
156 }
157
158 numActiveDims_ = 0;
159 int blockPlusDiagonalCount = 0;
160 underlyingMatchesLogical_ = true;
161 for (ordinal_type i=0; i<7; i++)
162 {
163 if (variationType_[i] == GENERAL)
164 {
165 if (extents_[i] != 0)
166 {
167 variationModulus_[i] = extents_[i];
168 }
169 else
170 {
171 variationModulus_[i] = 1;
172 }
173 activeDims_[numActiveDims_] = i;
174 numActiveDims_++;
175 }
176 else if (variationType_[i] == MODULAR)
177 {
178 underlyingMatchesLogical_ = false;
179 if (extents_[i] != getUnderlyingViewExtent(numActiveDims_))
180 {
181 const int dataExtent = getUnderlyingViewExtent(numActiveDims_);
182 const int logicalExtent = extents_[i];
183 const int modulus = dataExtent;
184
185 INTREPID2_TEST_FOR_EXCEPTION( dataExtent * (logicalExtent / dataExtent) != logicalExtent, std::invalid_argument, "data extent must evenly divide logical extent");
186
187 variationModulus_[i] = modulus;
188 }
189 else
190 {
191 variationModulus_[i] = extents_[i];
192 }
193 activeDims_[numActiveDims_] = i;
194 numActiveDims_++;
195 }
196 else if (variationType_[i] == BLOCK_PLUS_DIAGONAL)
197 {
198 underlyingMatchesLogical_ = false;
199 blockPlusDiagonalCount++;
200 if (blockPlusDiagonalCount == 1) // first dimension thus marked --> active
201 {
202
203#ifdef HAVE_INTREPID2_DEBUG
204 const int numNondiagonalEntries = blockPlusDiagonalNumNondiagonalEntries(blockPlusDiagonalLastNonDiagonal_);
205 const int dataExtent = getUnderlyingViewExtent(numActiveDims_); // flat storage of all matrix entries
206 const int logicalExtent = extents_[i];
207 const int numDiagonalEntries = logicalExtent - (blockPlusDiagonalLastNonDiagonal_ + 1);
208 const int expectedDataExtent = numNondiagonalEntries + numDiagonalEntries;
209 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());
210#endif
211
212 activeDims_[numActiveDims_] = i;
213 numActiveDims_++;
214 }
215 variationModulus_[i] = getUnderlyingViewExtent(numActiveDims_);
216 INTREPID2_TEST_FOR_EXCEPTION(variationType_[i+1] != BLOCK_PLUS_DIAGONAL, std::invalid_argument, "BLOCK_PLUS_DIAGONAL ranks must be contiguous");
217 i++; // skip over the next BLOCK_PLUS_DIAGONAL
218 variationModulus_[i] = 1; // trivial modulus (should not ever be used)
219 INTREPID2_TEST_FOR_EXCEPTION(blockPlusDiagonalCount > 1, std::invalid_argument, "BLOCK_PLUS_DIAGONAL can only apply to two ranks");
220 }
221 else // CONSTANT
222 {
223 if (i < rank_)
224 {
225 underlyingMatchesLogical_ = false;
226 }
227 variationModulus_[i] = 1; // trivial modulus
228 }
229 }
230
231 if (rank_ != dataRank_)
232 {
233 underlyingMatchesLogical_ = false;
234 }
235
236 for (int d=numActiveDims_; d<7; d++)
237 {
238 // for *inactive* dims, the activeDims_ map just is the identity
239 // (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.)
240 activeDims_[d] = d;
241 }
242 for (int d=0; d<7; d++)
243 {
244 INTREPID2_TEST_FOR_EXCEPTION(variationModulus_[d] == 0, std::logic_error, "variationModulus should not ever be 0");
245 }
246 }
247
248 public:
250 template<class UnaryOperator>
251 void applyOperator(UnaryOperator unaryOperator)
252 {
253 using ExecutionSpace = typename DeviceType::execution_space;
254
255 switch (dataRank_)
256 {
257 case 1:
258 {
259 const int dataRank = 1;
260 auto view = getUnderlyingView<dataRank>();
261
262 const int dataExtent = this->getDataExtent(0);
263 Kokkos::RangePolicy<ExecutionSpace> policy(ExecutionSpace(),0,dataExtent);
264 Kokkos::parallel_for("apply operator in-place", policy,
265 KOKKOS_LAMBDA (const int &i0) {
266 view(i0) = unaryOperator(view(i0));
267 });
268
269 }
270 break;
271 case 2:
272 {
273 const int dataRank = 2;
274 auto policy = dataExtentRangePolicy<dataRank>();
275 auto view = getUnderlyingView<dataRank>();
276
277 Kokkos::parallel_for("apply operator in-place", policy,
278 KOKKOS_LAMBDA (const int &i0, const int &i1) {
279 view(i0,i1) = unaryOperator(view(i0,i1));
280 });
281 }
282 break;
283 case 3:
284 {
285 const int dataRank = 3;
286 auto policy = dataExtentRangePolicy<dataRank>();
287 auto view = getUnderlyingView<dataRank>();
288
289 Kokkos::parallel_for("apply operator in-place", policy,
290 KOKKOS_LAMBDA (const int &i0, const int &i1, const int &i2) {
291 view(i0,i1,i2) = unaryOperator(view(i0,i1,i2));
292 });
293 }
294 break;
295 case 4:
296 {
297 const int dataRank = 4;
298 auto policy = dataExtentRangePolicy<dataRank>();
299 auto view = getUnderlyingView<dataRank>();
300
301 Kokkos::parallel_for("apply operator in-place", policy,
302 KOKKOS_LAMBDA (const int &i0, const int &i1, const int &i2, const int &i3) {
303 view(i0,i1,i2,i3) = unaryOperator(view(i0,i1,i2,i3));
304 });
305 }
306 break;
307 case 5:
308 {
309 const int dataRank = 5;
310 auto policy = dataExtentRangePolicy<dataRank>();
311 auto view = getUnderlyingView<dataRank>();
312
313 Kokkos::parallel_for("apply operator in-place", policy,
314 KOKKOS_LAMBDA (const int &i0, const int &i1, const int &i2, const int &i3, const int &i4) {
315 view(i0,i1,i2,i3,i4) = unaryOperator(view(i0,i1,i2,i3,i4));
316 });
317 }
318 break;
319 case 6:
320 {
321 const int dataRank = 6;
322 auto policy = dataExtentRangePolicy<dataRank>();
323 auto view = getUnderlyingView<dataRank>();
324
325 Kokkos::parallel_for("apply operator in-place", policy,
326 KOKKOS_LAMBDA (const int &i0, const int &i1, const int &i2, const int &i3, const int &i4, const int &i5) {
327 view(i0,i1,i2,i3,i4,i5) = unaryOperator(view(i0,i1,i2,i3,i4,i5));
328 });
329 }
330 break;
331 case 7:
332 {
333 const int dataRank = 7;
334 auto policy6 = dataExtentRangePolicy<6>();
335 auto view = getUnderlyingView<dataRank>();
336
337 const int dim_i6 = view.extent_int(6);
338
339 Kokkos::parallel_for("apply operator in-place", policy6,
340 KOKKOS_LAMBDA (const int &i0, const int &i1, const int &i2, const int &i3, const int &i4, const int &i5) {
341 for (int i6=0; i6<dim_i6; i6++)
342 {
343 view(i0,i1,i2,i3,i4,i5,i6) = unaryOperator(view(i0,i1,i2,i3,i4,i5,i6));
344 }
345 });
346 }
347 break;
348 default:
349 INTREPID2_TEST_FOR_EXCEPTION(true,std::invalid_argument,"Unsupported data rank");
350 }
351 }
352
354 template<class ...IntArgs>
355 KOKKOS_INLINE_FUNCTION
356 reference_type getWritableEntryWithPassThroughOption(const bool &passThroughBlockDiagonalArgs, const IntArgs... intArgs) const
357 {
358 #ifdef INTREPID2_HAVE_DEBUG
359 INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE(numArgs != rank_, std::invalid_argument, "getWritableEntry() should have the same number of arguments as the logical rank.");
360 #endif
361 constexpr int numArgs = sizeof...(intArgs);
362 if (underlyingMatchesLogical_)
363 {
364 // in this case, we require that numArgs == dataRank_
365 return getUnderlyingView<numArgs>()(intArgs...);
366 }
367
368 // extract the type of the first argument; use that for the arrays below
369 using int_type = std::tuple_element_t<0, std::tuple<IntArgs...>>;
370
371 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)
372 Kokkos::Array<int_type, 7> refEntry;
373 for (int d=0; d<numArgs; d++)
374 {
375 switch (variationType_[d])
376 {
377 case CONSTANT: refEntry[d] = 0; break;
378 case GENERAL: refEntry[d] = args[d]; break;
379 case MODULAR: refEntry[d] = args[d] % variationModulus_[d]; break;
381 {
382 if (passThroughBlockDiagonalArgs)
383 {
384 refEntry[d] = args[d];
385 refEntry[d+1] = args[d+1]; // this had better be == 0
386 INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE(args[d+1] != 0, std::invalid_argument, "getWritableEntry() called with passThroughBlockDiagonalArgs = true, but nonzero second matrix argument.");
387 }
388 else
389 {
390 const int numNondiagonalEntries = blockPlusDiagonalNumNondiagonalEntries(blockPlusDiagonalLastNonDiagonal_);
391
392 const int_type &i = args[d];
393 if (d+1 >= numArgs)
394 {
395 INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE(true, std::invalid_argument, "BLOCK_PLUS_DIAGONAL must be present for two dimensions; here, encountered only one");
396 }
397 else
398 {
399 const int_type &j = args[d+1];
400
401 if ((i > static_cast<int_type>(blockPlusDiagonalLastNonDiagonal_)) || (j > static_cast<int_type>(blockPlusDiagonalLastNonDiagonal_)))
402 {
403 if (i != j)
404 {
405 // off diagonal: zero
406 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.)
407 }
408 else
409 {
410 refEntry[d] = blockPlusDiagonalDiagonalEntryIndex(blockPlusDiagonalLastNonDiagonal_, numNondiagonalEntries, i);
411 }
412 }
413 else
414 {
415 refEntry[d] = blockPlusDiagonalBlockEntryIndex(blockPlusDiagonalLastNonDiagonal_, numNondiagonalEntries, i, j);
416 }
417
418 // skip next d (this is required also to be BLOCK_PLUS_DIAGONAL, and we've consumed its arg as j above)
419 refEntry[d+1] = 0;
420 }
421 }
422 d++;
423 }
424 }
425 }
426 // refEntry should be zero-filled beyond numArgs, for cases when rank_ < dataRank_ (this only is allowed if the extra dimensions each has extent 1).
427 for (int d=numArgs; d<7; d++)
428 {
429 refEntry[d] = 0;
430 }
431
432 if (dataRank_ == 1)
433 {
434 return data1_(refEntry[activeDims_[0]]);
435 }
436 else if (dataRank_ == 2)
437 {
438 return data2_(refEntry[activeDims_[0]],refEntry[activeDims_[1]]);
439 }
440 else if (dataRank_ == 3)
441 {
442 return data3_(refEntry[activeDims_[0]],refEntry[activeDims_[1]],refEntry[activeDims_[2]]);
443 }
444 else if (dataRank_ == 4)
445 {
446 return data4_(refEntry[activeDims_[0]],refEntry[activeDims_[1]],refEntry[activeDims_[2]],refEntry[activeDims_[3]]);
447 }
448 else if (dataRank_ == 5)
449 {
450 return data5_(refEntry[activeDims_[0]],refEntry[activeDims_[1]],refEntry[activeDims_[2]],refEntry[activeDims_[3]],
451 refEntry[activeDims_[4]]);
452 }
453 else if (dataRank_ == 6)
454 {
455 return data6_(refEntry[activeDims_[0]],refEntry[activeDims_[1]],refEntry[activeDims_[2]],refEntry[activeDims_[3]],
456 refEntry[activeDims_[4]],refEntry[activeDims_[5]]);
457 }
458 else // dataRank_ == 7
459 {
460 return data7_(refEntry[activeDims_[0]],refEntry[activeDims_[1]],refEntry[activeDims_[2]],refEntry[activeDims_[3]],
461 refEntry[activeDims_[4]],refEntry[activeDims_[5]],refEntry[activeDims_[6]]);
462 }
463
464 }
465
467 template<class ...IntArgs>
468 KOKKOS_INLINE_FUNCTION
469 reference_type getWritableEntry(const IntArgs... intArgs) const
470 {
471 return getWritableEntryWithPassThroughOption(false, intArgs...);
472 }
473 public:
475 template<class ToContainer, class FromContainer>
476 static void copyContainer(ToContainer to, FromContainer from)
477 {
478// std::cout << "Entered copyContainer().\n";
479 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)});
480
481 Kokkos::parallel_for("copyContainer", policy,
482 KOKKOS_LAMBDA (const int &i0, const int &i1, const int &i2, const int &i3, const int &i4, const int &i5) {
483 for (int i6=0; i6<from.extent_int(6); i6++)
484 {
485 to.access(i0,i1,i2,i3,i4,i5,i6) = from.access(i0,i1,i2,i3,i4,i5,i6);
486 }
487 });
488 }
489
491 void allocateAndCopyFromDynRankView(ScalarView<DataScalar,DeviceType> data)
492 {
493// std::cout << "Entered allocateAndCopyFromDynRankView().\n";
494 switch (dataRank_)
495 {
496 case 1: data1_ = Kokkos::View<DataScalar*, DeviceType>("Intrepid2 Data", data.extent_int(0)); break;
497 case 2: data2_ = Kokkos::View<DataScalar**, DeviceType>("Intrepid2 Data", data.extent_int(0), data.extent_int(1)); break;
498 case 3: data3_ = Kokkos::View<DataScalar***, DeviceType>("Intrepid2 Data", data.extent_int(0), data.extent_int(1), data.extent_int(2)); break;
499 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;
500 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;
501 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;
502 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;
503 default: INTREPID2_TEST_FOR_EXCEPTION(true, std::invalid_argument, "Invalid data rank");
504 }
505
506 switch (dataRank_)
507 {
508 case 1: copyContainer(data1_,data); break;
509 case 2: copyContainer(data2_,data); break;
510 case 3: copyContainer(data3_,data); break;
511 case 4: copyContainer(data4_,data); break;
512 case 5: copyContainer(data5_,data); break;
513 case 6: copyContainer(data6_,data); break;
514 case 7: copyContainer(data7_,data); break;
515 default: INTREPID2_TEST_FOR_EXCEPTION(true, std::invalid_argument, "Invalid data rank");
516 }
517 }
518
520 Data(std::vector<DimensionInfo> dimInfoVector)
521 :
522 // initialize member variables as if default constructor; if dimInfoVector is empty, we want default constructor behavior.
523 dataRank_(0), extents_({0,0,0,0,0,0,0}), variationType_({CONSTANT,CONSTANT,CONSTANT,CONSTANT,CONSTANT,CONSTANT,CONSTANT}), blockPlusDiagonalLastNonDiagonal_(-1), rank_(dimInfoVector.size())
524 {
525 // If dimInfoVector is empty, the member initialization above is correct; otherwise, we set as below.
526 // Either way, once members are initialized, we must call setActiveDims().
527 if (dimInfoVector.size() != 0)
528 {
529 std::vector<int> dataExtents;
530
531 bool blockPlusDiagonalEncountered = false;
532 for (int d=0; d<rank_; d++)
533 {
534 const DimensionInfo & dimInfo = dimInfoVector[d];
535 extents_[d] = dimInfo.logicalExtent;
536 variationType_[d] = dimInfo.variationType;
537 const bool isBlockPlusDiagonal = (variationType_[d] == BLOCK_PLUS_DIAGONAL);
538 const bool isSecondBlockPlusDiagonal = isBlockPlusDiagonal && blockPlusDiagonalEncountered;
539 if (isBlockPlusDiagonal)
540 {
541 blockPlusDiagonalEncountered = true;
542 blockPlusDiagonalLastNonDiagonal_ = dimInfo.blockPlusDiagonalLastNonDiagonal;
543 }
544 if ((variationType_[d] != CONSTANT) && (!isSecondBlockPlusDiagonal))
545 {
546 dataExtents.push_back(dimInfo.dataExtent);
547 }
548 }
549 if (dataExtents.size() == 0)
550 {
551 // constant data
552 dataExtents.push_back(1);
553 }
554 dataRank_ = dataExtents.size();
555 switch (dataRank_)
556 {
557 case 1: data1_ = Kokkos::View<DataScalar*, DeviceType>("Intrepid2 Data", dataExtents[0]); break;
558 case 2: data2_ = Kokkos::View<DataScalar**, DeviceType>("Intrepid2 Data", dataExtents[0], dataExtents[1]); break;
559 case 3: data3_ = Kokkos::View<DataScalar***, DeviceType>("Intrepid2 Data", dataExtents[0], dataExtents[1], dataExtents[2]); break;
560 case 4: data4_ = Kokkos::View<DataScalar****, DeviceType>("Intrepid2 Data", dataExtents[0], dataExtents[1], dataExtents[2], dataExtents[3]); break;
561 case 5: data5_ = Kokkos::View<DataScalar*****, DeviceType>("Intrepid2 Data", dataExtents[0], dataExtents[1], dataExtents[2], dataExtents[3], dataExtents[4]); break;
562 case 6: data6_ = Kokkos::View<DataScalar******, DeviceType>("Intrepid2 Data", dataExtents[0], dataExtents[1], dataExtents[2], dataExtents[3], dataExtents[4], dataExtents[5]); break;
563 case 7: data7_ = Kokkos::View<DataScalar*******, DeviceType>("Intrepid2 Data", dataExtents[0], dataExtents[1], dataExtents[2], dataExtents[3], dataExtents[4], dataExtents[5], dataExtents[6]); break;
564 default: INTREPID2_TEST_FOR_EXCEPTION(true, std::invalid_argument, "Invalid data rank");
565 }
566 }
568 }
569
571 Data(const ScalarView<DataScalar,DeviceType> &data, int rank, Kokkos::Array<int,7> extents, Kokkos::Array<DataVariationType,7> variationType, const int blockPlusDiagonalLastNonDiagonal = -1)
572 :
573 dataRank_(data.rank()), extents_(extents), variationType_(variationType), blockPlusDiagonalLastNonDiagonal_(blockPlusDiagonalLastNonDiagonal), rank_(rank)
574 {
577 }
578
580 template<typename OtherDeviceType, class = typename std::enable_if< std::is_same<typename DeviceType::memory_space, typename OtherDeviceType::memory_space>::value>::type,
581 class = typename std::enable_if<!std::is_same<DeviceType,OtherDeviceType>::value>::type>
582 Data(const Data<DataScalar,OtherDeviceType> &data)
583 :
584 dataRank_(data.getUnderlyingViewRank()), extents_(data.getExtents()), variationType_(data.getVariationTypes()), blockPlusDiagonalLastNonDiagonal_(data.blockPlusDiagonalLastNonDiagonal()), rank_(data.rank())
585 {
586// std::cout << "Entered copy-like Data constructor.\n";
587 if (dataRank_ != 0) // dataRank_ == 0 indicates an invalid Data object (a placeholder, can indicate zero value)
588 {
589 const auto view = data.getUnderlyingView();
590 switch (dataRank_)
591 {
592 case 1: data1_ = data.getUnderlyingView1(); break;
593 case 2: data2_ = data.getUnderlyingView2(); break;
594 case 3: data3_ = data.getUnderlyingView3(); break;
595 case 4: data4_ = data.getUnderlyingView4(); break;
596 case 5: data5_ = data.getUnderlyingView5(); break;
597 case 6: data6_ = data.getUnderlyingView6(); break;
598 case 7: data7_ = data.getUnderlyingView7(); break;
599 default: INTREPID2_TEST_FOR_EXCEPTION(true, std::invalid_argument, "Invalid data rank");
600 }
601 }
603 }
604
606 template<typename OtherDeviceType, class = typename std::enable_if<!std::is_same<typename DeviceType::memory_space, typename OtherDeviceType::memory_space>::value>::type>
608 :
609 dataRank_(data.getUnderlyingViewRank()), extents_(data.getExtents()), variationType_(data.getVariationTypes()), blockPlusDiagonalLastNonDiagonal_(data.blockPlusDiagonalLastNonDiagonal()), rank_(data.rank())
610 {
611// std::cout << "Entered copy-like Data constructor.\n";
612 if (dataRank_ != 0) // dataRank_ == 0 indicates an invalid Data object (a placeholder, can indicate zero value)
613 {
614 const auto view = data.getUnderlyingView();
615 switch (dataRank_)
616 {
617 case 1: data1_ = Kokkos::View<DataScalar*, DeviceType>("Intrepid2 Data", view.extent_int(0)); break;
618 case 2: data2_ = Kokkos::View<DataScalar**, DeviceType>("Intrepid2 Data", view.extent_int(0), view.extent_int(1)); break;
619 case 3: data3_ = Kokkos::View<DataScalar***, DeviceType>("Intrepid2 Data", view.extent_int(0), view.extent_int(1), view.extent_int(2)); break;
620 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;
621 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;
622 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;
623 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;
624 default: INTREPID2_TEST_FOR_EXCEPTION(true, std::invalid_argument, "Invalid data rank");
625 }
626
627 // copy
628 // (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):
629 // first, mirror and copy dataView; then copy to the appropriate data_ member
630 using MemorySpace = typename DeviceType::memory_space;
631 switch (dataRank_)
632 {
633 case 1: {auto dataViewMirror = Kokkos::create_mirror_view_and_copy(MemorySpace(), data.getUnderlyingView1()); copyContainer(data1_, dataViewMirror);} break;
634 case 2: {auto dataViewMirror = Kokkos::create_mirror_view_and_copy(MemorySpace(), data.getUnderlyingView2()); copyContainer(data2_, dataViewMirror);} break;
635 case 3: {auto dataViewMirror = Kokkos::create_mirror_view_and_copy(MemorySpace(), data.getUnderlyingView3()); copyContainer(data3_, dataViewMirror);} break;
636 case 4: {auto dataViewMirror = Kokkos::create_mirror_view_and_copy(MemorySpace(), data.getUnderlyingView4()); copyContainer(data4_, dataViewMirror);} break;
637 case 5: {auto dataViewMirror = Kokkos::create_mirror_view_and_copy(MemorySpace(), data.getUnderlyingView5()); copyContainer(data5_, dataViewMirror);} break;
638 case 6: {auto dataViewMirror = Kokkos::create_mirror_view_and_copy(MemorySpace(), data.getUnderlyingView6()); copyContainer(data6_, dataViewMirror);} break;
639 case 7: {auto dataViewMirror = Kokkos::create_mirror_view_and_copy(MemorySpace(), data.getUnderlyingView7()); copyContainer(data7_, dataViewMirror);} break;
640 default: INTREPID2_TEST_FOR_EXCEPTION(true, std::invalid_argument, "Invalid data rank");
641 }
642 }
644 }
645
647// Data(const Data<DataScalar,ExecSpaceType> &data)
648// :
649// dataRank_(data.getUnderlyingViewRank()), extents_(data.getExtents()), variationType_(data.getVariationTypes()), blockPlusDiagonalLastNonDiagonal_(data.blockPlusDiagonalLastNonDiagonal()), rank_(data.rank())
650// {
651// std::cout << "Entered Data copy constructor.\n";
652// if (dataRank_ != 0) // dataRank_ == 0 indicates an invalid Data object (a placeholder, can indicate zero value)
653// {
654// const auto view = data.getUnderlyingView();
655// switch (dataRank_)
656// {
657// case 1: data1_ = Kokkos::View<DataScalar*, DeviceType>("Intrepid2 Data - explicit copy constructor(for debugging)", view.extent_int(0)); break;
658// case 2: data2_ = Kokkos::View<DataScalar**, DeviceType>("Intrepid2 Data - explicit copy constructor(for debugging)", view.extent_int(0), view.extent_int(1)); break;
659// 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;
660// 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;
661// 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;
662// 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;
663// 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;
664// default: INTREPID2_TEST_FOR_EXCEPTION(true, std::invalid_argument, "Invalid data rank");
665// }
666//
667// // copy
668// // (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):
669// // first, mirror and copy dataView; then copy to the appropriate data_ member
670// using MemorySpace = typename DeviceType::memory_space;
671// switch (dataRank_)
672// {
673// case 1: {auto dataViewMirror = Kokkos::create_mirror_view_and_copy(MemorySpace(), data.getUnderlyingView1()); copyContainer(data1_, dataViewMirror);} break;
674// case 2: {auto dataViewMirror = Kokkos::create_mirror_view_and_copy(MemorySpace(), data.getUnderlyingView2()); copyContainer(data2_, dataViewMirror);} break;
675// case 3: {auto dataViewMirror = Kokkos::create_mirror_view_and_copy(MemorySpace(), data.getUnderlyingView3()); copyContainer(data3_, dataViewMirror);} break;
676// case 4: {auto dataViewMirror = Kokkos::create_mirror_view_and_copy(MemorySpace(), data.getUnderlyingView4()); copyContainer(data4_, dataViewMirror);} break;
677// case 5: {auto dataViewMirror = Kokkos::create_mirror_view_and_copy(MemorySpace(), data.getUnderlyingView5()); copyContainer(data5_, dataViewMirror);} break;
678// case 6: {auto dataViewMirror = Kokkos::create_mirror_view_and_copy(MemorySpace(), data.getUnderlyingView6()); copyContainer(data6_, dataViewMirror);} break;
679// case 7: {auto dataViewMirror = Kokkos::create_mirror_view_and_copy(MemorySpace(), data.getUnderlyingView7()); copyContainer(data7_, dataViewMirror);} break;
680// default: INTREPID2_TEST_FOR_EXCEPTION(true, std::invalid_argument, "Invalid data rank");
681// }
682// }
683//
684// setActiveDims();
685// }
686
688 Data(ScalarView<DataScalar,DeviceType> data)
689 :
690 Data(data,
691 data.rank(),
692 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)},
693 Kokkos::Array<DataVariationType,7> {GENERAL,GENERAL,GENERAL,GENERAL,GENERAL,GENERAL,GENERAL}, -1)
694 {}
695
697 template<size_t rank, class ...DynRankViewProperties>
698 Data(const Kokkos::DynRankView<DataScalar,DeviceType, DynRankViewProperties...> &data, Kokkos::Array<int,rank> extents, Kokkos::Array<DataVariationType,rank> variationType, const int blockPlusDiagonalLastNonDiagonal = -1)
699 :
700 dataRank_(data.rank()), extents_({1,1,1,1,1,1,1}), variationType_({CONSTANT,CONSTANT,CONSTANT,CONSTANT,CONSTANT,CONSTANT,CONSTANT}), blockPlusDiagonalLastNonDiagonal_(blockPlusDiagonalLastNonDiagonal), rank_(rank)
701 {
702// std::cout << "Entered a DynRankView Data() constructor.\n";
704 for (unsigned d=0; d<rank; d++)
705 {
706 extents_[d] = extents[d];
707 variationType_[d] = variationType[d];
708 }
710 }
711
712 template<size_t rank, class ...ViewProperties>
713 Data(Kokkos::View<DataScalar*,DeviceType, ViewProperties...> data, Kokkos::Array<int,rank> extents, Kokkos::Array<DataVariationType,rank> variationType, const int blockPlusDiagonalLastNonDiagonal = -1)
714 :
715 dataRank_(data.rank), extents_({1,1,1,1,1,1,1}), variationType_({CONSTANT,CONSTANT,CONSTANT,CONSTANT,CONSTANT,CONSTANT,CONSTANT}), blockPlusDiagonalLastNonDiagonal_(blockPlusDiagonalLastNonDiagonal), rank_(rank)
716 {
717 data1_ = data;
718 for (unsigned d=0; d<rank; d++)
719 {
720 extents_[d] = extents[d];
721 variationType_[d] = variationType[d];
722 }
724 }
725
726 template<size_t rank, class ...ViewProperties>
727 Data(Kokkos::View<DataScalar**,DeviceType, ViewProperties...> data, Kokkos::Array<int,rank> extents, Kokkos::Array<DataVariationType,rank> variationType, const int blockPlusDiagonalLastNonDiagonal = -1)
728 :
729 dataRank_(data.rank), extents_({1,1,1,1,1,1,1}), variationType_({CONSTANT,CONSTANT,CONSTANT,CONSTANT,CONSTANT,CONSTANT,CONSTANT}), blockPlusDiagonalLastNonDiagonal_(blockPlusDiagonalLastNonDiagonal), rank_(rank)
730 {
731 data2_ = data;
732 for (unsigned d=0; d<rank; d++)
733 {
734 extents_[d] = extents[d];
735 variationType_[d] = variationType[d];
736 }
738 }
739
740 template<size_t rank, class ...ViewProperties>
741 Data(Kokkos::View<DataScalar***,DeviceType, ViewProperties...> data, Kokkos::Array<int,rank> extents, Kokkos::Array<DataVariationType,rank> variationType, const int blockPlusDiagonalLastNonDiagonal = -1)
742 :
743 dataRank_(data.rank), extents_({1,1,1,1,1,1,1}), variationType_({CONSTANT,CONSTANT,CONSTANT,CONSTANT,CONSTANT,CONSTANT,CONSTANT}), blockPlusDiagonalLastNonDiagonal_(blockPlusDiagonalLastNonDiagonal), rank_(rank)
744 {
745 data3_ = data;
746 for (unsigned d=0; d<rank; d++)
747 {
748 extents_[d] = extents[d];
749 variationType_[d] = variationType[d];
750 }
752 }
753
754 template<size_t rank, class ...ViewProperties>
755 Data(Kokkos::View<DataScalar****,DeviceType, ViewProperties...> data, Kokkos::Array<int,rank> extents, Kokkos::Array<DataVariationType,rank> variationType, const int blockPlusDiagonalLastNonDiagonal = -1)
756 :
757 dataRank_(data.rank), extents_({1,1,1,1,1,1,1}), variationType_({CONSTANT,CONSTANT,CONSTANT,CONSTANT,CONSTANT,CONSTANT,CONSTANT}), blockPlusDiagonalLastNonDiagonal_(blockPlusDiagonalLastNonDiagonal), rank_(rank)
758 {
759 data4_ = data;
760 for (unsigned d=0; d<rank; d++)
761 {
762 extents_[d] = extents[d];
763 variationType_[d] = variationType[d];
764 }
766 }
767
768 template<size_t rank, class ...ViewProperties>
769 Data(Kokkos::View<DataScalar*****,DeviceType, ViewProperties...> data, Kokkos::Array<int,rank> extents, Kokkos::Array<DataVariationType,rank> variationType, const int blockPlusDiagonalLastNonDiagonal = -1)
770 :
771 dataRank_(data.rank), extents_({1,1,1,1,1,1,1}), variationType_({CONSTANT,CONSTANT,CONSTANT,CONSTANT,CONSTANT,CONSTANT,CONSTANT}), blockPlusDiagonalLastNonDiagonal_(blockPlusDiagonalLastNonDiagonal), rank_(rank)
772 {
773 data5_ = data;
774 for (unsigned d=0; d<rank; d++)
775 {
776 extents_[d] = extents[d];
777 variationType_[d] = variationType[d];
778 }
780 }
781
782 template<size_t rank, class ...ViewProperties>
783 Data(Kokkos::View<DataScalar******,DeviceType, ViewProperties...> data, Kokkos::Array<int,rank> extents, Kokkos::Array<DataVariationType,rank> variationType, const int blockPlusDiagonalLastNonDiagonal = -1)
784 :
785 dataRank_(data.rank), extents_({1,1,1,1,1,1,1}), variationType_({CONSTANT,CONSTANT,CONSTANT,CONSTANT,CONSTANT,CONSTANT,CONSTANT}), blockPlusDiagonalLastNonDiagonal_(blockPlusDiagonalLastNonDiagonal), rank_(rank)
786 {
787 data6_ = data;
788 for (unsigned d=0; d<rank; d++)
789 {
790 extents_[d] = extents[d];
791 variationType_[d] = variationType[d];
792 }
794 }
795
796 template<size_t rank, class ...ViewProperties>
797 Data(Kokkos::View<DataScalar*******,DeviceType, ViewProperties...> data, Kokkos::Array<int,rank> extents, Kokkos::Array<DataVariationType,rank> variationType, const int blockPlusDiagonalLastNonDiagonal = -1)
798 :
799 dataRank_(data.rank), extents_({1,1,1,1,1,1,1}), variationType_({CONSTANT,CONSTANT,CONSTANT,CONSTANT,CONSTANT,CONSTANT,CONSTANT}), blockPlusDiagonalLastNonDiagonal_(blockPlusDiagonalLastNonDiagonal), rank_(rank)
800 {
801 data7_ = data;
802 for (unsigned d=0; d<rank; d++)
803 {
804 extents_[d] = extents[d];
805 variationType_[d] = variationType[d];
806 }
808 }
809
811 template<class ViewScalar, class ...ViewProperties>
812 Data(const unsigned rank, Kokkos::View<ViewScalar,DeviceType, ViewProperties...> data, Kokkos::Array<int,7> extents, Kokkos::Array<DataVariationType,7> variationType, const int blockPlusDiagonalLastNonDiagonal = -1)
813 :
814 dataRank_(data.rank), extents_({1,1,1,1,1,1,1}), variationType_({CONSTANT,CONSTANT,CONSTANT,CONSTANT,CONSTANT,CONSTANT,CONSTANT}), blockPlusDiagonalLastNonDiagonal_(blockPlusDiagonalLastNonDiagonal), rank_(rank)
815 {
816 setUnderlyingView<data.rank>(data);
817 for (unsigned d=0; d<rank; d++)
818 {
819 extents_[d] = extents[d];
820 variationType_[d] = variationType[d];
821 }
823 }
824
826 template<size_t rank>
827 Data(DataScalar constantValue, Kokkos::Array<int,rank> extents)
828 :
829 dataRank_(1), extents_({1,1,1,1,1,1,1}), variationType_({CONSTANT,CONSTANT,CONSTANT,CONSTANT,CONSTANT,CONSTANT,CONSTANT}), blockPlusDiagonalLastNonDiagonal_(-1), rank_(rank)
830 {
831 data1_ = Kokkos::View<DataScalar*,DeviceType>("Constant Data",1);
832 Kokkos::deep_copy(data1_, constantValue);
833 for (unsigned d=0; d<rank; d++)
834 {
835 extents_[d] = extents[d];
836 }
838 }
839
842 :
843 dataRank_(0), extents_({0,0,0,0,0,0,0}), variationType_({CONSTANT,CONSTANT,CONSTANT,CONSTANT,CONSTANT,CONSTANT,CONSTANT}), blockPlusDiagonalLastNonDiagonal_(-1), rank_(0)
844 {
846 }
847
849 KOKKOS_INLINE_FUNCTION
851 {
852 return blockPlusDiagonalLastNonDiagonal_;
853 }
854
856 KOKKOS_INLINE_FUNCTION
857 Kokkos::Array<int,7> getExtents() const
858 {
859 return extents_;
860 }
861
863 KOKKOS_INLINE_FUNCTION
864 DimensionInfo getDimensionInfo(const int &dim) const
865 {
866 DimensionInfo dimInfo;
867
868 dimInfo.logicalExtent = extent_int(dim);
869 dimInfo.variationType = variationType_[dim];
870 dimInfo.dataExtent = getDataExtent(dim);
871 dimInfo.variationModulus = variationModulus_[dim];
872
873 if (dimInfo.variationType == BLOCK_PLUS_DIAGONAL)
874 {
875 dimInfo.blockPlusDiagonalLastNonDiagonal = blockPlusDiagonalLastNonDiagonal_;
876 }
877 return dimInfo;
878 }
879
881 KOKKOS_INLINE_FUNCTION
882 DimensionInfo combinedDataDimensionInfo(const Data &otherData, const int &dim) const
883 {
884 const DimensionInfo myDimInfo = getDimensionInfo(dim);
885 const DimensionInfo otherDimInfo = otherData.getDimensionInfo(dim);
886
887 return combinedDimensionInfo(myDimInfo, otherDimInfo);
888 }
889
891 template<int rank>
892 KOKKOS_INLINE_FUNCTION
893 enable_if_t<rank==1, const Kokkos::View<typename RankExpander<DataScalar, rank>::value_type, DeviceType> &>
895 {
896 #ifdef HAVE_INTREPID2_DEBUG
897 INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE(dataRank_ != rank, std::invalid_argument, "getUnderlyingView() called for rank that does not match dataRank_");
898 #endif
899 return data1_;
900 }
901
903 template<int rank>
904 KOKKOS_INLINE_FUNCTION
905 enable_if_t<rank==2, const Kokkos::View<typename RankExpander<DataScalar, rank>::value_type, DeviceType> &>
907 {
908 #ifdef HAVE_INTREPID2_DEBUG
909 INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE(dataRank_ != rank, std::invalid_argument, "getUnderlyingView() called for rank that does not match dataRank_");
910 #endif
911 return data2_;
912 }
913
915 template<int rank>
916 KOKKOS_INLINE_FUNCTION
917 enable_if_t<rank==3, const Kokkos::View<typename RankExpander<DataScalar, rank>::value_type, DeviceType> &>
919 {
920 #ifdef HAVE_INTREPID2_DEBUG
921 INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE(dataRank_ != rank, std::invalid_argument, "getUnderlyingView() called for rank that does not match dataRank_");
922 #endif
923 return data3_;
924 }
925
927 template<int rank>
928 KOKKOS_INLINE_FUNCTION
929 enable_if_t<rank==4, const Kokkos::View<typename RankExpander<DataScalar, rank>::value_type, DeviceType> &>
931 {
932 #ifdef HAVE_INTREPID2_DEBUG
933 INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE(dataRank_ != rank, std::invalid_argument, "getUnderlyingView() called for rank that does not match dataRank_");
934 #endif
935 return data4_;
936 }
937
939 template<int rank>
940 KOKKOS_INLINE_FUNCTION
941 enable_if_t<rank==5, const Kokkos::View<typename RankExpander<DataScalar, rank>::value_type, DeviceType> &>
943 {
944 #ifdef HAVE_INTREPID2_DEBUG
945 INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE(dataRank_ != rank, std::invalid_argument, "getUnderlyingView() called for rank that does not match dataRank_");
946 #endif
947 return data5_;
948 }
949
951 template<int rank>
952 KOKKOS_INLINE_FUNCTION
953 enable_if_t<rank==6, const Kokkos::View<typename RankExpander<DataScalar, rank>::value_type, DeviceType> &>
955 {
956 #ifdef HAVE_INTREPID2_DEBUG
957 INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE(dataRank_ != rank, std::invalid_argument, "getUnderlyingView() called for rank that does not match dataRank_");
958 #endif
959 return data6_;
960 }
961
963 template<int rank>
964 KOKKOS_INLINE_FUNCTION
965 enable_if_t<rank==7, const Kokkos::View<typename RankExpander<DataScalar, rank>::value_type, DeviceType> &>
967 {
968 #ifdef HAVE_INTREPID2_DEBUG
969 INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE(dataRank_ != rank, std::invalid_argument, "getUnderlyingView() called for rank that does not match dataRank_");
970 #endif
971 return data7_;
972 }
973
975 KOKKOS_INLINE_FUNCTION
976 const Kokkos::View<DataScalar*, DeviceType> & getUnderlyingView1() const
977 {
978 return getUnderlyingView<1>();
979 }
980
982 KOKKOS_INLINE_FUNCTION
983 const Kokkos::View<DataScalar**, DeviceType> & getUnderlyingView2() const
984 {
985 return getUnderlyingView<2>();
986 }
987
989 KOKKOS_INLINE_FUNCTION
990 const Kokkos::View<DataScalar***, DeviceType> & getUnderlyingView3() const
991 {
992 return getUnderlyingView<3>();
993 }
994
996 KOKKOS_INLINE_FUNCTION
997 const Kokkos::View<DataScalar****, DeviceType> & getUnderlyingView4() const
998 {
999 return getUnderlyingView<4>();
1000 }
1001
1003 KOKKOS_INLINE_FUNCTION
1004 const Kokkos::View<DataScalar*****, DeviceType> & getUnderlyingView5() const
1005 {
1006 return getUnderlyingView<5>();
1007 }
1008
1010 KOKKOS_INLINE_FUNCTION
1011 const Kokkos::View<DataScalar******, DeviceType> & getUnderlyingView6() const
1012 {
1013 return getUnderlyingView<6>();
1014 }
1015
1017 KOKKOS_INLINE_FUNCTION
1018 const Kokkos::View<DataScalar*******, DeviceType> & getUnderlyingView7() const
1019 {
1020 return getUnderlyingView<7>();
1021 }
1022
1024 KOKKOS_INLINE_FUNCTION
1025 void setUnderlyingView1(const Kokkos::View<DataScalar*, DeviceType> & view)
1026 {
1027 data1_ = view;
1028 }
1029
1031 KOKKOS_INLINE_FUNCTION
1032 void setUnderlyingView2(const Kokkos::View<DataScalar**, DeviceType> & view)
1033 {
1034 data2_ = view;
1035 }
1036
1038 KOKKOS_INLINE_FUNCTION
1039 void setUnderlyingView3(const Kokkos::View<DataScalar***, DeviceType> & view)
1040 {
1041 data3_ = view;
1042 }
1043
1045 KOKKOS_INLINE_FUNCTION
1046 void setUnderlyingView4(const Kokkos::View<DataScalar****, DeviceType> & view)
1047 {
1048 data4_ = view;
1049 }
1050
1052 KOKKOS_INLINE_FUNCTION
1053 void setUnderlyingView5(const Kokkos::View<DataScalar*****, DeviceType> & view)
1054 {
1055 data5_ = view;
1056 }
1057
1059 KOKKOS_INLINE_FUNCTION
1060 void setUnderlyingView6(const Kokkos::View<DataScalar******, DeviceType> & view)
1061 {
1062 data6_ = view;
1063 }
1064
1066 KOKKOS_INLINE_FUNCTION
1067 void setUnderlyingView7(const Kokkos::View<DataScalar*******, DeviceType> & view)
1068 {
1069 data7_ = view;
1070 }
1071
1072 template<int underlyingRank, class ViewScalar>
1073 KOKKOS_INLINE_FUNCTION
1074 void setUnderlyingView(const Kokkos::View<ViewScalar, DeviceType> & view)
1075 {
1076 if constexpr (underlyingRank == 1)
1077 {
1078 setUnderlyingView1(view);
1079 }
1080 else if constexpr (underlyingRank == 2)
1081 {
1082 setUnderlyingView2(view);
1083 }
1084 else if constexpr (underlyingRank == 3)
1085 {
1086 setUnderlyingView3(view);
1087 }
1088 else if constexpr (underlyingRank == 4)
1089 {
1090 setUnderlyingView4(view);
1091 }
1092 else if constexpr (underlyingRank == 5)
1093 {
1094 setUnderlyingView5(view);
1095 }
1096 else if constexpr (underlyingRank == 6)
1097 {
1098 setUnderlyingView6(view);
1099 }
1100 else if constexpr (underlyingRank == 7)
1101 {
1102 setUnderlyingView7(view);
1103 }
1104 else
1105 {
1106 INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE(true, std::invalid_argument, "implementation for specialization missing");
1107 }
1108 }
1109
1111 ScalarView<DataScalar,DeviceType> getUnderlyingView() const
1112 {
1113 switch (dataRank_)
1114 {
1115 case 1: return data1_;
1116 case 2: return data2_;
1117 case 3: return data3_;
1118 case 4: return data4_;
1119 case 5: return data5_;
1120 case 6: return data6_;
1121 case 7: return data7_;
1122 default: INTREPID2_TEST_FOR_EXCEPTION(true, std::invalid_argument, "Invalid data rank");
1123 }
1124 }
1125
1127 KOKKOS_INLINE_FUNCTION
1128 ordinal_type getUnderlyingViewRank() const
1129 {
1130 return dataRank_;
1131 }
1132
1134 KOKKOS_INLINE_FUNCTION
1135 ordinal_type getUnderlyingViewSize() const
1136 {
1137 ordinal_type size = 1;
1138 for (ordinal_type r=0; r<dataRank_; r++)
1139 {
1140 size *= getUnderlyingViewExtent(r);
1141 }
1142 return size;
1143 }
1144
1146 ScalarView<DataScalar,DeviceType> allocateDynRankViewMatchingUnderlying() const
1147 {
1148 switch (dataRank_)
1149 {
1150 case 1: return getMatchingViewWithLabel(data1_, "Intrepid2 Data", data1_.extent_int(0));
1151 case 2: return getMatchingViewWithLabel(data2_, "Intrepid2 Data", data2_.extent_int(0), data2_.extent_int(1));
1152 case 3: return getMatchingViewWithLabel(data3_, "Intrepid2 Data", data3_.extent_int(0), data3_.extent_int(1), data3_.extent_int(2));
1153 case 4: return getMatchingViewWithLabel(data4_, "Intrepid2 Data", data4_.extent_int(0), data4_.extent_int(1), data4_.extent_int(2), data4_.extent_int(3));
1154 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));
1155 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));
1156 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));
1157 default: INTREPID2_TEST_FOR_EXCEPTION(true, std::invalid_argument, "Invalid data rank");
1158 }
1159 }
1160
1162 template<class ... DimArgs>
1163 ScalarView<DataScalar,DeviceType> allocateDynRankViewMatchingUnderlying(DimArgs... dims) const
1164 {
1165 switch (dataRank_)
1166 {
1167 case 1: return getMatchingViewWithLabel(data1_, "Intrepid2 Data", dims...);
1168 case 2: return getMatchingViewWithLabel(data2_, "Intrepid2 Data", dims...);
1169 case 3: return getMatchingViewWithLabel(data3_, "Intrepid2 Data", dims...);
1170 case 4: return getMatchingViewWithLabel(data4_, "Intrepid2 Data", dims...);
1171 case 5: return getMatchingViewWithLabel(data5_, "Intrepid2 Data", dims...);
1172 case 6: return getMatchingViewWithLabel(data6_, "Intrepid2 Data", dims...);
1173 case 7: return getMatchingViewWithLabel(data7_, "Intrepid2 Data", dims...);
1174 default: INTREPID2_TEST_FOR_EXCEPTION(true, std::invalid_argument, "Invalid data rank");
1175 }
1176 }
1177
1179 void clear() const
1180 {
1181 switch (dataRank_)
1182 {
1183 case 1: Kokkos::deep_copy(data1_, 0.0); break;
1184 case 2: Kokkos::deep_copy(data2_, 0.0); break;
1185 case 3: Kokkos::deep_copy(data3_, 0.0); break;
1186 case 4: Kokkos::deep_copy(data4_, 0.0); break;
1187 case 5: Kokkos::deep_copy(data5_, 0.0); break;
1188 case 6: Kokkos::deep_copy(data6_, 0.0); break;
1189 case 7: Kokkos::deep_copy(data7_, 0.0); break;
1190 default: INTREPID2_TEST_FOR_EXCEPTION(true, std::invalid_argument, "Invalid data rank");
1191 }
1192 }
1193
1195 void copyDataFromDynRankViewMatchingUnderlying(const ScalarView<DataScalar,DeviceType> &dynRankView) const
1196 {
1197// std::cout << "Entered copyDataFromDynRankViewMatchingUnderlying().\n";
1198 switch (dataRank_)
1199 {
1200 case 1: copyContainer(data1_,dynRankView); break;
1201 case 2: copyContainer(data2_,dynRankView); break;
1202 case 3: copyContainer(data3_,dynRankView); break;
1203 case 4: copyContainer(data4_,dynRankView); break;
1204 case 5: copyContainer(data5_,dynRankView); break;
1205 case 6: copyContainer(data6_,dynRankView); break;
1206 case 7: copyContainer(data7_,dynRankView); break;
1207 default: INTREPID2_TEST_FOR_EXCEPTION(true, std::invalid_argument, "Invalid data rank");
1208 }
1209 }
1210
1212 KOKKOS_INLINE_FUNCTION int getDataExtent(const ordinal_type &d) const
1213 {
1214 for (int i=0; i<numActiveDims_; i++)
1215 {
1216 if (activeDims_[i] == d)
1217 {
1218 return getUnderlyingViewExtent(i);
1219 }
1220 else if (activeDims_[i] > d)
1221 {
1222 return 1; // data does not vary in the specified dimension
1223 }
1224 }
1225 return 1; // data does not vary in the specified dimension
1226 }
1227
1239 KOKKOS_INLINE_FUNCTION
1240 int getVariationModulus(const int &d) const
1241 {
1242 return variationModulus_[d];
1243 }
1244
1246 KOKKOS_INLINE_FUNCTION
1247 const Kokkos::Array<DataVariationType,7> & getVariationTypes() const
1248 {
1249 return variationType_;
1250 }
1251
1253 template<class ...IntArgs>
1254 KOKKOS_INLINE_FUNCTION
1255 return_type getEntryWithPassThroughOption(const bool &passThroughBlockDiagonalArgs, const IntArgs&... intArgs) const
1256 {
1257 return getWritableEntryWithPassThroughOption(passThroughBlockDiagonalArgs, intArgs...);
1258 }
1259
1261 template<class ...IntArgs>
1262 KOKKOS_INLINE_FUNCTION
1263 return_type getEntry(const IntArgs&... intArgs) const
1264 {
1265 return getEntryWithPassThroughOption(false, intArgs...);
1266 }
1267
1268 template <bool...> struct bool_pack;
1269
1270 template <bool... v>
1271 using all_true = std::is_same<bool_pack<true, v...>, bool_pack<v..., true>>;
1272
1273 template <class ...IntArgs>
1274 using valid_args = all_true<std::is_integral<IntArgs>{}...>;
1275
1276 static_assert(valid_args<int,long,unsigned>::value, "valid args works");
1277
1279 template <class ...IntArgs>
1280 KOKKOS_INLINE_FUNCTION
1281#ifndef __INTEL_COMPILER
1282 // icc has a bug that prevents compilation with this enable_if_t
1283 // (possibly the same as https://community.intel.com/t5/Intel-C-Compiler/Intel-Compiler-bug-while-deducing-template-arguments-inside/m-p/1164358)
1284 // so with icc we'll just skip the argument type/count check
1285 enable_if_t<valid_args<IntArgs...>::value && (sizeof...(IntArgs) <= 7),return_type>
1286#else
1287 return_type
1288#endif
1289 operator()(const IntArgs&... intArgs) const {
1290 return getEntry(intArgs...);
1291 }
1292
1294 KOKKOS_INLINE_FUNCTION
1295 int extent_int(const int& r) const
1296 {
1297 return extents_[r];
1298 }
1299
1300 template <typename iType>
1301 KOKKOS_INLINE_FUNCTION constexpr
1302 typename std::enable_if<std::is_integral<iType>::value, size_t>::type
1303 extent(const iType& r) const {
1304 return extents_[r];
1305 }
1306
1308 KOKKOS_INLINE_FUNCTION bool isDiagonal() const
1309 {
1310 if (blockPlusDiagonalLastNonDiagonal_ >= 1) return false;
1311 int numBlockPlusDiagonalTypes = 0;
1312 for (unsigned r = 0; r<variationType_.size(); r++)
1313 {
1314 const auto &entryType = variationType_[r];
1315 if (entryType == BLOCK_PLUS_DIAGONAL) numBlockPlusDiagonalTypes++;
1316 }
1317 // 2 BLOCK_PLUS_DIAGONAL entries, combined with blockPlusDiagonalLastNonDiagonal being -1 or 0 indicates diagonal
1318 if (numBlockPlusDiagonalTypes == 2) return true;
1319 else if (numBlockPlusDiagonalTypes == 0) return false; // no BLOCK_PLUS_DIAGONAL --> not a diagonal matrix
1320 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)");
1321 return false; // statement should be unreachable; included because compilers don't necessarily recognize that fact...
1322 }
1323
1328 {
1329 return Data<DataScalar,DeviceType>(value, this->getExtents());
1330 }
1331
1338 {
1339 INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE(A.rank() != B.rank(), std::invalid_argument, "A and B must have the same logical shape");
1340 const int rank = A.rank();
1341 std::vector<DimensionInfo> dimInfo(rank);
1342 for (int d=0; d<rank; d++)
1343 {
1344 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");
1345 dimInfo[d] = A.combinedDataDimensionInfo(B, d);
1346 }
1347 Data<DataScalar,DeviceType> result(dimInfo);
1348 return result;
1349 }
1350
1357 static Data<DataScalar,DeviceType> allocateMatMatResult( const bool transposeA, const Data<DataScalar,DeviceType> &A_MatData, const bool transposeB, const Data<DataScalar,DeviceType> &B_MatData )
1358 {
1359 // we treat last two logical dimensions of matData as the matrix; last dimension of vecData as the vector
1360 INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE(A_MatData.rank() != B_MatData.rank(), std::invalid_argument, "AmatData and BmatData have incompatible ranks");
1361
1362 const int D1_DIM = A_MatData.rank() - 2;
1363 const int D2_DIM = A_MatData.rank() - 1;
1364
1365 const int A_rows = A_MatData.extent_int(D1_DIM);
1366 const int A_cols = A_MatData.extent_int(D2_DIM);
1367 const int B_rows = B_MatData.extent_int(D1_DIM);
1368 const int B_cols = B_MatData.extent_int(D2_DIM);
1369
1370 const int leftRows = transposeA ? A_cols : A_rows;
1371 const int leftCols = transposeA ? A_rows : A_cols;
1372 const int rightRows = transposeB ? B_cols : B_rows;
1373 const int rightCols = transposeB ? B_rows : B_cols;
1374
1375 INTREPID2_TEST_FOR_EXCEPTION(leftCols != rightRows, std::invalid_argument, "incompatible matrix dimensions");
1376
1377 Kokkos::Array<int,7> resultExtents; // logical extents
1378 Kokkos::Array<DataVariationType,7> resultVariationTypes; // for each dimension, whether the data varies in that dimension
1379
1380 resultExtents[D1_DIM] = leftRows;
1381 resultExtents[D2_DIM] = rightCols;
1382 int resultBlockPlusDiagonalLastNonDiagonal = -1;
1383 if ( (A_MatData.getVariationTypes()[D1_DIM] == BLOCK_PLUS_DIAGONAL) && (B_MatData.getVariationTypes()[D1_DIM] == BLOCK_PLUS_DIAGONAL) )
1384 {
1385 // diagonal times diagonal is diagonal; the result will have the maximum of A and B's non-diagonal block size
1386 resultVariationTypes[D1_DIM] = BLOCK_PLUS_DIAGONAL;
1387 resultVariationTypes[D2_DIM] = BLOCK_PLUS_DIAGONAL;
1388 resultBlockPlusDiagonalLastNonDiagonal = std::max(A_MatData.blockPlusDiagonalLastNonDiagonal(), B_MatData.blockPlusDiagonalLastNonDiagonal());
1389 }
1390
1391 const int resultRank = A_MatData.rank();
1392
1393 auto A_VariationTypes = A_MatData.getVariationTypes();
1394 auto B_VariationTypes = B_MatData.getVariationTypes();
1395
1396 Kokkos::Array<int,7> resultActiveDims;
1397 Kokkos::Array<int,7> resultDataDims;
1398 int resultNumActiveDims = 0; // how many of the 7 entries are actually filled in
1399 // the following loop is over the dimensions *prior* to matrix dimensions
1400 for (int i=0; i<resultRank-2; i++)
1401 {
1402 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");
1403
1404 resultExtents[i] = A_MatData.extent_int(i);
1405
1406 const DataVariationType &A_VariationType = A_VariationTypes[i];
1407 const DataVariationType &B_VariationType = B_VariationTypes[i];
1408
1409 // BLOCK_PLUS_DIAGONAL should only occur in matData, and only in the matrix (final) dimensions
1410 INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE(A_VariationType == BLOCK_PLUS_DIAGONAL, std::invalid_argument, "unsupported variationType");
1411 INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE(B_VariationType == BLOCK_PLUS_DIAGONAL, std::invalid_argument, "unsupported variationType");
1412
1413 int dataSize = 0;
1414 DataVariationType resultVariationType;
1415 if ((A_VariationType == GENERAL) || (B_VariationType == GENERAL))
1416 {
1417 resultVariationType = GENERAL;
1418 dataSize = resultExtents[i];
1419 }
1420 else if ((B_VariationType == CONSTANT) && (A_VariationType == CONSTANT))
1421 {
1422 resultVariationType = CONSTANT;
1423 dataSize = 1;
1424 }
1425 else if ((B_VariationType == MODULAR) && (A_VariationType == CONSTANT))
1426 {
1427 resultVariationType = MODULAR;
1428 dataSize = B_MatData.getVariationModulus(i);
1429 }
1430 else if ((B_VariationType == CONSTANT) && (A_VariationType == MODULAR))
1431 {
1432 resultVariationType = MODULAR;
1433 dataSize = A_MatData.getVariationModulus(i);
1434 }
1435 else
1436 {
1437 // both are modular. We allow this if they agree on the modulus
1438 auto A_Modulus = A_MatData.getVariationModulus(i);
1439 auto B_Modulus = B_MatData.getVariationModulus(i);
1440 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");
1441 resultVariationType = MODULAR;
1442 dataSize = A_Modulus;
1443 }
1444 resultVariationTypes[i] = resultVariationType;
1445
1446 if (resultVariationType != CONSTANT)
1447 {
1448 resultActiveDims[resultNumActiveDims] = i;
1449 resultDataDims[resultNumActiveDims] = dataSize;
1450 resultNumActiveDims++;
1451 }
1452 }
1453
1454 // set things for final dimensions:
1455 resultExtents[D1_DIM] = leftRows;
1456 resultExtents[D2_DIM] = rightCols;
1457
1458 if ( (A_MatData.getVariationTypes()[D1_DIM] == BLOCK_PLUS_DIAGONAL) && (B_MatData.getVariationTypes()[D1_DIM] == BLOCK_PLUS_DIAGONAL) )
1459 {
1460 // diagonal times diagonal is diagonal; the result will have the maximum of A and B's non-diagonal block size
1461 resultVariationTypes[D1_DIM] = BLOCK_PLUS_DIAGONAL;
1462 resultVariationTypes[D2_DIM] = BLOCK_PLUS_DIAGONAL;
1463 resultBlockPlusDiagonalLastNonDiagonal = std::max(A_MatData.blockPlusDiagonalLastNonDiagonal(), B_MatData.blockPlusDiagonalLastNonDiagonal());
1464
1465 resultActiveDims[resultNumActiveDims] = resultRank - 2;
1466
1467 const int numDiagonalEntries = leftRows - (resultBlockPlusDiagonalLastNonDiagonal + 1);
1468 const int numNondiagonalEntries = (resultBlockPlusDiagonalLastNonDiagonal + 1) * (resultBlockPlusDiagonalLastNonDiagonal + 1);
1469
1470 resultDataDims[resultNumActiveDims] = numDiagonalEntries + numNondiagonalEntries;
1471 resultNumActiveDims++;
1472 }
1473 else
1474 {
1475 // pretty much the only variation types that make sense for matrix dims are GENERAL and BLOCK_PLUS_DIAGONAL
1476 resultVariationTypes[D1_DIM] = GENERAL;
1477 resultVariationTypes[D2_DIM] = GENERAL;
1478
1479 resultActiveDims[resultNumActiveDims] = resultRank - 2;
1480 resultActiveDims[resultNumActiveDims+1] = resultRank - 1;
1481
1482 resultDataDims[resultNumActiveDims] = leftRows;
1483 resultDataDims[resultNumActiveDims+1] = rightCols;
1484 resultNumActiveDims += 2;
1485 }
1486
1487 for (int i=resultRank; i<7; i++)
1488 {
1489 resultVariationTypes[i] = CONSTANT;
1490 resultExtents[i] = 1;
1491 }
1492
1493 ScalarView<DataScalar,DeviceType> data; // new view will match this one in layout and fad dimension, if any
1494 auto viewToMatch = A_MatData.getUnderlyingView();
1495 if (resultNumActiveDims == 1)
1496 {
1497 data = getMatchingViewWithLabel(viewToMatch, "Data mat-mat result", resultDataDims[0]);
1498 }
1499 else if (resultNumActiveDims == 2)
1500 {
1501 data = getMatchingViewWithLabel(viewToMatch, "Data mat-mat result", resultDataDims[0], resultDataDims[1]);
1502 }
1503 else if (resultNumActiveDims == 3)
1504 {
1505 data = getMatchingViewWithLabel(viewToMatch, "Data mat-mat result", resultDataDims[0], resultDataDims[1], resultDataDims[2]);
1506 }
1507 else if (resultNumActiveDims == 4)
1508 {
1509 data = getMatchingViewWithLabel(viewToMatch, "Data mat-mat result", resultDataDims[0], resultDataDims[1], resultDataDims[2],
1510 resultDataDims[3]);
1511 }
1512 else if (resultNumActiveDims == 5)
1513 {
1514 data = getMatchingViewWithLabel(viewToMatch, "Data mat-mat result", resultDataDims[0], resultDataDims[1], resultDataDims[2],
1515 resultDataDims[3], resultDataDims[4]);
1516 }
1517 else if (resultNumActiveDims == 6)
1518 {
1519 data = getMatchingViewWithLabel(viewToMatch, "Data mat-mat result", resultDataDims[0], resultDataDims[1], resultDataDims[2],
1520 resultDataDims[3], resultDataDims[4], resultDataDims[5]);
1521 }
1522 else // resultNumActiveDims == 7
1523 {
1524 data = getMatchingViewWithLabel(viewToMatch, "Data mat-mat result", resultDataDims[0], resultDataDims[1], resultDataDims[2],
1525 resultDataDims[3], resultDataDims[4], resultDataDims[5], resultDataDims[6]);
1526 }
1527
1528 return Data<DataScalar,DeviceType>(data,resultRank,resultExtents,resultVariationTypes,resultBlockPlusDiagonalLastNonDiagonal);
1529 }
1530
1538 {
1539 INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE(A.rank() != B.rank(), std::invalid_argument, "A and B must have the same logical shape");
1540 const int rank = A.rank();
1541 const int resultRank = rank - numContractionDims;
1542 std::vector<DimensionInfo> dimInfo(resultRank);
1543 for (int d=0; d<resultRank; d++)
1544 {
1545 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");
1546 dimInfo[d] = A.combinedDataDimensionInfo(B, d);
1547 }
1548 Data<DataScalar,DeviceType> result(dimInfo);
1549 return result;
1550 }
1551
1561
1564 static Data<DataScalar,DeviceType> allocateMatVecResult( const Data<DataScalar,DeviceType> &matData, const Data<DataScalar,DeviceType> &vecData, const bool transposeMatrix = false )
1565 {
1566 // we treat last two logical dimensions of matData as the matrix; last dimension of vecData as the vector
1567 INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE(matData.rank() != vecData.rank() + 1, std::invalid_argument, "matData and vecData have incompatible ranks");
1568 const int vecDim = vecData.extent_int(vecData.rank() - 1);
1569
1570 const int D1_DIM = matData.rank() - 2;
1571 const int D2_DIM = matData.rank() - 1;
1572
1573 const int matRows = matData.extent_int(D1_DIM);
1574 const int matCols = matData.extent_int(D2_DIM);
1575
1576 const int rows = transposeMatrix ? matCols : matRows;
1577 const int cols = transposeMatrix ? matRows : matCols;
1578
1579 const int resultRank = vecData.rank();
1580
1581 INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE(cols != vecDim, std::invalid_argument, "matData column count != vecData dimension");
1582
1583 Kokkos::Array<int,7> resultExtents; // logical extents
1584 Kokkos::Array<DataVariationType,7> resultVariationTypes; // for each dimension, whether the data varies in that dimension
1585 auto vecVariationTypes = vecData.getVariationTypes();
1586 auto matVariationTypes = matData.getVariationTypes();
1587
1588 Kokkos::Array<int,7> resultActiveDims;
1589 Kokkos::Array<int,7> resultDataDims;
1590 int resultNumActiveDims = 0; // how many of the 7 entries are actually filled in
1591 // the following loop is over the dimensions *prior* to matrix/vector dimensions
1592 for (int i=0; i<resultRank-1; i++)
1593 {
1594 resultExtents[i] = vecData.extent_int(i);
1595 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");
1596
1597 const DataVariationType &vecVariationType = vecVariationTypes[i];
1598 const DataVariationType &matVariationType = matVariationTypes[i];
1599
1600 // BLOCK_PLUS_DIAGONAL should only occur in matData, and only in the matrix (final) dimensions
1601 INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE(vecVariationType == BLOCK_PLUS_DIAGONAL, std::invalid_argument, "unsupported variationType");
1602 INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE(matVariationType == BLOCK_PLUS_DIAGONAL, std::invalid_argument, "unsupported variationType");
1603
1604 int dataSize = 0;
1605 DataVariationType resultVariationType;
1606 if ((vecVariationType == GENERAL) || (matVariationType == GENERAL))
1607 {
1608 resultVariationType = GENERAL;
1609 dataSize = resultExtents[i];
1610 }
1611 else if ((matVariationType == CONSTANT) && (vecVariationType == CONSTANT))
1612 {
1613 resultVariationType = CONSTANT;
1614 dataSize = 1;
1615 }
1616 else if ((matVariationType == MODULAR) && (vecVariationType == CONSTANT))
1617 {
1618 resultVariationType = MODULAR;
1619 dataSize = matData.getVariationModulus(i);
1620 }
1621 else if ((matVariationType == CONSTANT) && (vecVariationType == MODULAR))
1622 {
1623 resultVariationType = MODULAR;
1624 dataSize = matData.getVariationModulus(i);
1625 }
1626 else
1627 {
1628 // both are modular. We allow this if they agree on the modulus
1629 auto matModulus = matData.getVariationModulus(i);
1630 auto vecModulus = vecData.getVariationModulus(i);
1631 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");
1632 resultVariationType = MODULAR;
1633 dataSize = matModulus;
1634 }
1635 resultVariationTypes[i] = resultVariationType;
1636
1637 if (resultVariationType != CONSTANT)
1638 {
1639 resultActiveDims[resultNumActiveDims] = i;
1640 resultDataDims[resultNumActiveDims] = dataSize;
1641 resultNumActiveDims++;
1642 }
1643 }
1644 // for the final dimension, the variation type is always GENERAL
1645 // (Some combinations, e.g. CONSTANT/CONSTANT *would* generate a CONSTANT result, but constant matrices don't make a lot of sense beyond 1x1 matrices…)
1646 resultActiveDims[resultNumActiveDims] = resultRank - 1;
1647 resultDataDims[resultNumActiveDims] = rows;
1648 resultNumActiveDims++;
1649
1650 for (int i=resultRank; i<7; i++)
1651 {
1652 resultVariationTypes[i] = CONSTANT;
1653 resultExtents[i] = 1;
1654 }
1655 resultVariationTypes[resultRank-1] = GENERAL;
1656 resultExtents[resultRank-1] = rows;
1657
1658 ScalarView<DataScalar,DeviceType> data;
1659 if (resultNumActiveDims == 1)
1660 {
1661 data = matData.allocateDynRankViewMatchingUnderlying(resultDataDims[0]);
1662 }
1663 else if (resultNumActiveDims == 2)
1664 {
1665 data = matData.allocateDynRankViewMatchingUnderlying(resultDataDims[0], resultDataDims[1]);
1666 }
1667 else if (resultNumActiveDims == 3)
1668 {
1669 data = matData.allocateDynRankViewMatchingUnderlying(resultDataDims[0], resultDataDims[1], resultDataDims[2]);
1670 }
1671 else if (resultNumActiveDims == 4)
1672 {
1673 data = matData.allocateDynRankViewMatchingUnderlying(resultDataDims[0], resultDataDims[1], resultDataDims[2],
1674 resultDataDims[3]);
1675 }
1676 else if (resultNumActiveDims == 5)
1677 {
1678 data = matData.allocateDynRankViewMatchingUnderlying(resultDataDims[0], resultDataDims[1], resultDataDims[2],
1679 resultDataDims[3], resultDataDims[4]);
1680 }
1681 else if (resultNumActiveDims == 6)
1682 {
1683 data = matData.allocateDynRankViewMatchingUnderlying(resultDataDims[0], resultDataDims[1], resultDataDims[2],
1684 resultDataDims[3], resultDataDims[4], resultDataDims[5]);
1685 }
1686 else // resultNumActiveDims == 7
1687 {
1688 data = matData.allocateDynRankViewMatchingUnderlying(resultDataDims[0], resultDataDims[1], resultDataDims[2],
1689 resultDataDims[3], resultDataDims[4], resultDataDims[5], resultDataDims[6]);
1690 }
1691
1692 return Data<DataScalar,DeviceType>(data,resultRank,resultExtents,resultVariationTypes);
1693 }
1694
1696 template<int rank>
1697 enable_if_t<(rank!=1) && (rank!=7), Kokkos::MDRangePolicy<typename DeviceType::execution_space,Kokkos::Rank<rank>> >
1699 {
1700 using ExecutionSpace = typename DeviceType::execution_space;
1701 Kokkos::Array<int,rank> startingOrdinals;
1702 Kokkos::Array<int,rank> extents;
1703
1704 for (int d=0; d<rank; d++)
1705 {
1706 startingOrdinals[d] = 0;
1707 extents[d] = getDataExtent(d);
1708 }
1709 auto policy = Kokkos::MDRangePolicy<ExecutionSpace,Kokkos::Rank<rank>>(startingOrdinals,extents);
1710 return policy;
1711 }
1712
1714 template<int rank>
1715 enable_if_t<rank==7, Kokkos::MDRangePolicy<typename DeviceType::execution_space,Kokkos::Rank<6>> >
1717 {
1718 using ExecutionSpace = typename DeviceType::execution_space;
1719 Kokkos::Array<int,6> startingOrdinals;
1720 Kokkos::Array<int,6> extents;
1721
1722 for (int d=0; d<6; d++)
1723 {
1724 startingOrdinals[d] = 0;
1725 extents[d] = getDataExtent(d);
1726 }
1727 auto policy = Kokkos::MDRangePolicy<ExecutionSpace,Kokkos::Rank<6>>(startingOrdinals,extents);
1728 return policy;
1729 }
1730
1731 template<int rank>
1732 inline
1733 enable_if_t<rank==1, Kokkos::RangePolicy<typename DeviceType::execution_space> >
1735 {
1736 using ExecutionSpace = typename DeviceType::execution_space;
1737 Kokkos::RangePolicy<ExecutionSpace> policy(ExecutionSpace(),0,getDataExtent(0));
1738 return policy;
1739 }
1740
1742 Data shallowCopy(const int rank, const Kokkos::Array<int,7> &extents, const Kokkos::Array<DataVariationType,7> &variationTypes) const
1743 {
1744 switch (dataRank_)
1745 {
1746 case 1: return Data(rank, data1_, extents, variationTypes);
1747 case 2: return Data(rank, data2_, extents, variationTypes);
1748 case 3: return Data(rank, data3_, extents, variationTypes);
1749 case 4: return Data(rank, data4_, extents, variationTypes);
1750 case 5: return Data(rank, data5_, extents, variationTypes);
1751 case 6: return Data(rank, data6_, extents, variationTypes);
1752 case 7: return Data(rank, data7_, extents, variationTypes);
1753 default:
1754 INTREPID2_TEST_FOR_EXCEPTION(true, std::invalid_argument, "Unhandled dataRank_");
1755 }
1756 }
1757
1760 {
1761 const int D_DIM = A.rank() - 1;
1762 INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE(A.extent_int(D_DIM) != B.extent_int(D_DIM), std::invalid_argument, "A and B have different extents");
1763 const int vectorComponents = A.extent_int(D_DIM);
1764
1765 // shallow copy of this to avoid implicit references to this in call to getWritableEntry() below
1766 Data<DataScalar,DeviceType> thisData = *this;
1767
1768 using ExecutionSpace = typename DeviceType::execution_space;
1769 // note the use of getDataExtent() below: we only range over the possibly-distinct entries
1770 if (rank_ == 1) // contraction result rank; e.g., (P)
1771 {
1772 Kokkos::parallel_for("compute dot product", getDataExtent(0),
1773 KOKKOS_LAMBDA (const int &pointOrdinal) {
1774 auto & val = thisData.getWritableEntry(pointOrdinal);
1775 val = 0;
1776 for (int i=0; i<vectorComponents; i++)
1777 {
1778 val += A(pointOrdinal,i) * B(pointOrdinal,i);
1779 }
1780 });
1781 }
1782 else if (rank_ == 2) // contraction result rank; e.g., (C,P)
1783 {
1784 // typical case for e.g. gradient data: (C,P,D)
1785 auto policy = Kokkos::MDRangePolicy<ExecutionSpace,Kokkos::Rank<2>>({0,0},{getDataExtent(0),getDataExtent(1)});
1786 Kokkos::parallel_for("compute dot product", policy,
1787 KOKKOS_LAMBDA (const int &cellOrdinal, const int &pointOrdinal) {
1788 auto & val = thisData.getWritableEntry(cellOrdinal, pointOrdinal);
1789 val = 0;
1790 for (int i=0; i<vectorComponents; i++)
1791 {
1792 val += A(cellOrdinal,pointOrdinal,i) * B(cellOrdinal,pointOrdinal,i);
1793 }
1794 });
1795 }
1796 else if (rank_ == 3)
1797 {
1798 auto policy = Kokkos::MDRangePolicy<ExecutionSpace,Kokkos::Rank<3>>({0,0,0},{getDataExtent(0),getDataExtent(1),getDataExtent(2)});
1799 Kokkos::parallel_for("compute dot product", policy,
1800 KOKKOS_LAMBDA (const int &cellOrdinal, const int &pointOrdinal, const int &d) {
1801 auto & val = thisData.getWritableEntry(cellOrdinal, pointOrdinal,d);
1802 val = 0;
1803 for (int i=0; i<vectorComponents; i++)
1804 {
1805 val += A(cellOrdinal,pointOrdinal,d,i) * B(cellOrdinal,pointOrdinal,d,i);
1806 }
1807 });
1808 }
1809 else
1810 {
1811 // TODO: handle other cases
1812 INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE(true, std::logic_error, "rank not yet supported");
1813 }
1814 }
1815
1817 template<class BinaryOperator>
1818 void storeInPlaceCombination(const Data<DataScalar,DeviceType> &A, const Data<DataScalar,DeviceType> &B, BinaryOperator binaryOperator);
1819
1826
1833
1840
1847
1849 void storeMatVec( const Data<DataScalar,DeviceType> &matData, const Data<DataScalar,DeviceType> &vecData, const bool transposeMatrix = false )
1850 {
1851 // 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.)
1852 // TODO: check for invalidly shaped containers.
1853
1854 const int D1_DIM = matData.rank() - 2;
1855 const int D2_DIM = matData.rank() - 1;
1856
1857 const int matRows = matData.extent_int(D1_DIM);
1858 const int matCols = matData.extent_int(D2_DIM);
1859
1860 const int rows = transposeMatrix ? matCols : matRows;
1861 const int cols = transposeMatrix ? matRows : matCols;
1862
1863 // shallow copy of this to avoid implicit references to this in call to getWritableEntry() below
1864 Data<DataScalar,DeviceType> thisData = *this;
1865
1866 using ExecutionSpace = typename DeviceType::execution_space;
1867 // note the use of getDataExtent() below: we only range over the possibly-distinct entries
1868 if (rank_ == 3)
1869 {
1870 // typical case for e.g. gradient data: (C,P,D)
1871 auto policy = Kokkos::MDRangePolicy<ExecutionSpace,Kokkos::Rank<3>>({0,0,0},{getDataExtent(0),getDataExtent(1),rows});
1872 Kokkos::parallel_for("compute mat-vec", policy,
1873 KOKKOS_LAMBDA (const int &cellOrdinal, const int &pointOrdinal, const int &i) {
1874 auto & val_i = thisData.getWritableEntry(cellOrdinal, pointOrdinal, i);
1875 val_i = 0;
1876 for (int j=0; j<cols; j++)
1877 {
1878 const auto & mat_ij = transposeMatrix ? matData(cellOrdinal,pointOrdinal,j,i) : matData(cellOrdinal,pointOrdinal,i,j);
1879 val_i += mat_ij * vecData(cellOrdinal,pointOrdinal,j);
1880 }
1881 });
1882 }
1883 else if (rank_ == 2)
1884 {
1885 //
1886 auto policy = Kokkos::MDRangePolicy<ExecutionSpace,Kokkos::Rank<2>>({0,0},{getDataExtent(0),rows});
1887 Kokkos::parallel_for("compute mat-vec", policy,
1888 KOKKOS_LAMBDA (const int &vectorOrdinal, const int &i) {
1889 auto & val_i = thisData.getWritableEntry(vectorOrdinal, i);
1890 val_i = 0;
1891 for (int j=0; j<cols; j++)
1892 {
1893 const auto & mat_ij = transposeMatrix ? matData(vectorOrdinal,j,i) : matData(vectorOrdinal,i,j);
1894 val_i += mat_ij * vecData(vectorOrdinal,j);
1895 }
1896 });
1897 }
1898 else if (rank_ == 1)
1899 {
1900 // single-vector case
1901 Kokkos::RangePolicy<ExecutionSpace> policy(0,rows);
1902 Kokkos::parallel_for("compute mat-vec", policy,
1903 KOKKOS_LAMBDA (const int &i) {
1904 auto & val_i = thisData.getWritableEntry(i);
1905 val_i = 0;
1906 for (int j=0; j<cols; j++)
1907 {
1908 const auto & mat_ij = transposeMatrix ? matData(j,i) : matData(i,j);
1909 val_i += mat_ij * vecData(j);
1910 }
1911 });
1912 }
1913 else
1914 {
1915 // TODO: handle other cases
1916 INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE(true, std::logic_error, "rank not yet supported");
1917 }
1918 }
1919
1926 void storeMatMat( const bool transposeA, const Data<DataScalar,DeviceType> &A_MatData, const bool transposeB, const Data<DataScalar,DeviceType> &B_MatData )
1927 {
1928 // 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.)
1929 // TODO: check for invalidly shaped containers.
1930
1931 // we treat last two logical dimensions of matData as the matrix; last dimension of vecData as the vector
1932 INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE(A_MatData.rank() != B_MatData.rank(), std::invalid_argument, "AmatData and BmatData have incompatible ranks");
1933
1934 const int D1_DIM = A_MatData.rank() - 2;
1935 const int D2_DIM = A_MatData.rank() - 1;
1936
1937 const int A_rows = A_MatData.extent_int(D1_DIM);
1938 const int A_cols = A_MatData.extent_int(D2_DIM);
1939 const int B_rows = B_MatData.extent_int(D1_DIM);
1940 const int B_cols = B_MatData.extent_int(D2_DIM);
1941
1942 const int leftRows = transposeA ? A_cols : A_rows;
1943 const int leftCols = transposeA ? A_rows : A_cols;
1944 const int rightCols = transposeB ? B_rows : B_cols;
1945
1946#ifdef INTREPID2_HAVE_DEBUG
1947 const int rightRows = transposeB ? B_cols : B_rows;
1948 INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE(leftCols != rightRows, std::invalid_argument, "inner dimensions do not match");
1949#endif
1950
1951 // shallow copy of this to avoid implicit references to this in call to getWritableEntry() below
1952 Data<DataScalar,DeviceType> thisData = *this;
1953
1954 using ExecutionSpace = typename DeviceType::execution_space;
1955
1956 const int diagonalStart = (variationType_[D1_DIM] == BLOCK_PLUS_DIAGONAL) ? blockPlusDiagonalLastNonDiagonal_ + 1 : leftRows;
1957 // note the use of getDataExtent() below: we only range over the possibly-distinct entries
1958 if (rank_ == 3)
1959 {
1960 // (C,D,D), say
1961 auto policy = Kokkos::RangePolicy<ExecutionSpace>(0,getDataExtent(0));
1962 Kokkos::parallel_for("compute mat-mat", policy,
1963 KOKKOS_LAMBDA (const int &matrixOrdinal) {
1964 for (int i=0; i<diagonalStart; i++)
1965 {
1966 for (int j=0; j<rightCols; j++)
1967 {
1968 auto & val_ij = thisData.getWritableEntry(matrixOrdinal, i, j);
1969 val_ij = 0;
1970 for (int k=0; k<leftCols; k++)
1971 {
1972 const auto & left = transposeA ? A_MatData(matrixOrdinal,k,i) : A_MatData(matrixOrdinal,i,k);
1973 const auto & right = transposeB ? B_MatData(matrixOrdinal,j,k) : B_MatData(matrixOrdinal,k,j);
1974 val_ij += left * right;
1975 }
1976 }
1977 }
1978 for (int i=diagonalStart; i<leftRows; i++)
1979 {
1980 auto & val_ii = thisData.getWritableEntry(matrixOrdinal, i, i);
1981 const auto & left = A_MatData(matrixOrdinal,i,i);
1982 const auto & right = B_MatData(matrixOrdinal,i,i);
1983 val_ii = left * right;
1984 }
1985 });
1986 }
1987 else if (rank_ == 4)
1988 {
1989 // (C,P,D,D), perhaps
1990 auto policy = Kokkos::MDRangePolicy<ExecutionSpace, Kokkos::Rank<2> >({0,0},{getDataExtent(0),getDataExtent(1)});
1991 if (underlyingMatchesLogical_) // receiving data object is completely expanded
1992 {
1993 Kokkos::parallel_for("compute mat-mat", policy,
1994 KOKKOS_LAMBDA (const int &cellOrdinal, const int &pointOrdinal) {
1995 for (int i=0; i<leftRows; i++)
1996 {
1997 for (int j=0; j<rightCols; j++)
1998 {
1999 auto & val_ij = thisData.getUnderlyingView4()(cellOrdinal,pointOrdinal, i, j);
2000 val_ij = 0;
2001 for (int k=0; k<leftCols; k++)
2002 {
2003 const auto & left = transposeA ? A_MatData(cellOrdinal,pointOrdinal,k,i) : A_MatData(cellOrdinal,pointOrdinal,i,k);
2004 const auto & right = transposeB ? B_MatData(cellOrdinal,pointOrdinal,j,k) : B_MatData(cellOrdinal,pointOrdinal,k,j);
2005 val_ij += left * right;
2006 }
2007 }
2008 }
2009 });
2010 }
2011 else
2012 {
2013 Kokkos::parallel_for("compute mat-mat", policy,
2014 KOKKOS_LAMBDA (const int &cellOrdinal, const int &pointOrdinal) {
2015 for (int i=0; i<diagonalStart; i++)
2016 {
2017 for (int j=0; j<rightCols; j++)
2018 {
2019 auto & val_ij = thisData.getWritableEntry(cellOrdinal,pointOrdinal, i, j);
2020 val_ij = 0;
2021 for (int k=0; k<leftCols; k++)
2022 {
2023 const auto & left = transposeA ? A_MatData(cellOrdinal,pointOrdinal,k,i) : A_MatData(cellOrdinal,pointOrdinal,i,k);
2024 const auto & right = transposeB ? B_MatData(cellOrdinal,pointOrdinal,j,k) : B_MatData(cellOrdinal,pointOrdinal,k,j);
2025 val_ij += left * right;
2026 }
2027 }
2028 }
2029 for (int i=diagonalStart; i<leftRows; i++)
2030 {
2031 auto & val_ii = thisData.getWritableEntry(cellOrdinal,pointOrdinal, i, i);
2032 const auto & left = A_MatData(cellOrdinal,pointOrdinal,i,i);
2033 const auto & right = B_MatData(cellOrdinal,pointOrdinal,i,i);
2034 val_ii = left * right;
2035 }
2036 });
2037 }
2038 }
2039 else
2040 {
2041 // TODO: handle other cases
2042 INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE(true, std::logic_error, "rank not yet supported");
2043 }
2044 }
2045
2047 KOKKOS_INLINE_FUNCTION constexpr bool isValid() const
2048 {
2049 return extents_[0] > 0;
2050 }
2051
2053 KOKKOS_INLINE_FUNCTION
2054 unsigned rank() const
2055 {
2056 return rank_;
2057 }
2058
2065 void setExtent(const ordinal_type &d, const ordinal_type &newExtent)
2066 {
2067 INTREPID2_TEST_FOR_EXCEPTION(variationType_[d] == BLOCK_PLUS_DIAGONAL, std::invalid_argument, "setExtent is not supported for BLOCK_PLUS_DIAGONAL dimensions");
2068
2069 if (variationType_[d] == MODULAR)
2070 {
2071 bool dividesEvenly = ((newExtent / variationModulus_[d]) * variationModulus_[d] == newExtent);
2072 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");
2073 }
2074
2075 if ((newExtent != extents_[d]) && (variationType_[d] == GENERAL))
2076 {
2077 // then we need to resize; let's determine the full set of new extents
2078 std::vector<ordinal_type> newExtents(dataRank_,-1);
2079 for (int r=0; r<dataRank_; r++)
2080 {
2081 if (activeDims_[r] == d)
2082 {
2083 // this is the changed dimension
2084 newExtents[r] = newExtent;
2085 }
2086 else
2087 {
2088 // unchanged; copy from existing
2089 newExtents[r] = getUnderlyingViewExtent(r);
2090 }
2091 }
2092
2093 switch (dataRank_)
2094 {
2095 case 1: Kokkos::resize(data1_,newExtents[0]);
2096 break;
2097 case 2: Kokkos::resize(data2_,newExtents[0],newExtents[1]);
2098 break;
2099 case 3: Kokkos::resize(data3_,newExtents[0],newExtents[1],newExtents[2]);
2100 break;
2101 case 4: Kokkos::resize(data4_,newExtents[0],newExtents[1],newExtents[2],newExtents[3]);
2102 break;
2103 case 5: Kokkos::resize(data5_,newExtents[0],newExtents[1],newExtents[2],newExtents[3],newExtents[4]);
2104 break;
2105 case 6: Kokkos::resize(data6_,newExtents[0],newExtents[1],newExtents[2],newExtents[3],newExtents[4],newExtents[5]);
2106 break;
2107 case 7: Kokkos::resize(data7_,newExtents[0],newExtents[1],newExtents[2],newExtents[3],newExtents[4],newExtents[5],newExtents[6]);
2108 break;
2109 default: INTREPID2_TEST_FOR_EXCEPTION(true, std::logic_error, "Unexpected dataRank_ value");
2110 }
2111 }
2112
2113 extents_[d] = newExtent;
2114 }
2115
2117 KOKKOS_INLINE_FUNCTION
2119 {
2120 return underlyingMatchesLogical_;
2121 }
2122 };
2123
2124 template<class DataScalar, typename DeviceType>
2125 KOKKOS_INLINE_FUNCTION constexpr unsigned rank(const Data<DataScalar, DeviceType>& D) {
2126 return D.rank();
2127 }
2128}
2129
2130// we do ETI for doubles and default ExecutionSpace's device_type
2132
2133#include "Intrepid2_DataDef.hpp"
2134
2135#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 ...
static Data< DataScalar, DeviceType > allocateDotProductResult(const Data< DataScalar, DeviceType > &A, const Data< DataScalar, DeviceType > &B)
Data()
default constructor (empty data)
static Data< DataScalar, DeviceType > allocateMatVecResult(const Data< DataScalar, DeviceType > &matData, const Data< DataScalar, DeviceType > &vecData, const bool transposeMatrix=false)
void storeMatVec(const Data< DataScalar, DeviceType > &matData, const Data< DataScalar, DeviceType > &vecData, const bool transposeMatrix=false)
Places the result of a matrix-vector multiply corresponding to the two provided containers into this ...
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....
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 > allocateContractionResult(const Data< DataScalar, DeviceType > &A, const Data< DataScalar, DeviceType > &B, const int &numContractionDims)
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.
void storeDotProduct(const Data< DataScalar, DeviceType > &A, const Data< DataScalar, DeviceType > &B)
Places the result of a contraction along the final dimension of A and B into this 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,...