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