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 
1531  static Data<DataScalar,DeviceType> allocateMatVecResult( const Data<DataScalar,DeviceType> &matData, const Data<DataScalar,DeviceType> &vecData, const bool transposeMatrix = false )
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 
1537  const int D1_DIM = matData.rank() - 2;
1538  const int D2_DIM = matData.rank() - 1;
1539 
1540  const int matRows = matData.extent_int(D1_DIM);
1541  const int matCols = matData.extent_int(D2_DIM);
1542 
1543  const int rows = transposeMatrix ? matCols : matRows;
1544  const int cols = transposeMatrix ? matRows : matCols;
1545 
1546  const int resultRank = vecData.rank();
1547 
1548  INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE(cols != vecDim, std::invalid_argument, "matData column count != vecData dimension");
1549 
1550  Kokkos::Array<int,7> resultExtents; // logical extents
1551  Kokkos::Array<DataVariationType,7> resultVariationTypes; // for each dimension, whether the data varies in that dimension
1552  auto vecVariationTypes = vecData.getVariationTypes();
1553  auto matVariationTypes = matData.getVariationTypes();
1554 
1555  Kokkos::Array<int,7> resultActiveDims;
1556  Kokkos::Array<int,7> resultDataDims;
1557  int resultNumActiveDims = 0; // how many of the 7 entries are actually filled in
1558  // the following loop is over the dimensions *prior* to matrix/vector dimensions
1559  for (int i=0; i<resultRank-1; i++)
1560  {
1561  resultExtents[i] = vecData.extent_int(i);
1562  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");
1563 
1564  const DataVariationType &vecVariationType = vecVariationTypes[i];
1565  const DataVariationType &matVariationType = matVariationTypes[i];
1566 
1567  // BLOCK_PLUS_DIAGONAL should only occur in matData, and only in the matrix (final) dimensions
1568  INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE(vecVariationType == BLOCK_PLUS_DIAGONAL, std::invalid_argument, "unsupported variationType");
1569  INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE(matVariationType == BLOCK_PLUS_DIAGONAL, std::invalid_argument, "unsupported variationType");
1570 
1571  int dataSize = 0;
1572  DataVariationType resultVariationType;
1573  if ((vecVariationType == GENERAL) || (matVariationType == GENERAL))
1574  {
1575  resultVariationType = GENERAL;
1576  dataSize = resultExtents[i];
1577  }
1578  else if ((matVariationType == CONSTANT) && (vecVariationType == CONSTANT))
1579  {
1580  resultVariationType = CONSTANT;
1581  dataSize = 1;
1582  }
1583  else if ((matVariationType == MODULAR) && (vecVariationType == CONSTANT))
1584  {
1585  resultVariationType = MODULAR;
1586  dataSize = matData.getVariationModulus(i);
1587  }
1588  else if ((matVariationType == CONSTANT) && (vecVariationType == MODULAR))
1589  {
1590  resultVariationType = MODULAR;
1591  dataSize = matData.getVariationModulus(i);
1592  }
1593  else
1594  {
1595  // both are modular. We allow this if they agree on the modulus
1596  auto matModulus = matData.getVariationModulus(i);
1597  auto vecModulus = vecData.getVariationModulus(i);
1598  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");
1599  resultVariationType = MODULAR;
1600  dataSize = matModulus;
1601  }
1602  resultVariationTypes[i] = resultVariationType;
1603 
1604  if (resultVariationType != CONSTANT)
1605  {
1606  resultActiveDims[resultNumActiveDims] = i;
1607  resultDataDims[resultNumActiveDims] = dataSize;
1608  resultNumActiveDims++;
1609  }
1610  }
1611  // for the final dimension, the variation type is always GENERAL
1612  // (Some combinations, e.g. CONSTANT/CONSTANT *would* generate a CONSTANT result, but constant matrices don't make a lot of sense beyond 1x1 matrices…)
1613  resultVariationTypes[resultNumActiveDims] = GENERAL;
1614  resultActiveDims[resultNumActiveDims] = resultRank - 1;
1615  resultDataDims[resultNumActiveDims] = rows;
1616  resultExtents[resultRank-1] = rows;
1617  resultNumActiveDims++;
1618 
1619  for (int i=resultRank; i<7; i++)
1620  {
1621  resultVariationTypes[i] = CONSTANT;
1622  resultExtents[i] = 1;
1623  }
1624 
1625  ScalarView<DataScalar,DeviceType> data;
1626  if (resultNumActiveDims == 1)
1627  {
1628  data = matData.allocateDynRankViewMatchingUnderlying(resultDataDims[0]);
1629  }
1630  else if (resultNumActiveDims == 2)
1631  {
1632  data = matData.allocateDynRankViewMatchingUnderlying(resultDataDims[0], resultDataDims[1]);
1633  }
1634  else if (resultNumActiveDims == 3)
1635  {
1636  data = matData.allocateDynRankViewMatchingUnderlying(resultDataDims[0], resultDataDims[1], resultDataDims[2]);
1637  }
1638  else if (resultNumActiveDims == 4)
1639  {
1640  data = matData.allocateDynRankViewMatchingUnderlying(resultDataDims[0], resultDataDims[1], resultDataDims[2],
1641  resultDataDims[3]);
1642  }
1643  else if (resultNumActiveDims == 5)
1644  {
1645  data = matData.allocateDynRankViewMatchingUnderlying(resultDataDims[0], resultDataDims[1], resultDataDims[2],
1646  resultDataDims[3], resultDataDims[4]);
1647  }
1648  else if (resultNumActiveDims == 6)
1649  {
1650  data = matData.allocateDynRankViewMatchingUnderlying(resultDataDims[0], resultDataDims[1], resultDataDims[2],
1651  resultDataDims[3], resultDataDims[4], resultDataDims[5]);
1652  }
1653  else // resultNumActiveDims == 7
1654  {
1655  data = matData.allocateDynRankViewMatchingUnderlying(resultDataDims[0], resultDataDims[1], resultDataDims[2],
1656  resultDataDims[3], resultDataDims[4], resultDataDims[5], resultDataDims[6]);
1657  }
1658 
1659  return Data<DataScalar,DeviceType>(data,resultRank,resultExtents,resultVariationTypes);
1660  }
1661 
1663  template<int rank>
1664  enable_if_t<(rank!=1) && (rank!=7), Kokkos::MDRangePolicy<typename DeviceType::execution_space,Kokkos::Rank<rank>> >
1666  {
1667  using ExecutionSpace = typename DeviceType::execution_space;
1668  Kokkos::Array<int,rank> startingOrdinals;
1669  Kokkos::Array<int,rank> extents;
1670 
1671  for (int d=0; d<rank; d++)
1672  {
1673  startingOrdinals[d] = 0;
1674  extents[d] = getDataExtent(d);
1675  }
1676  auto policy = Kokkos::MDRangePolicy<ExecutionSpace,Kokkos::Rank<rank>>(startingOrdinals,extents);
1677  return policy;
1678  }
1679 
1681  template<int rank>
1682  enable_if_t<rank==7, Kokkos::MDRangePolicy<typename DeviceType::execution_space,Kokkos::Rank<6>> >
1684  {
1685  using ExecutionSpace = typename DeviceType::execution_space;
1686  Kokkos::Array<int,6> startingOrdinals;
1687  Kokkos::Array<int,6> extents;
1688 
1689  for (int d=0; d<6; d++)
1690  {
1691  startingOrdinals[d] = 0;
1692  extents[d] = getDataExtent(d);
1693  }
1694  auto policy = Kokkos::MDRangePolicy<ExecutionSpace,Kokkos::Rank<6>>(startingOrdinals,extents);
1695  return policy;
1696  }
1697 
1698  template<int rank>
1699  inline
1700  enable_if_t<rank==1, Kokkos::RangePolicy<typename DeviceType::execution_space> >
1702  {
1703  using ExecutionSpace = typename DeviceType::execution_space;
1704  Kokkos::RangePolicy<ExecutionSpace> policy(ExecutionSpace(),0,getDataExtent(0));
1705  return policy;
1706  }
1707 
1709  Data shallowCopy(const int rank, const Kokkos::Array<int,7> &extents, const Kokkos::Array<DataVariationType,7> &variationTypes) const
1710  {
1711  switch (dataRank_)
1712  {
1713  case 1: return Data(rank, data1_, extents, variationTypes);
1714  case 2: return Data(rank, data2_, extents, variationTypes);
1715  case 3: return Data(rank, data3_, extents, variationTypes);
1716  case 4: return Data(rank, data4_, extents, variationTypes);
1717  case 5: return Data(rank, data5_, extents, variationTypes);
1718  case 6: return Data(rank, data6_, extents, variationTypes);
1719  case 7: return Data(rank, data7_, extents, variationTypes);
1720  default:
1721  INTREPID2_TEST_FOR_EXCEPTION(true, std::invalid_argument, "Unhandled dataRank_");
1722  }
1723  }
1724 
1726  template<class BinaryOperator>
1727  void storeInPlaceCombination(const Data<DataScalar,DeviceType> &A, const Data<DataScalar,DeviceType> &B, BinaryOperator binaryOperator);
1728 
1731  {
1733  storeInPlaceCombination(A, B, sum);
1734  }
1735 
1738  {
1740  storeInPlaceCombination(A, B, product);
1741  }
1742 
1745  {
1747  storeInPlaceCombination(A, B, difference);
1748  }
1749 
1752  {
1754  storeInPlaceCombination(A, B, quotient);
1755  }
1756 
1758  void storeMatVec( const Data<DataScalar,DeviceType> &matData, const Data<DataScalar,DeviceType> &vecData, const bool transposeMatrix = false )
1759  {
1760  // 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.)
1761  // TODO: check for invalidly shaped containers.
1762 
1763  const int D1_DIM = matData.rank() - 2;
1764  const int D2_DIM = matData.rank() - 1;
1765 
1766  const int matRows = matData.extent_int(D1_DIM);
1767  const int matCols = matData.extent_int(D2_DIM);
1768 
1769  const int rows = transposeMatrix ? matCols : matRows;
1770  const int cols = transposeMatrix ? matRows : matCols;
1771 
1772  // shallow copy of this to avoid implicit references to this in call to getWritableEntry() below
1773  Data<DataScalar,DeviceType> thisData = *this;
1774 
1775  using ExecutionSpace = typename DeviceType::execution_space;
1776  // note the use of getDataExtent() below: we only range over the possibly-distinct entries
1777  if (rank_ == 3)
1778  {
1779  // typical case for e.g. gradient data: (C,P,D)
1780  auto policy = Kokkos::MDRangePolicy<ExecutionSpace,Kokkos::Rank<3>>({0,0,0},{getDataExtent(0),getDataExtent(1),rows});
1781  Kokkos::parallel_for("compute mat-vec", policy,
1782  KOKKOS_LAMBDA (const int &cellOrdinal, const int &pointOrdinal, const int &i) {
1783  auto & val_i = thisData.getWritableEntry(cellOrdinal, pointOrdinal, i);
1784  val_i = 0;
1785  for (int j=0; j<cols; j++)
1786  {
1787  const auto & mat_ij = transposeMatrix ? matData(cellOrdinal,pointOrdinal,j,i) : matData(cellOrdinal,pointOrdinal,i,j);
1788  val_i += mat_ij * vecData(cellOrdinal,pointOrdinal,j);
1789  }
1790  });
1791  }
1792  else if (rank_ == 2)
1793  {
1794  //
1795  auto policy = Kokkos::MDRangePolicy<ExecutionSpace,Kokkos::Rank<2>>({0,0},{getDataExtent(0),rows});
1796  Kokkos::parallel_for("compute mat-vec", policy,
1797  KOKKOS_LAMBDA (const int &vectorOrdinal, const int &i) {
1798  auto & val_i = thisData.getWritableEntry(vectorOrdinal, i);
1799  val_i = 0;
1800  for (int j=0; j<cols; j++)
1801  {
1802  const auto & mat_ij = transposeMatrix ? matData(vectorOrdinal,j,i) : matData(vectorOrdinal,i,j);
1803  val_i += mat_ij * vecData(vectorOrdinal,j);
1804  }
1805  });
1806  }
1807  else if (rank_ == 1)
1808  {
1809  // single-vector case
1810  Kokkos::RangePolicy<ExecutionSpace> policy(0,rows);
1811  Kokkos::parallel_for("compute mat-vec", policy,
1812  KOKKOS_LAMBDA (const int &i) {
1813  auto & val_i = thisData.getWritableEntry(i);
1814  val_i = 0;
1815  for (int j=0; j<cols; j++)
1816  {
1817  const auto & mat_ij = transposeMatrix ? matData(j,i) : matData(i,j);
1818  val_i += mat_ij * vecData(j);
1819  }
1820  });
1821  }
1822  else
1823  {
1824  // TODO: handle other cases
1825  INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE(true, std::logic_error, "rank not yet supported");
1826  }
1827  }
1828 
1835  void storeMatMat( const bool transposeA, const Data<DataScalar,DeviceType> &A_MatData, const bool transposeB, const Data<DataScalar,DeviceType> &B_MatData )
1836  {
1837  // 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.)
1838  // TODO: check for invalidly shaped containers.
1839 
1840  // we treat last two logical dimensions of matData as the matrix; last dimension of vecData as the vector
1841  INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE(A_MatData.rank() != B_MatData.rank(), std::invalid_argument, "AmatData and BmatData have incompatible ranks");
1842 
1843  const int D1_DIM = A_MatData.rank() - 2;
1844  const int D2_DIM = A_MatData.rank() - 1;
1845 
1846  const int A_rows = A_MatData.extent_int(D1_DIM);
1847  const int A_cols = A_MatData.extent_int(D2_DIM);
1848  const int B_rows = B_MatData.extent_int(D1_DIM);
1849  const int B_cols = B_MatData.extent_int(D2_DIM);
1850 
1851  const int leftRows = transposeA ? A_cols : A_rows;
1852  const int leftCols = transposeA ? A_rows : A_cols;
1853  const int rightCols = transposeB ? B_rows : B_cols;
1854 
1855 #ifdef INTREPID2_HAVE_DEBUG
1856  const int rightRows = transposeB ? B_cols : B_rows;
1857  INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE(leftCols != rightRows, std::invalid_argument, "inner dimensions do not match");
1858 #endif
1859 
1860  // shallow copy of this to avoid implicit references to this in call to getWritableEntry() below
1861  Data<DataScalar,DeviceType> thisData = *this;
1862 
1863  using ExecutionSpace = typename DeviceType::execution_space;
1864 
1865  const int diagonalStart = (variationType_[D1_DIM] == BLOCK_PLUS_DIAGONAL) ? blockPlusDiagonalLastNonDiagonal_ + 1 : leftRows;
1866  // note the use of getDataExtent() below: we only range over the possibly-distinct entries
1867  if (rank_ == 3)
1868  {
1869  // (C,D,D), say
1870  auto policy = Kokkos::RangePolicy<ExecutionSpace>(0,getDataExtent(0));
1871  Kokkos::parallel_for("compute mat-mat", policy,
1872  KOKKOS_LAMBDA (const int &matrixOrdinal) {
1873  for (int i=0; i<diagonalStart; i++)
1874  {
1875  for (int j=0; j<rightCols; j++)
1876  {
1877  auto & val_ij = thisData.getWritableEntry(matrixOrdinal, i, j);
1878  val_ij = 0;
1879  for (int k=0; k<leftCols; k++)
1880  {
1881  const auto & left = transposeA ? A_MatData(matrixOrdinal,k,i) : A_MatData(matrixOrdinal,i,k);
1882  const auto & right = transposeB ? B_MatData(matrixOrdinal,j,k) : B_MatData(matrixOrdinal,k,j);
1883  val_ij += left * right;
1884  }
1885  }
1886  }
1887  for (int i=diagonalStart; i<leftRows; i++)
1888  {
1889  auto & val_ii = thisData.getWritableEntry(matrixOrdinal, i, i);
1890  const auto & left = A_MatData(matrixOrdinal,i,i);
1891  const auto & right = B_MatData(matrixOrdinal,i,i);
1892  val_ii = left * right;
1893  }
1894  });
1895  }
1896  else if (rank_ == 4)
1897  {
1898  // (C,P,D,D), perhaps
1899  auto policy = Kokkos::MDRangePolicy<ExecutionSpace, Kokkos::Rank<2> >({0,0},{getDataExtent(0),getDataExtent(1)});
1900  if (underlyingMatchesLogical_) // receiving data object is completely expanded
1901  {
1902  Kokkos::parallel_for("compute mat-mat", policy,
1903  KOKKOS_LAMBDA (const int &cellOrdinal, const int &pointOrdinal) {
1904  for (int i=0; i<leftCols; i++)
1905  {
1906  for (int j=0; j<rightCols; j++)
1907  {
1908  auto & val_ij = thisData.getUnderlyingView4()(cellOrdinal,pointOrdinal, i, j);
1909  val_ij = 0;
1910  for (int k=0; k<leftCols; k++)
1911  {
1912  const auto & left = transposeA ? A_MatData(cellOrdinal,pointOrdinal,k,i) : A_MatData(cellOrdinal,pointOrdinal,i,k);
1913  const auto & right = transposeB ? B_MatData(cellOrdinal,pointOrdinal,j,k) : B_MatData(cellOrdinal,pointOrdinal,k,j);
1914  val_ij += left * right;
1915  }
1916  }
1917  }
1918  });
1919  }
1920  else
1921  {
1922  Kokkos::parallel_for("compute mat-mat", policy,
1923  KOKKOS_LAMBDA (const int &cellOrdinal, const int &pointOrdinal) {
1924  for (int i=0; i<diagonalStart; i++)
1925  {
1926  for (int j=0; j<rightCols; j++)
1927  {
1928  auto & val_ij = thisData.getWritableEntry(cellOrdinal,pointOrdinal, i, j);
1929  val_ij = 0;
1930  for (int k=0; k<leftCols; k++)
1931  {
1932  const auto & left = transposeA ? A_MatData(cellOrdinal,pointOrdinal,k,i) : A_MatData(cellOrdinal,pointOrdinal,i,k);
1933  const auto & right = transposeB ? B_MatData(cellOrdinal,pointOrdinal,j,k) : B_MatData(cellOrdinal,pointOrdinal,k,j);
1934  val_ij += left * right;
1935  }
1936  }
1937  }
1938  for (int i=diagonalStart; i<leftRows; i++)
1939  {
1940  auto & val_ii = thisData.getWritableEntry(cellOrdinal,pointOrdinal, i, i);
1941  const auto & left = A_MatData(cellOrdinal,pointOrdinal,i,i);
1942  const auto & right = B_MatData(cellOrdinal,pointOrdinal,i,i);
1943  val_ii = left * right;
1944  }
1945  });
1946  }
1947  }
1948  else
1949  {
1950  // TODO: handle other cases
1951  INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE(true, std::logic_error, "rank not yet supported");
1952  }
1953  }
1954 
1956  KOKKOS_INLINE_FUNCTION constexpr bool isValid() const
1957  {
1958  return extents_[0] > 0;
1959  }
1960 
1962  KOKKOS_INLINE_FUNCTION
1963  unsigned rank() const
1964  {
1965  return rank_;
1966  }
1967 
1974  void setExtent(const ordinal_type &d, const ordinal_type &newExtent)
1975  {
1976  INTREPID2_TEST_FOR_EXCEPTION(variationType_[d] == BLOCK_PLUS_DIAGONAL, std::invalid_argument, "setExtent is not supported for BLOCK_PLUS_DIAGONAL dimensions");
1977 
1978  if (variationType_[d] == MODULAR)
1979  {
1980  bool dividesEvenly = ((newExtent / variationModulus_[d]) * variationModulus_[d] == newExtent);
1981  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");
1982  }
1983 
1984  if ((newExtent != extents_[d]) && (variationType_[d] == GENERAL))
1985  {
1986  // then we need to resize; let's determine the full set of new extents
1987  std::vector<ordinal_type> newExtents(dataRank_,-1);
1988  for (int r=0; r<dataRank_; r++)
1989  {
1990  if (activeDims_[r] == d)
1991  {
1992  // this is the changed dimension
1993  newExtents[r] = newExtent;
1994  }
1995  else
1996  {
1997  // unchanged; copy from existing
1998  newExtents[r] = getUnderlyingViewExtent(r);
1999  }
2000  }
2001 
2002  switch (dataRank_)
2003  {
2004  case 1: Kokkos::resize(data1_,newExtents[0]);
2005  break;
2006  case 2: Kokkos::resize(data2_,newExtents[0],newExtents[1]);
2007  break;
2008  case 3: Kokkos::resize(data3_,newExtents[0],newExtents[1],newExtents[2]);
2009  break;
2010  case 4: Kokkos::resize(data4_,newExtents[0],newExtents[1],newExtents[2],newExtents[3]);
2011  break;
2012  case 5: Kokkos::resize(data5_,newExtents[0],newExtents[1],newExtents[2],newExtents[3],newExtents[4]);
2013  break;
2014  case 6: Kokkos::resize(data6_,newExtents[0],newExtents[1],newExtents[2],newExtents[3],newExtents[4],newExtents[5]);
2015  break;
2016  case 7: Kokkos::resize(data7_,newExtents[0],newExtents[1],newExtents[2],newExtents[3],newExtents[4],newExtents[5],newExtents[6]);
2017  break;
2018  default: INTREPID2_TEST_FOR_EXCEPTION(true, std::logic_error, "Unexpected dataRank_ value");
2019  }
2020  }
2021 
2022  extents_[d] = newExtent;
2023  }
2024 
2026  KOKKOS_INLINE_FUNCTION
2028  {
2029  return underlyingMatchesLogical_;
2030  }
2031  };
2032 
2033  template<class DataScalar, typename DeviceType>
2034  KOKKOS_INLINE_FUNCTION constexpr unsigned rank(const Data<DataScalar, DeviceType>& D) {
2035  return D.rank();
2036  }
2037 }
2038 
2039 // we do ETI for doubles and default ExecutionSpace's device_type
2041 
2042 #include "Intrepid2_DataDef.hpp"
2043 
2044 #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)
static Data< DataScalar, DeviceType > allocateMatVecResult(const Data< DataScalar, DeviceType > &matData, const Data< DataScalar, DeviceType > &vecData, const bool transposeMatrix=false)
void storeMatVec(const Data< DataScalar, DeviceType > &matData, const Data< DataScalar, DeviceType > &vecData, const bool transposeMatrix=false)
Places the result of a matrix-vector multiply corresponding to the two provided containers into this ...
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.
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.
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...