Intrepid2
Intrepid2_ArrayToolsDefTensor.hpp
Go to the documentation of this file.
1 // @HEADER
2 // *****************************************************************************
3 // Intrepid2 Package
4 //
5 // Copyright 2007 NTESS and the Intrepid2 contributors.
6 // SPDX-License-Identifier: BSD-3-Clause
7 // *****************************************************************************
8 // @HEADER
9 
16 #ifndef __INTREPID2_ARRAYTOOLS_DEF_TENSOR_HPP__
17 #define __INTREPID2_ARRAYTOOLS_DEF_TENSOR_HPP__
18 
19 namespace Intrepid2 {
20 
21  namespace FunctorArrayTools {
25  template < typename OutputViewType, typename leftInputViewType, typename rightInputViewType >
27  OutputViewType _output;
28  const leftInputViewType _leftInput;
29  const rightInputViewType _rightInput;
30  const bool _hasField, _isCrossProd3D;
31 
32  KOKKOS_INLINE_FUNCTION
33  F_crossProduct(OutputViewType output_,
34  leftInputViewType leftInput_,
35  rightInputViewType rightInput_,
36  const bool hasField_,
37  const bool isCrossProd3D_)
38  : _output(output_), _leftInput(leftInput_), _rightInput(rightInput_),
39  _hasField(hasField_), _isCrossProd3D(isCrossProd3D_) {}
40 
41  KOKKOS_INLINE_FUNCTION
42  void operator()(const size_type iter) const {
43  size_type cell, field(0), point;
44  size_type rightRank = _rightInput.rank();
45 
46  if (_hasField)
47  unrollIndex( cell, field, point,
48  _output.extent(0),
49  _output.extent(1),
50  _output.extent(2),
51  iter );
52  else
53  unrollIndex( cell, point,
54  _output.extent(0),
55  _output.extent(1),
56  iter );
57 
58 
59  auto left = Kokkos::subview(_leftInput, cell, point, Kokkos::ALL());
60 
61  auto right = (rightRank == 2 + size_type(_hasField)) ?
62  ( _hasField ? Kokkos::subview(_rightInput, field, point, Kokkos::ALL()) :
63  Kokkos::subview(_rightInput, point, Kokkos::ALL())) :
64  ( _hasField ? Kokkos::subview(_rightInput, cell, field, point, Kokkos::ALL()) :
65  Kokkos::subview(_rightInput, cell, point, Kokkos::ALL()));
66 
67  // branch prediction is possible
68  if (_isCrossProd3D) {
69  auto result = ( _hasField ? Kokkos::subview(_output, cell, field, point, Kokkos::ALL()) :
70  Kokkos::subview(_output, cell, point, Kokkos::ALL()));
71  result(0) = left(1)*right(2) - left(2)*right(1);
72  result(1) = left(2)*right(0) - left(0)*right(2);
73  result(2) = left(0)*right(1) - left(1)*right(0);
74  } else {
75  typename OutputViewType::reference_type result = _hasField ? _output(cell, field, point) : _output(cell, point);
76  result = left(0)*right(1) - left(1)*right(0);
77  }
78  }
79  };
80  } //namespace
81 
82  template<typename DeviceType>
83  template<typename outputValueType, class ...outputProperties,
84  typename leftInputValueType, class ...leftInputProperties,
85  typename rightInputValueType, class ...rightInputProperties>
86  void
88  crossProduct( Kokkos::DynRankView<outputValueType, outputProperties...> output,
89  const Kokkos::DynRankView<leftInputValueType, leftInputProperties...> leftInput,
90  const Kokkos::DynRankView<rightInputValueType,rightInputProperties...> rightInput,
91  const bool hasField ) {
92 
93  typedef Kokkos::DynRankView<outputValueType, outputProperties...> OutputViewType;
94  typedef const Kokkos::DynRankView<leftInputValueType, leftInputProperties...> leftInputViewType;
95  typedef const Kokkos::DynRankView<rightInputValueType,rightInputProperties...> rightInputViewType;
97 
98  const size_type loopSize = ( hasField ? output.extent(0)*output.extent(1)*output.extent(2) :
99  output.extent(0)*output.extent(1) );
100  const bool isCrossProd3D = (leftInput.extent(2) == 3);
101  Kokkos::RangePolicy<ExecSpaceType,Kokkos::Schedule<Kokkos::Static> > policy(0, loopSize);
102  Kokkos::parallel_for( policy, FunctorType(output, leftInput, rightInput, hasField, isCrossProd3D) );
103  }
104 
105 
106 
107  template<typename DeviceType>
108  template<typename outputFieldValueType, class ...outputFieldProperties,
109  typename inputDataValueType, class ...inputDataProperties,
110  typename inputFieldValueType, class ...inputFieldProperties>
111  void
113  crossProductDataField( Kokkos::DynRankView<outputFieldValueType,outputFieldProperties...> outputFields,
114  const Kokkos::DynRankView<inputDataValueType, inputDataProperties...> inputData,
115  const Kokkos::DynRankView<inputFieldValueType, inputFieldProperties...> inputFields ) {
116 
117 #ifdef HAVE_INTREPID2_DEBUG
118  {
119  /*
120  * Check array rank and spatial dimension range (if applicable)
121  * (1) inputData(C,P,D);
122  * (2) inputFields(C,F,P,D) or (F,P,D);
123  * (3) outputFields(C,F,P,D) in 3D, or (C,F,P) in 2D
124  */
125  // (1) inputData is (C, P, D) and 2 <= D <= 3 is required
126  INTREPID2_TEST_FOR_EXCEPTION( inputData.rank() != 3, std::invalid_argument,
127  ">>> ERROR (ArrayTools::crossProductDataField): inputData must have rank 3");
128  INTREPID2_TEST_FOR_EXCEPTION( inputData.extent(2) < 2 || inputData.extent(2) > 3, std::invalid_argument,
129  ">>> ERROR (ArrayTools::crossProductDataField): inputData dimension(2) must be 2 or 3");
130 
131  // (2) inputFields is (C, F, P, D) or (F, P, D) and 2 <= (D=dimension(rank - 1)) <= 3 is required.
132  INTREPID2_TEST_FOR_EXCEPTION( inputFields.rank() < 3 || inputFields.rank() > 4, std::invalid_argument,
133  ">>> ERROR (ArrayTools::crossProductDataField): inputFields must have rank 3 or 4" );
134  INTREPID2_TEST_FOR_EXCEPTION( inputFields.extent(inputFields.rank()-1) < 2 ||
135  inputFields.extent(inputFields.rank()-1) > 3, std::invalid_argument,
136  ">>> ERROR (ArrayTools::crossProductDataField): inputFields dimension (rank-1) must have rank 2 or 3" );
137 
138  // (3) outputFields is (C,F,P,D) in 3D and (C,F,P) in 2D => rank = inputData.extent(2) + 1
139  INTREPID2_TEST_FOR_EXCEPTION( outputFields.rank() != inputData.extent(2)+1, std::invalid_argument,
140  ">>> ERROR (ArrayTools::crossProductDataField): outputFields rank must match to inputData dimension(2)+1");
141  /*
142  * Dimension cross-checks:
143  * (1) inputData vs. inputFields
144  * (2) outputFields vs. inputData
145  * (3) outputFields vs. inputFields
146  *
147  * Cross-check (1):
148  */
149  if (inputFields.rank() == 4) {
150  // inputData(C,P,D) vs. inputFields(C,F,P,D): dimensions C, P, D must match
151  const size_type f1[] = { 0, 1, 2 }, f2[] = { 0, 2, 3 };
152  for (size_type i=0; i<3; ++i) {
153  INTREPID2_TEST_FOR_EXCEPTION( inputData.extent(f1[i]) != inputFields.extent(f2[i]), std::invalid_argument,
154  ">>> ERROR (ArrayTools::crossProductDataField): inputData dimension does not match with inputFields");
155  }
156  } else {
157  // inputData(C,P,D) vs. inputFields(F,P,D): dimensions P, D must match
158  const size_type f1[] = { 1, 2 }, f2[] = { 1, 2 };
159  for (size_type i=0; i<2; ++i) {
160  INTREPID2_TEST_FOR_EXCEPTION( inputData.extent(f1[i]) != inputFields.extent(f2[i]), std::invalid_argument,
161  ">>> ERROR (ArrayTools::crossProductDataField): inputData dimension does not match with inputFields");
162  }
163  }
164  /*
165  * Cross-check (2):
166  */
167  if (inputData.extent(2) == 2) {
168  // in 2D: outputFields(C,F,P) vs. inputData(C,P,D): dimensions C,P must match
169  // inputData(C,P,D) vs. inputFields(F,P,D): dimensions P, D must match
170  const size_type f1[] = { 0, 2 }, f2[] = { 0, 1 };
171  for (size_type i=0; i<2; ++i) {
172  INTREPID2_TEST_FOR_EXCEPTION( outputFields.extent(f1[i]) != inputData.extent(f2[i]), std::invalid_argument,
173  ">>> ERROR (ArrayTools::crossProductDataField): outputFields dimension does not match with inputData");
174  }
175  } else {
176  // in 3D: outputFields(C,F,P,D) vs. inputData(C,P,D): dimensions C,P,D must match
177  const size_type f1[] = { 0, 2, 3 }, f2[] = { 0, 1, 2 };
178  for (size_type i=0; i<3; ++i) {
179  INTREPID2_TEST_FOR_EXCEPTION( outputFields.extent(f1[i]) != inputData.extent(f2[i]), std::invalid_argument,
180  ">>> ERROR (ArrayTools::crossProductDataField): outputFields dimension does not match with inputData");
181  }
182  }
183  /*
184  * Cross-check (3):
185  */
186  if (inputData.extent(2) == 2) {
187  // In 2D:
188  if (inputFields.rank() == 4) {
189  // and rank-4 inputFields: outputFields(C,F,P) vs. inputFields(C,F,P,D): dimensions C,F,P must match
190  const size_type f1[] = { 0, 1, 2 }, f2[] = { 0, 1, 2 };
191  for (size_type i=0; i<3; ++i) {
192  INTREPID2_TEST_FOR_EXCEPTION( outputFields.extent(f1[i]) != inputFields.extent(f2[i]), std::invalid_argument,
193  ">>> ERROR (ArrayTools::crossProductDataField): outputFields dimension does not match with inputFields");
194  }
195  } else {
196  // and rank-3 inputFields: outputFields(C,F,P) vs. inputFields(F,P,D): dimensions F,P must match
197  const size_type f1[] = { 1, 2 }, f2[] = { 0, 1 };
198  for (size_type i=0; i<2; ++i) {
199  INTREPID2_TEST_FOR_EXCEPTION( outputFields.extent(f1[i]) != inputFields.extent(f2[i]), std::invalid_argument,
200  ">>> ERROR (ArrayTools::crossProductDataField): outputFields dimension does not match with inputFields");
201  }
202  }
203  } else {
204  // In 3D:
205  if (inputFields.rank() == 4) {
206  // and rank-4 inputFields: outputFields(C,F,P,D) vs. inputFields(C,F,P,D): all dimensions C,F,P,D must match
207  for (size_type i=0; i<outputFields.rank(); ++i) {
208  INTREPID2_TEST_FOR_EXCEPTION( outputFields.extent(i) != inputFields.extent(i), std::invalid_argument,
209  ">>> ERROR (ArrayTools::crossProductDataField): outputFields dimension does not match with inputFields");
210  }
211  } else {
212  // and rank-3 inputFields: outputFields(C,F,P,D) vs. inputFields(F,P,D): dimensions F,P,D must match
213  const size_type f1[] = { 1, 2, 3 }, f2[] = { 0, 1, 2 };
214  for (size_type i=0; i<3; ++i) {
215  INTREPID2_TEST_FOR_EXCEPTION( outputFields.extent(f1[i]) != inputFields.extent(f2[i]), std::invalid_argument,
216  ">>> ERROR (ArrayTools::crossProductDataField): outputFields dimension does not match with inputFields");
217  }
218  }
219  }
220  }
221 #endif
222  // body
224  inputData,
225  inputFields,
226  true );
227  }
228 
229 
230  template<typename DeviceType>
231  template<typename outputDataValueType, class ...outputDataProperties,
232  typename inputDataLeftValueType, class ...inputDataLeftProperties,
233  typename inputDataRightValueType, class ...inputDataRightProperties>
234  void
236  crossProductDataData( Kokkos::DynRankView<outputDataValueType, outputDataProperties...> outputData,
237  const Kokkos::DynRankView<inputDataLeftValueType, inputDataLeftProperties...> inputDataLeft,
238  const Kokkos::DynRankView<inputDataRightValueType,inputDataRightProperties...> inputDataRight ) {
239 
240 #ifdef HAVE_INTREPID2_DEBUG
241  {
242  /*
243  * Check array rank and spatial dimension range (if applicable)
244  * (1) inputDataLeft(C,P,D);
245  * (2) inputDataRight(C,P,D) or (P,D);
246  * (3) outputData(C,P,D) in 3D, or (C,P) in 2D
247  */
248  // (1) inputDataLeft is (C, P, D) and 2 <= D <= 3 is required
249  INTREPID2_TEST_FOR_EXCEPTION( inputDataLeft.rank() != 3, std::invalid_argument,
250  ">>> ERROR (ArrayTools::crossProductDataData): inputDataLeft must have rank 3");
251  INTREPID2_TEST_FOR_EXCEPTION( inputDataLeft.extent(2) < 2 || inputDataLeft.extent(2) > 3, std::invalid_argument,
252  ">>> ERROR (ArrayTools::crossProductDataData): inputDataLeft dimension(2) must be 2 or 3");
253 
254  // (2) inputDataRight is (C, P, D) or (P, D) and 2 <= (D=dimension(rank - 1)) <= 3 is required.
255  INTREPID2_TEST_FOR_EXCEPTION( inputDataRight.rank() < 2 || inputDataRight.rank() > 3, std::invalid_argument,
256  ">>> ERROR (ArrayTools::crossProductDataData): inputDataRight must have rank 2 or 3" );
257  INTREPID2_TEST_FOR_EXCEPTION( inputDataRight.extent(inputDataRight.rank()-1) < 2 ||
258  inputDataRight.extent(inputDataRight.rank()-1) > 3, std::invalid_argument,
259  ">>> ERROR (ArrayTools::crossProductDataData): inputDataRight dimension (rank-1) must have rank 2 or 3" );
260 
261  // (3) outputData is (C,P,D) in 3D and (C,P) in 2D => rank = inputDataLeft.extent(2)
262  INTREPID2_TEST_FOR_EXCEPTION( outputData.rank() != inputDataLeft.extent(2), std::invalid_argument,
263  ">>> ERROR (ArrayTools::crossProductDataData): outputData rank must match to inputDataLeft dimension(2)");
264  /*
265  * Dimension cross-checks:
266  * (1) inputDataLeft vs. inputDataRight
267  * (2) outputData vs. inputDataLeft
268  * (3) outputData vs. inputDataRight
269  *
270  * Cross-check (1):
271  */
272  if (inputDataRight.rank() == 3) {
273  // inputDataLeft(C,P,D) vs. inputDataRight(C,P,D): all dimensions C, P, D must match
274  for (size_type i=0; i<inputDataLeft.rank(); ++i) {
275  INTREPID2_TEST_FOR_EXCEPTION( inputDataLeft.extent(i) != inputDataRight.extent(i), std::invalid_argument,
276  ">>> ERROR (ArrayTools::crossProductDataData): inputDataLeft dimension does not match to inputDataRight");
277  }
278  }
279  // inputDataLeft(C, P,D) vs. inputDataRight(P,D): dimensions P, D must match
280  else {
281  const size_type f1[] = { 1, 2 }, f2[] = { 0, 1 };
282  for (size_type i=0; i<2; ++i) {
283  INTREPID2_TEST_FOR_EXCEPTION( inputDataLeft.extent(f1[i]) != inputDataRight.extent(f2[i]), std::invalid_argument,
284  ">>> ERROR (ArrayTools::crossProductDataData): inputDataLeft dimension does not match to inputDataRight");
285  }
286  }
287  /*
288  * Cross-check (2):
289  */
290  if (inputDataLeft.extent(2) == 2) {
291  // in 2D: outputData(C,P) vs. inputDataLeft(C,P,D): dimensions C, P must match
292  const size_type f1[] = { 1, 2 }, f2[] = { 0, 1 };
293  for (size_type i=0; i<2; ++i) {
294  INTREPID2_TEST_FOR_EXCEPTION( inputDataLeft.extent(f1[i]) != outputData.extent(f2[i]), std::invalid_argument,
295  ">>> ERROR (ArrayTools::crossProductDataData): inputDataLeft dimension does not match to outputData");
296  }
297  } else {
298  // in 3D: outputData(C,P,D) vs. inputDataLeft(C,P,D): all dimensions C, P, D must match
299  for (size_type i=0; i<inputDataLeft.rank(); ++i) {
300  INTREPID2_TEST_FOR_EXCEPTION( inputDataLeft.extent(i) != outputData.extent(i), std::invalid_argument,
301  ">>> ERROR (ArrayTools::crossProductDataData): inputDataLeft dimension does not match to outputData");
302  }
303  }
304  /*
305  * Cross-check (3):
306  */
307  if (inputDataLeft.extent(2) == 2) {
308  // In 2D:
309  if (inputDataRight.rank() == 3) {
310  // and rank-3 inputDataRight: outputData(C,P) vs. inputDataRight(C,P,D): dimensions C,P must match
311  const size_type f1[] = { 0, 1 }, f2[] = { 0, 1 };
312  for (size_type i=0; i<2; ++i) {
313  INTREPID2_TEST_FOR_EXCEPTION( outputData.extent(f1[i]) != inputDataRight.extent(f2[i]), std::invalid_argument,
314  ">>> ERROR (ArrayTools::crossProductDataData): outputData dimension does not match to inputDataRight");
315  }
316  } else {
317  // and rank-2 inputDataRight: outputData(C,P) vs. inputDataRight(P,D): dimension P must match
318  INTREPID2_TEST_FOR_EXCEPTION( outputData.extent(1) != inputDataRight.extent(0), std::invalid_argument,
319  ">>> ERROR (ArrayTools::crossProductDataData): outputData dimension does not match to inputDataRight");
320  }
321  } else {
322  // In 3D:
323  if (inputDataRight.rank() == 3) {
324  // and rank-3 inputDataRight: outputData(C,P,D) vs. inputDataRight(C,P,D): all dimensions C,P,D must match
325  for (size_type i=0; i<outputData.rank(); ++i) {
326  INTREPID2_TEST_FOR_EXCEPTION( outputData.extent(i) != inputDataRight.extent(i), std::invalid_argument,
327  ">>> ERROR (ArrayTools::crossProductDataData): outputData dimension does not match to inputDataRight");
328  }
329  } else {
330  // and rank-2 inputDataRight: outputData(C,P,D) vs. inputDataRight(P,D): dimensions P, D must match
331  const size_type f1[] = { 1, 2 }, f2[] = { 0, 1 };
332  for (size_type i=0; i<2; ++i) {
333  INTREPID2_TEST_FOR_EXCEPTION( outputData.extent(f1[i]) != inputDataRight.extent(f2[i]), std::invalid_argument,
334  ">>> ERROR (ArrayTools::crossProductDataData): outputData dimension does not match to inputDataRight");
335  }
336  }
337  }
338  }
339 #endif
340  // body
342  inputDataLeft,
343  inputDataRight,
344  false );
345  }
346 
347 
348  namespace FunctorArrayTools {
352  template < typename OutputViewType, typename leftInputViewType, typename rightInputViewType >
353  struct F_outerProduct {
354  OutputViewType _output;
355  const leftInputViewType _leftInput;
356  const rightInputViewType _rightInput;
357  const bool _hasField;
358 
359  KOKKOS_INLINE_FUNCTION
360  F_outerProduct(OutputViewType output_,
361  leftInputViewType leftInput_,
362  rightInputViewType rightInput_,
363  const bool hasField_)
364  : _output(output_), _leftInput(leftInput_), _rightInput(rightInput_),
365  _hasField(hasField_) {}
366 
367  KOKKOS_INLINE_FUNCTION
368  void operator()(const size_type iter) const {
369  size_type cell, field(0), point;
370  size_type rightRank = _rightInput.rank();
371 
372  if (_hasField)
373  unrollIndex( cell, field, point,
374  _output.extent(0),
375  _output.extent(1),
376  _output.extent(2),
377  iter );
378  else
379  unrollIndex( cell, point,
380  _output.extent(0),
381  _output.extent(1),
382  iter );
383 
384  auto result = ( _hasField ? Kokkos::subview(_output, cell, field, point, Kokkos::ALL(), Kokkos::ALL()) :
385  Kokkos::subview(_output, cell, point, Kokkos::ALL(), Kokkos::ALL()));
386 
387  auto left = Kokkos::subview(_leftInput, cell, point, Kokkos::ALL());
388 
389  auto right = (rightRank == 2 + size_type(_hasField)) ?
390  ( _hasField ? Kokkos::subview(_rightInput, field, point, Kokkos::ALL()) :
391  Kokkos::subview(_rightInput, point, Kokkos::ALL())) :
392  ( _hasField ? Kokkos::subview(_rightInput, cell, field, point, Kokkos::ALL()) :
393  Kokkos::subview(_rightInput, cell, point, Kokkos::ALL()));
394 
395  const ordinal_type iend = result.extent(0);
396  const ordinal_type jend = result.extent(1);
397  for (ordinal_type i=0; i<iend; ++i)
398  for (ordinal_type j=0; j<jend; ++j)
399  result(i, j) = left(i)*right(j);
400  }
401  };
402  }
403 
404  template<typename DeviceType>
405  template<typename outputValueType, class ...outputProperties,
406  typename leftInputValueType, class ...leftInputProperties,
407  typename rightInputValueType, class ...rightInputProperties>
408  void
410  outerProduct( Kokkos::DynRankView<outputValueType, outputProperties...> output,
411  const Kokkos::DynRankView<leftInputValueType, leftInputProperties...> leftInput,
412  const Kokkos::DynRankView<rightInputValueType,rightInputProperties...> rightInput,
413  const bool hasField ) {
414 
415  typedef Kokkos::DynRankView<outputValueType, outputProperties...> OutputViewType;
416  typedef const Kokkos::DynRankView<leftInputValueType, leftInputProperties...> leftInputViewType;
417  typedef const Kokkos::DynRankView<rightInputValueType,rightInputProperties...> rightInputViewType;
419 
420  const size_type loopSize = ( hasField ? output.extent(0)*output.extent(1)*output.extent(2) :
421  output.extent(0)*output.extent(1) );
422  Kokkos::RangePolicy<ExecSpaceType,Kokkos::Schedule<Kokkos::Static> > policy(0, loopSize);
423  Kokkos::parallel_for( policy, FunctorType(output, leftInput, rightInput, hasField) );
424  }
425 
426 
427  template<typename DeviceType>
428  template<typename outputFieldValueType, class ...outputFieldProperties,
429  typename inputDataValueType, class ...inputDataProperties,
430  typename inputFieldValueType, class ...inputFieldProperties>
431  void
433  outerProductDataField( Kokkos::DynRankView<outputFieldValueType,outputFieldProperties...> outputFields,
434  const Kokkos::DynRankView<inputDataValueType, inputDataProperties...> inputData,
435  const Kokkos::DynRankView<inputFieldValueType, inputFieldProperties...> inputFields ) {
436 
437 #ifdef HAVE_INTREPID2_DEBUG
438  {
439  /*
440  * Check array rank and spatial dimension range (if applicable)
441  * (1) inputData(C,P,D);
442  * (2) inputFields(C,F,P,D) or (F,P,D);
443  * (3) outputFields(C,F,P,D,D)
444  */
445  // (1) inputData is (C, P, D) and 2 <= D <= 3 is required
446  INTREPID2_TEST_FOR_EXCEPTION( inputData.rank() != 3, std::invalid_argument,
447  ">>> ERROR (ArrayTools::outerProductDataField): inputData must have rank 3");
448  INTREPID2_TEST_FOR_EXCEPTION( inputData.extent(2) < 2 || inputData.extent(2) > 3, std::invalid_argument,
449  ">>> ERROR (ArrayTools::outerProductDataField): inputData dimension(2) must be 2 or 3");
450 
451  // (2) inputFields is (C, F, P, D) or (F, P, D) and 2 <= (D=dimension(rank - 1)) <= 3 is required.
452  INTREPID2_TEST_FOR_EXCEPTION( inputFields.rank() < 3 || inputFields.rank() > 4, std::invalid_argument,
453  ">>> ERROR (ArrayTools::outerProductDataField): inputFields must have rank 3 or 4" );
454  INTREPID2_TEST_FOR_EXCEPTION( inputFields.extent(inputFields.rank()-1) < 2 ||
455  inputFields.extent(inputFields.rank()-1) < 3, std::invalid_argument,
456  ">>> ERROR (ArrayTools::outerProductDataField): inputFields dimension (rank-1) must have rank 2 or 3" );
457 
458  // (3) outputFields is (C,F,P,D,D)
459  INTREPID2_TEST_FOR_EXCEPTION( outputFields.rank() != 5, std::invalid_argument,
460  ">>> ERROR (ArrayTools::outerProductDataField): outputFields must have rank 5");
461  INTREPID2_TEST_FOR_EXCEPTION( outputFields.extent(3) < 2 ||
462  outputFields.extent(3) > 3, std::invalid_argument,
463  ">>> ERROR (ArrayTools::outerProductDataField): outputFields dimension(3) must be 2 or 3");
464  INTREPID2_TEST_FOR_EXCEPTION( outputFields.extent(4) < 2 ||
465  outputFields.extent(4) > 3, std::invalid_argument,
466  ">>> ERROR (ArrayTools::outerProductDataField): outputFields dimension(4) must be 2 or 3");
467 
468  /*
469  * Dimension cross-checks:
470  * (1) inputData vs. inputFields
471  * (2) outputFields vs. inputData
472  * (3) outputFields vs. inputFields
473  *
474  * Cross-check (2): outputFields(C,F,P,D,D) vs. inputData(C,P,D): dimensions C, P, D must match
475  */
476  {
477  const size_type f1[] = { 0, 2, 3, 4 }, f2[] = { 0, 1, 2, 2 };
478  for (size_type i=0; i<4; ++i) {
479  INTREPID2_TEST_FOR_EXCEPTION( outputFields.extent(f1[i]) != inputData.extent(f2[i]), std::invalid_argument,
480  ">>> ERROR (ArrayTools::outerProductDataField): outputFields dimension does not match with inputData");
481  }
482  }
483 
484  /*
485  * Cross-checks (1,3):
486  */
487  if (inputFields.rank() == 4) {
488  // Cross-check (1): inputData(C,P,D) vs. inputFields(C,F,P,D): dimensions C, P, D must match
489  {
490  const size_type f1[] = { 0, 1, 2 }, f2[] = { 0, 2, 3 };
491  for (size_type i=0; i<3; ++i) {
492  INTREPID2_TEST_FOR_EXCEPTION( inputData.extent(f1[i]) != inputFields.extent(f2[i]), std::invalid_argument,
493  ">>> ERROR (ArrayTools::outerProductDataField): inputData dimension does not match with inputFields");
494  }
495  }
496 
497  // Cross-check (3): outputFields(C,F,P,D,D) vs. inputFields(C,F,P,D): dimensions C, F, P, D must match
498  {
499  const size_type f1[] = { 0, 1, 2, 3, 4 }, f2[] = { 0, 1, 2, 3, 3 };
500  for (size_type i=0; i<5; ++i) {
501  INTREPID2_TEST_FOR_EXCEPTION( outputFields.extent(f1[i]) != inputFields.extent(f2[i]), std::invalid_argument,
502  ">>> ERROR (ArrayTools::outerProductDataField): outputFields dimension does not match with inputFields");
503  }
504  }
505  } else {
506  // Cross-check (1): inputData(C,P,D) vs. inputFields(F,P,D): dimensions P, D must match
507  {
508  const size_type f1[] = { 1, 2 }, f2[] = { 1, 2 };
509  for (size_type i=0; i<2; ++i) {
510  INTREPID2_TEST_FOR_EXCEPTION( inputData.extent(f1[i]) != inputFields.extent(f2[i]), std::invalid_argument,
511  ">>> ERROR (ArrayTools::outerProductDataField): inputData dimension does not match with inputFields");
512  }
513  }
514 
515  // Cross-check (3): outputFields(C,F,P,D,D) vs. inputFields(F,P,D): dimensions F, P, D must match
516  {
517  const size_type f1[] = { 1, 2, 3, 4 }, f2[] = { 0, 1, 2, 2 };
518  for (size_type i=0; i<4; ++i) {
519  INTREPID2_TEST_FOR_EXCEPTION( outputFields.extent(f1[i]) != inputFields.extent(f2[i]), std::invalid_argument,
520  ">>> ERROR (ArrayTools::outerProductDataField): outputFields dimension does not match with inputFields");
521  }
522  }
523  }
524  }
525 #endif
526  // body
528  inputData,
529  inputFields,
530  true );
531  }
532 
533 
534  template<typename DeviceType>
535  template<typename outputDataValueType, class ...outputDataProperties,
536  typename inputDataLeftValuetype, class ...inputDataLeftProperties,
537  typename inputDataRightValueType, class ...inputDataRightProperties>
538  void
540  outerProductDataData( Kokkos::DynRankView<outputDataValueType, outputDataProperties...> outputData,
541  const Kokkos::DynRankView<inputDataLeftValuetype, inputDataLeftProperties...> inputDataLeft,
542  const Kokkos::DynRankView<inputDataRightValueType,inputDataRightProperties...> inputDataRight ) {
543 
544 #ifdef HAVE_INTREPID2_DEBUG
545  {
546  /*
547  * Check array rank and spatial dimension range (if applicable)
548  * (1) inputDataLeft(C,P,D);
549  * (2) inputDataRight(C,P,D) or (P,D);
550  * (3) outputData(C,P,D,D)
551  */
552  // (1) inputDataLeft is (C, P, D) and 2 <= D <= 3 is required
553  INTREPID2_TEST_FOR_EXCEPTION( inputDataLeft.rank() != 3, std::invalid_argument,
554  ">>> ERROR (ArrayTools::outerProductDataField): inputDataLeft must have rank 3");
555  INTREPID2_TEST_FOR_EXCEPTION( inputDataLeft.extent(2) < 2 || inputDataLeft.extent(2) > 3, std::invalid_argument,
556  ">>> ERROR (ArrayTools::outerProductDataField): inputDataLeft dimension(2) must be 2 or 3");
557 
558  // (2) inputDataRight is (C, P, D) or (P, D) and 2 <= (D=dimension(rank - 1)) <= 3 is required.
559  INTREPID2_TEST_FOR_EXCEPTION( inputDataRight.rank() < 2 || inputDataRight.rank() > 3, std::invalid_argument,
560  ">>> ERROR (ArrayTools::outerProductDataField): inputDataRight must have rank 2 or 3" );
561  INTREPID2_TEST_FOR_EXCEPTION( inputDataRight.extent(inputDataRight.rank()-1) < 2 ||
562  inputDataRight.extent(inputDataRight.rank()-1) < 3, std::invalid_argument,
563  ">>> ERROR (ArrayTools::outerProductDataField): inputDataRight dimension (rank-1) must have rank 2 or 3" );
564 
565  // (3) outputData is (C,P,D,D)
566  INTREPID2_TEST_FOR_EXCEPTION( outputData.rank() != 4, std::invalid_argument,
567  ">>> ERROR (ArrayTools::outerProductDataField): outputData must have rank 5");
568  INTREPID2_TEST_FOR_EXCEPTION( outputData.extent(2) < 2 ||
569  outputData.extent(2) > 3, std::invalid_argument,
570  ">>> ERROR (ArrayTools::outerProductDataField): outputData dimension(3) must be 2 or 3");
571  INTREPID2_TEST_FOR_EXCEPTION( outputData.extent(3) < 2 ||
572  outputData.extent(3) > 3, std::invalid_argument,
573  ">>> ERROR (ArrayTools::outerProductDataField): outputData dimension(4) must be 2 or 3");
574 
575  /*
576  * Dimension cross-checks:
577  * (1) inputDataLeft vs. inputDataRight
578  * (2) outputData vs. inputDataLeft
579  * (3) outputData vs. inputDataRight
580  *
581  * Cross-check (2): outputData(C,P,D,D) vs. inputDataLeft(C,P,D): dimensions C, P, D must match
582  */
583  {
584  const size_type f1[] = { 0, 1, 2, 3 }, f2[] = { 0, 1, 2, 2 };
585  for (size_type i=0; i<4; ++i) {
586  INTREPID2_TEST_FOR_EXCEPTION( outputData.extent(f1[i]) != inputDataLeft.extent(f2[i]), std::invalid_argument,
587  ">>> ERROR (ArrayTools::outerProductDataField): outputData dimension does not match with inputDataLeft");
588  }
589  }
590 
591  /*
592  * Cross-checks (1,3):
593  */
594  if (inputDataRight.rank() == 3) {
595  // Cross-check (1): inputDataLeft(C,P,D) vs. inputDataRight(C,P,D): all dimensions C, P, D must match
596  for (size_type i=0; i<inputDataLeft.rank(); ++i) {
597  INTREPID2_TEST_FOR_EXCEPTION( inputDataLeft.extent(i) != inputDataRight.extent(i), std::invalid_argument,
598  ">>> ERROR (ArrayTools::outerProductDataField): inputDataLeft dimension does not match with inputDataRight");
599  }
600 
601  // Cross-check (3): outputData(C,P,D,D) vs. inputDataRight(C,P,D): dimensions C, P, D must match
602  {
603  const size_type f1[] = { 0, 1, 2, 3 }, f2[] = { 0, 1, 2, 2 };
604  for (size_type i=0; i<4; ++i) {
605  INTREPID2_TEST_FOR_EXCEPTION( outputData.extent(f1[i]) != inputDataRight.extent(f2[i]), std::invalid_argument,
606  ">>> ERROR (ArrayTools::outerProductDataField): outputData dimension does not match with inputDataRight");
607  }
608  }
609  } else {
610  // Cross-check (1): inputDataLeft(C,P,D) vs. inputDataRight(P,D): dimensions P, D must match
611  {
612  const size_type f1[] = { 1, 2 }, f2[] = { 0, 1 };
613  for (size_type i=0; i<2; ++i) {
614  INTREPID2_TEST_FOR_EXCEPTION( inputDataLeft.extent(f1[i]) != inputDataRight.extent(f2[i]), std::invalid_argument,
615  ">>> ERROR (ArrayTools::outerProductDataField): inputDataLeft dimension does not match with inputDataRight");
616  }
617  }
618 
619  // Cross-check (3): outputData(C,P,D,D) vs. inputDataRight(P,D): dimensions P, D must match
620  {
621  const size_type f1[] = { 1, 2, 3 }, f2[] = { 0, 1, 1 };
622  for (size_type i=0; i<3; ++i) {
623  INTREPID2_TEST_FOR_EXCEPTION( outputData.extent(f1[i]) != inputDataRight.extent(f2[i]), std::invalid_argument,
624  ">>> ERROR (ArrayTools::outerProductDataField): outputData dimension does not match with inputDataRight");
625  }
626  }
627  }
628  }
629 #endif
630  // body
632  inputDataLeft,
633  inputDataRight,
634  false );
635  }
636 
637 
638  namespace FunctorArrayTools {
642  template < typename OutputViewType,
643  typename leftInputViewType,
644  typename rightInputViewType,
645  ordinal_type leftInputRank,
646  ordinal_type rightInputRank,
647  bool hasField,
648  bool isTranspose>
650  OutputViewType _output;
651  const leftInputViewType _leftInput;
652  const rightInputViewType _rightInput;
653 
654  const ordinal_type _iend;
655  const ordinal_type _jend;
656 
657  using value_type = typename OutputViewType::value_type;
658 
659  KOKKOS_INLINE_FUNCTION
660  F_matvecProduct(OutputViewType output_,
661  leftInputViewType leftInput_,
662  rightInputViewType rightInput_)
663  : _output(output_), _leftInput(leftInput_), _rightInput(rightInput_),
664  _iend(output_.extent_int(rank(output_)-1)), _jend(rightInput_.extent_int(rightInputRank-1))
665  {}
666 
667  // ****** hasField == true cases ******
668  KOKKOS_INLINE_FUNCTION
669  void operator()(const ordinal_type cl,
670  const ordinal_type bf,
671  const ordinal_type pt) const
672  {
673  apply_matvec_product(cl, bf, pt);
674  }
675 
676  template <ordinal_type l=leftInputRank, ordinal_type r=rightInputRank, bool hf=hasField>
677  KOKKOS_FORCEINLINE_FUNCTION
678  typename std::enable_if_t<l==4 && r==4 && hf, void>
679  apply_matvec_product(const ordinal_type &cl,
680  const ordinal_type &bf,
681  const ordinal_type &pt) const {
682  const auto lpt = (_leftInput.extent(1) == 1 ? size_type(0) : pt);
683  if (isTranspose) {
684  for (ordinal_type i=0;i<_iend;++i) {
685  value_type tmp(0);
686  for (ordinal_type j=0;j<_jend;++j)
687  tmp += _leftInput(cl,lpt, j,i)*_rightInput(cl,bf,pt, j);
688  _output(cl,bf,pt, i) = tmp;
689  }
690  } else {
691  for (ordinal_type i=0;i<_iend;++i) {
692  value_type tmp(0);
693  for (ordinal_type j=0;j<_jend;++j)
694  tmp += _leftInput(cl,lpt, i,j)*_rightInput(cl,bf,pt, j);
695  _output(cl,bf,pt, i) = tmp;
696  }
697  }
698  }
699 
700  template <ordinal_type l=leftInputRank, ordinal_type r=rightInputRank, bool hf=hasField>
701  KOKKOS_FORCEINLINE_FUNCTION
702  typename std::enable_if_t<l==4 && r==3 && hf, void>
703  apply_matvec_product(const ordinal_type &cl,
704  const ordinal_type &bf,
705  const ordinal_type &pt) const {
706  const auto lpt = (_leftInput.extent(1) == 1 ? size_type(0) : pt);
707  if (isTranspose) {
708  for (ordinal_type i=0;i<_iend;++i) {
709  value_type tmp(0);
710  for (ordinal_type j=0;j<_jend;++j)
711  tmp += _leftInput(cl,lpt, j,i)*_rightInput(bf,pt, j);
712  _output(cl,bf,pt, i) = tmp;
713  }
714  } else {
715  for (ordinal_type i=0;i<_iend;++i) {
716  value_type tmp(0);
717  for (ordinal_type j=0;j<_jend;++j)
718  tmp += _leftInput(cl,lpt, i,j)*_rightInput(bf,pt, j);
719  _output(cl,bf,pt, i) = tmp;
720  }
721  }
722  }
723 
724  template <ordinal_type l=leftInputRank, ordinal_type r=rightInputRank, bool hf=hasField>
725  KOKKOS_FORCEINLINE_FUNCTION
726  typename std::enable_if_t<l==3 && r==4 && hf, void>
727  apply_matvec_product(const ordinal_type &cl,
728  const ordinal_type &bf,
729  const ordinal_type &pt) const {
730  const auto lpt = (_leftInput.extent(1) == 1 ? size_type(0) : pt);
731  for (ordinal_type i=0;i<_iend;++i)
732  _output(cl,bf,pt, i) = _leftInput(cl,lpt, i)*_rightInput(cl,bf,pt, i);
733  }
734 
735  template <ordinal_type l=leftInputRank, ordinal_type r=rightInputRank, bool hf=hasField>
736  KOKKOS_FORCEINLINE_FUNCTION
737  typename std::enable_if_t<l==3 && r==3 && hf, void>
738  apply_matvec_product(const ordinal_type &cl,
739  const ordinal_type &bf,
740  const ordinal_type &pt) const {
741  const auto lpt = (_leftInput.extent(1) == 1 ? size_type(0) : pt);
742  for (ordinal_type i=0;i<_iend;++i)
743  _output(cl,bf,pt, i) = _leftInput(cl,lpt, i)*_rightInput(bf,pt, i);
744  }
745 
746  template <ordinal_type l=leftInputRank, ordinal_type r=rightInputRank, bool hf=hasField>
747  KOKKOS_FORCEINLINE_FUNCTION
748  typename std::enable_if_t<l==2 && r==4 && hf, void>
749  apply_matvec_product(const ordinal_type &cl,
750  const ordinal_type &bf,
751  const ordinal_type &pt) const {
752  const auto lpt = (_leftInput.extent(1) == 1 ? size_type(0) : pt);
753  const value_type & val = _leftInput(cl,lpt);
754  for (ordinal_type i=0;i<_iend;++i) {
755  _output(cl,bf,pt, i) = val*_rightInput(cl,bf,pt, i);
756  }
757  }
758 
759  template <ordinal_type l=leftInputRank, ordinal_type r=rightInputRank, bool hf=hasField>
760  KOKKOS_FORCEINLINE_FUNCTION
761  typename std::enable_if_t<l==2 && r==3 && hf, void>
762  apply_matvec_product(const ordinal_type &cl,
763  const ordinal_type &bf,
764  const ordinal_type &pt) const {
765  const auto lpt = (_leftInput.extent(1) == 1 ? size_type(0) : pt);
766  const value_type & val = _leftInput(cl,lpt);
767  for (ordinal_type i=0;i<_iend;++i) {
768  _output(cl,bf,pt, i) = val*_rightInput(bf,pt, i);
769  }
770  }
771 
772  // ****** hasField == false cases ******
773  KOKKOS_INLINE_FUNCTION
774  void operator()(const ordinal_type cl,
775  const ordinal_type pt) const
776  {
777  apply_matvec_product(cl, pt);
778  }
779 
780  template <ordinal_type l=leftInputRank, ordinal_type r=rightInputRank, bool hf=hasField>
781  KOKKOS_FORCEINLINE_FUNCTION
782  typename std::enable_if_t<l==4 && r==3 && !hf, void>
783  apply_matvec_product(const ordinal_type &cl,
784  const ordinal_type &pt) const {
785  const auto lpt = (_leftInput.extent(1) == 1 ? size_type(0) : pt);
786  if (isTranspose) {
787  for (ordinal_type i=0;i<_iend;++i) {
788  value_type tmp(0);
789  for (ordinal_type j=0;j<_jend;++j)
790  tmp += _leftInput(cl,lpt, j,i)*_rightInput(cl,pt, j);
791  _output(cl,pt, i) = tmp;
792  }
793  } else {
794  for (ordinal_type i=0;i<_iend;++i) {
795  value_type tmp(0);
796  for (ordinal_type j=0;j<_jend;++j)
797  tmp += _leftInput(cl,lpt, i,j)*_rightInput(cl,pt, j);
798  _output(cl,pt, i) = tmp;
799  }
800  }
801  }
802 
803  template <ordinal_type l=leftInputRank, ordinal_type r=rightInputRank, bool hf=hasField>
804  KOKKOS_FORCEINLINE_FUNCTION
805  typename std::enable_if_t<l==4 && r==2 && !hf, void>
806  apply_matvec_product(const ordinal_type &cl,
807  const ordinal_type &pt) const {
808  const auto lpt = (_leftInput.extent(1) == 1 ? size_type(0) : pt);
809  if (isTranspose) {
810  for (ordinal_type i=0;i<_iend;++i) {
811  value_type tmp(0);
812  for (ordinal_type j=0;j<_jend;++j)
813  tmp += _leftInput(cl,lpt, j,i)*_rightInput(pt, j);
814  _output(cl,pt, i) = tmp;
815  }
816  } else {
817  for (ordinal_type i=0;i<_iend;++i) {
818  value_type tmp(0);
819  for (ordinal_type j=0;j<_jend;++j)
820  tmp += _leftInput(cl,lpt, i,j)*_rightInput(pt, j);
821  _output(cl,pt, i) = tmp;
822  }
823  }
824  }
825 
826  template <ordinal_type l=leftInputRank, ordinal_type r=rightInputRank, bool hf=hasField>
827  KOKKOS_FORCEINLINE_FUNCTION
828  typename std::enable_if_t<l==3 && r==3 && !hf, void>
829  apply_matvec_product(const ordinal_type &cl,
830  const ordinal_type &pt) const {
831  const auto lpt = (_leftInput.extent(1) == 1 ? size_type(0) : pt);
832  for (ordinal_type i=0;i<_iend;++i)
833  _output(cl,pt, i) = _leftInput(cl,lpt, i)*_rightInput(cl,pt, i);
834  }
835 
836  template <ordinal_type l=leftInputRank, ordinal_type r=rightInputRank, bool hf=hasField>
837  KOKKOS_FORCEINLINE_FUNCTION
838  typename std::enable_if_t<l==3 && r==2 && !hf, void>
839  apply_matvec_product(const ordinal_type &cl,
840  const ordinal_type &pt) const {
841  const auto lpt = (_leftInput.extent(1) == 1 ? size_type(0) : pt);
842  for (ordinal_type i=0;i<_iend;++i)
843  _output(cl,pt, i) = _leftInput(cl,lpt, i)*_rightInput(pt, i);
844  }
845 
846  template <ordinal_type l=leftInputRank, ordinal_type r=rightInputRank, bool hf=hasField>
847  KOKKOS_FORCEINLINE_FUNCTION
848  typename std::enable_if_t<l==2 && r==3 && !hf, void>
849  apply_matvec_product(const ordinal_type &cl,
850  const ordinal_type &pt) const {
851  const auto lpt = (_leftInput.extent(1) == 1 ? size_type(0) : pt);
852  const value_type & val = _leftInput(cl,lpt);
853  for (ordinal_type i=0;i<_iend;++i) {
854  _output(cl,pt, i) = val*_rightInput(cl,pt, i);
855  }
856  }
857 
858  template <ordinal_type l=leftInputRank, ordinal_type r=rightInputRank, bool hf=hasField>
859  KOKKOS_FORCEINLINE_FUNCTION
860  typename std::enable_if_t<l==2 && r==2 && !hf, void>
861  apply_matvec_product(const ordinal_type &cl,
862  const ordinal_type &pt) const {
863  const auto lpt = (_leftInput.extent(1) == 1 ? size_type(0) : pt);
864  const value_type & val = _leftInput(cl,lpt);
865  for (ordinal_type i=0;i<_iend;++i) {
866  _output(cl,pt, i) = val*_rightInput(pt, i);
867  }
868  }
869  };
870  } //namespace
871 
872  template<typename DeviceType>
873  template<typename outputValueType, class ...outputProperties,
874  typename leftInputValueType, class ...leftInputProperties,
875  typename rightInputValueType, class ...rightInputProperties>
876  void
878  matvecProduct( Kokkos::DynRankView<outputValueType, outputProperties...> output,
879  const Kokkos::DynRankView<leftInputValueType, leftInputProperties...> leftInput,
880  const Kokkos::DynRankView<rightInputValueType,rightInputProperties...> rightInput,
881  const bool hasField,
882  const bool isTranspose ) {
883 
884  using Output = Kokkos::DynRankView<outputValueType, outputProperties...>;
885  using Left = const Kokkos::DynRankView<leftInputValueType, leftInputProperties...>;
886  using Right = const Kokkos::DynRankView<rightInputValueType,rightInputProperties...>;
887 
888  // FTNMAB: FunctorType with left rank N, right rank M, hasField = (A==T), isTranspose = (B==T)
889 
890  // hasField == true
895 
896  // for left rank 3, 2, isTranspose does not matter
901 
902  // hasField == false
907 
908  // for left rank 3, 2, isTranspose does not matter
913 
914  const ordinal_type l = leftInput.rank();
915  const ordinal_type r = rightInput.rank();
916 
917  using range_policy2 = Kokkos::MDRangePolicy< ExecSpaceType, Kokkos::Rank<2>, Kokkos::IndexType<ordinal_type> >;
918  range_policy2 policy2( { 0, 0 }, { output.extent(0), output.extent(1) } );
919 
920  using range_policy3 = Kokkos::MDRangePolicy< ExecSpaceType, Kokkos::Rank<3>, Kokkos::IndexType<ordinal_type> >;
921  range_policy3 policy3( { 0, 0, 0 }, { output.extent(0), output.extent(1), output.extent(2) } );
922 
923  // just to make the below a little easier to read, we pack l and r together:
924  const ordinal_type lr = l * 10 + r;
925  const auto &ov = output;
926  const auto &lv = leftInput;
927  const auto &rv = rightInput;
928 
929  if (hasField) // this means we want policy3
930  {
931  if (l == 4)
932  {
933  // isTranspose matters
934  if (isTranspose)
935  {
936  switch (r)
937  {
938  case 4: { FT44TT f(ov,lv,rv); Kokkos::parallel_for( policy3, f ); } break;
939  default: { FT43TT f(ov,lv,rv); Kokkos::parallel_for( policy3, f ); }
940  }
941  }
942  else
943  {
944  switch (r)
945  {
946  case 4: { FT44TF f(ov,lv,rv); Kokkos::parallel_for( policy3, f ); } break;
947  default: { FT43TF f(ov,lv,rv); Kokkos::parallel_for( policy3, f ); }
948  }
949  }
950  }
951  else // l == 3 or 2; isTranspose does not matter
952  {
953  switch (lr)
954  {
955  case 34: { FT34TF f(ov,lv,rv); Kokkos::parallel_for( policy3, f ); } break;
956  case 33: { FT33TF f(ov,lv,rv); Kokkos::parallel_for( policy3, f ); } break;
957  case 24: { FT24TF f(ov,lv,rv); Kokkos::parallel_for( policy3, f ); } break;
958  default: { FT23TF f(ov,lv,rv); Kokkos::parallel_for( policy3, f ); } // 23
959  }
960  }
961  }
962  else // hasField is false; use policy2
963  {
964  if (l == 4)
965  {
966  // isTranspose matters
967  if (isTranspose)
968  {
969  switch (r)
970  {
971  case 3: { FT43FT f(ov,lv,rv); Kokkos::parallel_for( policy2, f ); } break;
972  default: { FT42FT f(ov,lv,rv); Kokkos::parallel_for( policy2, f ); } // 2
973  }
974  }
975  else
976  {
977  switch (r)
978  {
979  case 3: { FT43FF f(ov,lv,rv); Kokkos::parallel_for( policy2, f ); } break;
980  default: { FT42FF f(ov,lv,rv); Kokkos::parallel_for( policy2, f ); } // 2
981  }
982  }
983  }
984  else // l == 3 or 2; isTranspose does not matter
985  {
986  switch (lr)
987  {
988  case 33: { FT33FF f(ov,lv,rv); Kokkos::parallel_for( policy2, f ); } break;
989  case 32: { FT32FF f(ov,lv,rv); Kokkos::parallel_for( policy2, f ); } break;
990  case 23: { FT23FF f(ov,lv,rv); Kokkos::parallel_for( policy2, f ); } break;
991  default: { FT22FF f(ov,lv,rv); Kokkos::parallel_for( policy2, f ); } // 22
992  }
993  }
994  }
995  }
996 
997  template<typename DeviceType>
998  template<typename outputFieldValueType, class ...outputFieldProperties,
999  typename inputDataValueType, class ...inputDataProperties,
1000  typename inputFieldValueType, class ...inputFieldProperties>
1001  void
1002  ArrayTools<DeviceType>::matvecProductDataField( Kokkos::DynRankView<outputFieldValueType,outputFieldProperties...> outputFields,
1003  const Kokkos::DynRankView<inputDataValueType, inputDataProperties...> inputData,
1004  const Kokkos::DynRankView<inputFieldValueType, inputFieldProperties...> inputFields,
1005  const char transpose ) {
1006 
1007 #ifdef HAVE_INTREPID2_DEBUG
1008  {
1009  /*
1010  * Check array rank and spatial dimension range (if applicable)
1011  * (1) inputData(C,P), (C,P,D) or (C,P,D,D); P=1 is admissible to allow multiply by const. data
1012  * (2) inputFields(C,F,P,D) or (F,P,D);
1013  * (3) outputFields(C,F,P,D)
1014  */
1015  // (1) inputData is (C,P), (C, P, D) or (C, P, D, D) and 1 <= D <= 3 is required
1016  INTREPID2_TEST_FOR_EXCEPTION( inputData.rank() < 2 || inputData.rank() > 4, std::invalid_argument,
1017  ">>> ERROR (ArrayTools::matvecProductDataField): inputData must have rank 2,3 or 4" );
1018  if (inputData.rank() > 2) {
1019  INTREPID2_TEST_FOR_EXCEPTION( inputData.extent(2) < 1 ||
1020  inputData.extent(2) > 3, std::invalid_argument,
1021  ">>> ERROR (ArrayTools::matvecProductDataField): inputData dimension(2) must be 1,2 or 3");
1022  }
1023  if (inputData.rank() == 4) {
1024  INTREPID2_TEST_FOR_EXCEPTION( inputData.extent(3) < 1 ||
1025  inputData.extent(3) > 3, std::invalid_argument,
1026  ">>> ERROR (ArrayTools::matvecProductDataField): inputData dimension(3) must be 1,2 or 3");
1027  }
1028 
1029  // (2) inputFields is (C, F, P, D) or (F, P, D) and 1 <= (D=dimension(rank - 1)) <= 3 is required.
1030  INTREPID2_TEST_FOR_EXCEPTION( inputFields.rank() < 3 ||
1031  inputFields.rank() > 4, std::invalid_argument,
1032  ">>> ERROR (ArrayTools::matvecProductDataField): inputFields must have rank 3 or 4" );
1033  INTREPID2_TEST_FOR_EXCEPTION( (inputFields.rank()-1) < 1 ||
1034  (inputFields.rank()-1) > 3, std::invalid_argument,
1035  ">>> ERROR (ArrayTools::matvecProductDataField): inputFields dimension(rank-1) must be 1,2, or 3" );
1036 
1037  // (3) outputFields is (C,F,P,D)
1038  INTREPID2_TEST_FOR_EXCEPTION( outputFields.rank() != 4, std::invalid_argument,
1039  ">>> ERROR (ArrayTools::matvecProductDataField): outputFields must have rank 4" );
1040  INTREPID2_TEST_FOR_EXCEPTION( outputFields.extent(3) < 1 ||
1041  outputFields.extent(3) > 3, std::invalid_argument,
1042  ">>> ERROR (ArrayTools::matvecProductDataField): outputFields dimension(3) must be 1,2 or 3" );
1043 
1044  /*
1045  * Dimension cross-checks:
1046  * (1) inputData vs. inputFields
1047  * (2) outputFields vs. inputData
1048  * (3) outputFields vs. inputFields
1049  *
1050  * Cross-check (2): outputFields(C,F,P,D) vs. inputData(C,P), (C,P,D) or (C,P,D,D):
1051  * dimensions C, and D must match in all cases, dimension P must match only when non-constant
1052  * data is specified (P>1). Do not check P dimensions with constant data, i.e., when P=1 in
1053  * inputData(C,1,...)
1054  */
1055  if (inputData.extent(1) > 1) { // check P dimension if P>1 in inputData
1056  INTREPID2_TEST_FOR_EXCEPTION( outputFields.extent(2) != inputData.extent(1), std::invalid_argument,
1057  ">>> ERROR (ArrayTools::matvecProductDataField): outputFields dimension(2) must match to inputData dimension(1)" );
1058  }
1059  if (inputData.rank() == 2) { // inputData(C,P) -> C match
1060  INTREPID2_TEST_FOR_EXCEPTION( outputFields.extent(0) != inputData.extent(0), std::invalid_argument,
1061  ">>> ERROR (ArrayTools::matvecProductDataField): outputFields dimension(0) must match to inputData dimension(0)" );
1062  }
1063  if (inputData.rank() == 3) { // inputData(C,P,D) -> C, D match
1064  const size_type f1[] = { 0, 3 }, f2[] = { 0, 2 };
1065  for (size_type i=0; i<2; ++i) {
1066  INTREPID2_TEST_FOR_EXCEPTION( outputFields.extent(f1[i]) != inputData.extent(f2[i]), std::invalid_argument,
1067  ">>> ERROR (ArrayTools::matvecProductDataField): outputFields dimension does not match to inputData dimension" );
1068  }
1069  }
1070  if (inputData.rank() == 4) { // inputData(C,P,D,D) -> C, D, D match
1071  const size_type f1[] = { 0, 3, 3 }, f2[] = { 0, 2, 3 };
1072  for (size_type i=0; i<3; ++i) {
1073  INTREPID2_TEST_FOR_EXCEPTION( outputFields.extent(f1[i]) != inputData.extent(f2[i]), std::invalid_argument,
1074  ">>> ERROR (ArrayTools::matvecProductDataField): outputFields dimension does not match to inputData dimension" );
1075  }
1076  }
1077 
1078  /*
1079  * Cross-checks (1,3):
1080  */
1081  if (inputFields.rank() == 4) {
1082  // Cross-check (1): inputData(C,P), (C,P,D) or (C,P,D,D) vs. inputFields(C,F,P,D): dimensions C, P, D must match
1083  if (inputData.extent(1) > 1) { // check P dimension if P>1 in inputData
1084  INTREPID2_TEST_FOR_EXCEPTION( inputFields.extent(2) != inputData.extent(1), std::invalid_argument,
1085  ">>> ERROR (ArrayTools::matvecProductDataField): inputFields dimension (2) does not match to inputData dimension (1)" );
1086  }
1087  if (inputData.rank() == 2) { // inputData(C,P) -> C match
1088  INTREPID2_TEST_FOR_EXCEPTION( inputData.extent(0) != inputFields.extent(0), std::invalid_argument,
1089  ">>> ERROR (ArrayTools::matvecProductDataField): inputData dimension (0) does not match to inputFields dimension (0)" );
1090  }
1091  if (inputData.rank() == 3) { // inputData(C,P,D) -> C, D match
1092  const size_type f1[] = { 0, 2 }, f2[] = { 0, 3 };
1093  for (size_type i=0; i<2; ++i) {
1094  INTREPID2_TEST_FOR_EXCEPTION( inputData.extent(f1[i]) != inputFields.extent(f2[i]), std::invalid_argument,
1095  ">>> ERROR (ArrayTools::matvecProductDataField): inputData dimension does not match to inputFields dimension" );
1096  }
1097  }
1098  if (inputData.rank() == 4) { // inputData(C,P,D,D) -> C, D, D match
1099  const size_type f1[] = { 0, 2, 3 }, f2[] = { 0, 3, 3 };
1100  for (size_type i=0; i<3; ++i) {
1101  INTREPID2_TEST_FOR_EXCEPTION( inputData.extent(f1[i]) != inputFields.extent(f2[i]), std::invalid_argument,
1102  ">>> ERROR (ArrayTools::matvecProductDataField): inputData dimension does not match to inputFields dimension" );
1103  }
1104  }
1105 
1106  // Cross-check (3): outputFields(C,F,P,D) vs. inputFields(C,F,P,D): all dimensions C, F, P, D must match
1107  for (size_type i=0; i<outputFields.rank(); ++i) {
1108  INTREPID2_TEST_FOR_EXCEPTION( outputFields.extent(i) != inputFields.extent(i), std::invalid_argument,
1109  ">>> ERROR (ArrayTools::matvecProductDataField): outputFields dimension does not match to inputFields dimension" );
1110  }
1111  } else {
1112  // Cross-check (1): inputData(C,P), (C,P,D) or (C,P,D,D) vs. inputFields(F,P,D): dimensions P, D must match
1113  if (inputData.extent(1) > 1) { // check P if P>1 in inputData
1114  INTREPID2_TEST_FOR_EXCEPTION( inputData.extent(1) != inputFields.extent(1), std::invalid_argument,
1115  ">>> ERROR (ArrayTools::matvecProductDataField): inputData dimension(1) does not match to inputFields dimension (1)" );
1116  }
1117  if (inputData.rank() == 3) {
1118  INTREPID2_TEST_FOR_EXCEPTION( inputData.extent(2) != inputFields.extent(2), std::invalid_argument,
1119  ">>> ERROR (ArrayTools::matvecProductDataField): inputData dimension(2) does not match to inputFields dimension (2)" );
1120  }
1121  if (inputData.rank() == 4) {
1122  const size_type f1[] = { 2, 3 }, f2[] = { 2, 2 };
1123  for (size_type i=0; i<2; ++i) {
1124  INTREPID2_TEST_FOR_EXCEPTION( inputData.extent(f1[i]) != inputFields.extent(f2[i]), std::invalid_argument,
1125  ">>> ERROR (ArrayTools::matvecProductDataField): inputData dimension does not match to inputFields dimension" );
1126  }
1127  }
1128 
1129  // Cross-check (3): outputFields(C,F,P,D) vs. inputFields(F,P,D): dimensions F, P, D must match
1130  {
1131  const size_type f1[] = { 1, 2, 3 }, f2[] = { 0, 1, 2 };
1132  for (size_type i=0; i<3; ++i) {
1133  INTREPID2_TEST_FOR_EXCEPTION( outputFields.extent(f1[i]) != inputFields.extent(f2[i]), std::invalid_argument,
1134  ">>> ERROR (ArrayTools::matvecProductDataField): outputFields dimension does not match to inputFields dimension" );
1135  }
1136  }
1137  }
1138  }
1139 #endif
1140  // body
1142  inputData,
1143  inputFields,
1144  true,
1145  transpose == 't' || transpose == 'T' );
1146  }
1147 
1148 
1149 
1150  template<typename DeviceType>
1151  template<typename outputDataValueType, class ...outputDataProperties,
1152  typename inputDataLeftValueType, class ...inputDataLeftProperties,
1153  typename inputDataRightValueType, class ...inputDataRightProperties>
1154  void
1156  matvecProductDataData( Kokkos::DynRankView<outputDataValueType, outputDataProperties...> outputData,
1157  const Kokkos::DynRankView<inputDataLeftValueType, inputDataLeftProperties...> inputDataLeft,
1158  const Kokkos::DynRankView<inputDataRightValueType,inputDataRightProperties...> inputDataRight,
1159  const char transpose ) {
1160 
1161 #ifdef HAVE_INTREPID2_DEBUG
1162  {
1163  /*
1164  * Check array rank and spatial dimension range (if applicable)
1165  * (1) inputDataLeft(C,P), (C,P,D) or (C,P,D1,D2); P=1 is admissible to allow multiply by const. left data
1166  * (2) inputDataRight(C,P,D) or (P,D);
1167  * (3) outputData(C,P,D)
1168  */
1169  // (1) inputDataLeft is (C,P), (C,P,D) or (C,P,D1,D2) and 1 <= D,D1,D2 <= 3 is required
1170  INTREPID2_TEST_FOR_EXCEPTION( inputDataLeft.rank() < 2 ||
1171  inputDataLeft.rank() > 4, std::invalid_argument,
1172  ">>> ERROR (ArrayTools::matvecProductDataData): inputDataLeft must have rank 2,3 or 4" );
1173 
1174  if (inputDataLeft.rank() > 2) {
1175  INTREPID2_TEST_FOR_EXCEPTION( inputDataLeft.extent(2) < 1 ||
1176  inputDataLeft.extent(2) > 3, std::invalid_argument,
1177  ">>> ERROR (ArrayTools::matvecProductDataData): inputDataLeft dimension(2) must be 1, 2 or 3");
1178  }
1179  if (inputDataLeft.rank() == 4) {
1180  INTREPID2_TEST_FOR_EXCEPTION( inputDataLeft.extent(3) < 1 ||
1181  inputDataLeft.extent(3) > 3, std::invalid_argument,
1182  ">>> ERROR (ArrayTools::matvecProductDataData): inputDataLeft dimension(3) must be 1, 2 or 3");
1183  }
1184 
1185  // (2) inputDataRight is (C, P, D) or (P, D) and 1 <= (D=dimension(rank - 1)) <= 3 is required.
1186  INTREPID2_TEST_FOR_EXCEPTION( inputDataRight.rank() < 2 ||
1187  inputDataRight.rank() > 3, std::invalid_argument,
1188  ">>> ERROR (ArrayTools::matvecProductDataData): inputDataRight must have rank 2 or 3" );
1189  INTREPID2_TEST_FOR_EXCEPTION( inputDataRight.extent(inputDataRight.rank()-1) < 1 ||
1190  inputDataRight.extent(inputDataRight.rank()-1) > 3, std::invalid_argument,
1191  ">>> ERROR (ArrayTools::matvecProductDataData): inputDataRight dimension (rank-1) must be 1,2 or 3" );
1192 
1193  // (3) outputData is (C,P,D)
1194  INTREPID2_TEST_FOR_EXCEPTION( outputData.rank() != 3, std::invalid_argument,
1195  ">>> ERROR (ArrayTools::matvecProductDataData): outputData must have rank 3" );
1196  INTREPID2_TEST_FOR_EXCEPTION( outputData.extent(2) < 1 ||
1197  outputData.extent(2) > 3, std::invalid_argument,
1198  ">>> ERROR (ArrayTools::matvecProductDataData): outputData dimension(2) must be 1, 2 or 3");
1199 
1200  /*
1201  * Dimension cross-checks:
1202  * (1) inputDataLeft vs. inputDataRight
1203  * (2) outputData vs. inputDataLeft
1204  * (3) outputData vs. inputDataRight
1205  *
1206  * Cross-check (2): outputData(C,P,D) vs. inputDataLeft(C,P), (C,P,D) or (C,P,D,D):
1207  * dimensions C, and D must match in all cases, dimension P must match only when non-constant
1208  * data is specified (P>1). Do not check P dimensions with constant left data, i.e., when P=1 in
1209  * inputDataLeft(C,1,...)
1210  */
1211  if (inputDataLeft.extent(1) > 1) { // check P dimension if P>1 in inputDataLeft
1212  INTREPID2_TEST_FOR_EXCEPTION( outputData.extent(1) != inputDataLeft.extent(1), std::invalid_argument,
1213  ">>> ERROR (ArrayTools::matvecProductDataData): outputData dimension(1) muat match inputDataLeft dimension(1)" );
1214  }
1215  if (inputDataLeft.rank() == 2) { // inputDataLeft(C,P): check C
1216  INTREPID2_TEST_FOR_EXCEPTION( outputData.extent(0) != inputDataLeft.extent(0), std::invalid_argument,
1217  ">>> ERROR (ArrayTools::matvecProductDataData): outputData dimension(0) muat match inputDataLeft dimension(0)" );
1218  }
1219  if (inputDataLeft.rank() == 3) { // inputDataLeft(C,P,D): check C and D
1220  const size_type f1[] = { 0, 2 }, f2[] = { 0, 2 };
1221  for (size_type i=0; i<2; ++i) {
1222  INTREPID2_TEST_FOR_EXCEPTION( outputData.extent(f1[i]) != inputDataLeft.extent(f2[i]), std::invalid_argument,
1223  ">>> ERROR (ArrayTools::matvecProductDataData): outputData dimension muat match inputDataLeft dimension" );
1224  }
1225  }
1226  if (inputDataLeft.rank() == 4) { // inputDataLeft(C,P,D1,D2): check C and D
1227  size_type f1[] = { 0, 2}, f2[] = { 0, 2};
1228  if (transpose) f2[1] = 3;
1229  for (size_type i=0; i<2; ++i) {
1230  INTREPID2_TEST_FOR_EXCEPTION( outputData.extent(f1[i]) != inputDataLeft.extent(f2[i]), std::invalid_argument,
1231  ">>> ERROR (ArrayTools::matvecProductDataData): outputData dimension muat match inputDataLeft dimension" );
1232  }
1233  }
1234 
1235  /*
1236  * Cross-checks (1,3):
1237  */
1238  if (inputDataRight.rank() == 3) {
1239  // Cross-check (1): inputDataLeft(C,P), (C,P,D), or (C,P,D,D) vs. inputDataRight(C,P,D): dimensions C, P, D must match
1240  if (inputDataLeft.extent(1) > 1) { // check P dimension if P>1 in inputDataLeft
1241  INTREPID2_TEST_FOR_EXCEPTION( inputDataLeft.extent(1) != inputDataRight.extent(1), std::invalid_argument,
1242  ">>> ERROR (ArrayTools::matvecProductDataData): inputDataLeft dimension (1) muat match to inputDataRight dimension (1)" );
1243  }
1244  if (inputDataLeft.rank() == 2) { // inputDataLeft(C,P): check C
1245  INTREPID2_TEST_FOR_EXCEPTION( inputDataLeft.extent(0) != inputDataRight.extent(0), std::invalid_argument,
1246  ">>> ERROR (ArrayTools::matvecProductDataData): inputDataLeft dimension (0) muat match to inputDataRight dimension (0)" );
1247  }
1248  if (inputDataLeft.rank() == 3) { // inputDataLeft(C,P,D): check C and D
1249  const size_type f1[] = { 0, 2 }, f2[] = { 0, 2 };
1250  for (size_type i=0; i<2; ++i) {
1251  INTREPID2_TEST_FOR_EXCEPTION( inputDataLeft.extent(f1[i]) != inputDataRight.extent(f2[i]), std::invalid_argument,
1252  ">>> ERROR (ArrayTools::matvecProductDataData): inputDataLeft dimension muat match to inputDataRight dimension" );
1253  }
1254  }
1255  if (inputDataLeft.rank() == 4) { // inputDataLeft(C,P,D,D): check C and D
1256  size_type f1[] = { 0, 3}, f2[] = { 0, 2};
1257  if (transpose) f1[1] = 2;
1258  for (size_type i=0; i<2; ++i) {
1259  INTREPID2_TEST_FOR_EXCEPTION( inputDataLeft.extent(f1[i]) != inputDataRight.extent(f2[i]), std::invalid_argument,
1260  ">>> ERROR (ArrayTools::matvecProductDataData): inputDataLeft dimension muat match to inputDataRight dimension" );
1261  }
1262  }
1263 
1264  // Cross-check (3): outputData(C,P) vs. inputDataRight(C,P): all dimensions C, P must match
1265  for (size_type i=0; i<outputData.rank()-1; ++i) {
1266  INTREPID2_TEST_FOR_EXCEPTION( outputData.extent(i) != inputDataRight.extent(i), std::invalid_argument,
1267  ">>> ERROR (ArrayTools::matvecProductDataData): outputData dimension muat match to inputDataRight dimension" );
1268  }
1269  } else {
1270  // Cross-check (1): inputDataLeft(C,P), (C,P,D), or (C,P,D,D) vs. inputDataRight(P,D): dimensions P, D must match
1271  if (inputDataLeft.extent(1) > 1) { // check P if P>1 in inputData
1272  INTREPID2_TEST_FOR_EXCEPTION( inputDataLeft.extent(1) != inputDataRight.extent(0), std::invalid_argument,
1273  ">>> ERROR (ArrayTools::matvecProductDataData): inputDataLeft dimension (1) does mot match to inputDataright dimension (0)" );
1274  }
1275  if (inputDataLeft.rank() == 3) { // inputDataLeft(C,P,D): check D
1276  INTREPID2_TEST_FOR_EXCEPTION( inputDataLeft.extent(2) != inputDataRight.extent(1), std::invalid_argument,
1277  ">>> ERROR (ArrayTools::matvecProductDataData): inputDataLeft dimension (2) does mot match to inputDataright dimension (1)" );
1278  }
1279  if (inputDataLeft.rank() == 4) { // inputDataLeft(C,P,D,D): check D
1280  const size_type f1[] = { 2, 3 }, f2[] = { 1, 1 };
1281  for (size_type i=0; i<2; ++i) {
1282  INTREPID2_TEST_FOR_EXCEPTION( inputDataLeft.extent(f1[i]) != inputDataRight.extent(f2[i]), std::invalid_argument,
1283  ">>> ERROR (ArrayTools::matvecProductDataData): inputDataLeft dimension muat match to inputDataRight dimension" );
1284  }
1285  }
1286 
1287  // Cross-check (3): outputData(C,P,D) vs. inputDataRight(P,D): dimensions P, D must match
1288  {
1289  const size_type f1[] = { 1, 2 }, f2[] = { 0, 1 };
1290  for (size_type i=0; i<2; ++i) {
1291  INTREPID2_TEST_FOR_EXCEPTION( outputData.extent(f1[i]) != inputDataRight.extent(f2[i]), std::invalid_argument,
1292  ">>> ERROR (ArrayTools::matvecProductDataData): outputData dimension muat match to inputDataRight dimension" );
1293  }
1294  }
1295  }
1296  }
1297 #endif
1298  // body
1300  inputDataLeft,
1301  inputDataRight,
1302  false,
1303  transpose == 't' || transpose == 'T' );
1304  }
1305 
1306 
1307  namespace FunctorArrayTools {
1311  template < typename OutputViewType, typename leftInputViewType, typename rightInputViewType >
1313  OutputViewType _output;
1314  leftInputViewType _leftInput;
1315  rightInputViewType _rightInput;
1316  const bool _hasField, _isTranspose;
1317  typedef typename leftInputViewType::value_type value_type;
1318 
1319  KOKKOS_INLINE_FUNCTION
1320  F_matmatProduct(OutputViewType output_,
1321  leftInputViewType leftInput_,
1322  rightInputViewType rightInput_,
1323  const bool hasField_,
1324  const bool isTranspose_)
1325  : _output(output_), _leftInput(leftInput_), _rightInput(rightInput_),
1326  _hasField(hasField_), _isTranspose(isTranspose_) {}
1327 
1328  KOKKOS_INLINE_FUNCTION
1329  void operator()(const size_type iter) const {
1330  size_type cell(0), field(0), point(0);
1331  size_type leftRank = _leftInput.rank();
1332  size_type rightRank = _rightInput.rank();
1333 
1334  if (_hasField)
1335  unrollIndex( cell, field, point,
1336  _output.extent(0),
1337  _output.extent(1),
1338  _output.extent(2),
1339  iter );
1340  else
1341  unrollIndex( cell, point,
1342  _output.extent(0),
1343  _output.extent(1),
1344  iter );
1345 
1346  auto result = ( _hasField ? Kokkos::subview(_output, cell, field, point, Kokkos::ALL(), Kokkos::ALL()) :
1347  Kokkos::subview(_output, cell, point, Kokkos::ALL(), Kokkos::ALL()));
1348 
1349  const auto lpoint = (_leftInput.extent(1) == 1 ? 0 : point);
1350  auto left = ( leftRank == 4 ? Kokkos::subview(_leftInput, cell, lpoint, Kokkos::ALL(), Kokkos::ALL()) :
1351  leftRank == 3 ? Kokkos::subview(_leftInput, cell, lpoint, Kokkos::ALL()) :
1352  Kokkos::subview(_leftInput, cell, lpoint) );
1353 
1354  //temporary
1355  const bool hasCell = (_hasField ? rightRank == 5 : rightRank == 4);
1356  auto right = ( _hasField ? ( hasCell ? Kokkos::subview(_rightInput, cell, field, point, Kokkos::ALL(), Kokkos::ALL()) :
1357  Kokkos::subview(_rightInput, field, point, Kokkos::ALL(), Kokkos::ALL())):
1358  ( hasCell ? Kokkos::subview(_rightInput, cell, point, Kokkos::ALL(), Kokkos::ALL()) :
1359  Kokkos::subview(_rightInput, point, Kokkos::ALL(), Kokkos::ALL())));
1360 
1361  const ordinal_type iend = result.extent(0);
1362  const ordinal_type jend = result.extent(1);
1363 
1364  switch (leftRank) {
1365  case 4: {
1366  if (_isTranspose) {
1367  const size_type kend = right.extent(0);
1368  for (ordinal_type i=0; i<iend; ++i)
1369  for (ordinal_type j=0; j<jend; ++j) {
1370  result(i, j) = value_type(0);
1371  for (size_type k=0; k<kend; ++k)
1372  result(i, j) += left(k, i) * right(k, j);
1373  }
1374  } else {
1375  const size_type kend = right.extent(0);
1376  for (ordinal_type i=0; i<iend; ++i)
1377  for (ordinal_type j=0; j<jend; ++j) {
1378  result(i, j) = value_type(0);
1379  for (size_type k=0; k<kend; ++k)
1380  result(i, j) += left(i, k) * right(k, j);
1381  }
1382  }
1383  break;
1384  }
1385  case 3: { //matrix is diagonal
1386  for (ordinal_type i=0; i<iend; ++i)
1387  for (ordinal_type j=0; j<jend; ++j)
1388  result(i, j) = left(i) * right(i, j);
1389  break;
1390  }
1391  case 2: { //matrix is a scaled identity
1392  for (ordinal_type i=0; i<iend; ++i)
1393  for (ordinal_type j=0; j<jend; ++j)
1394  result(i, j) = left() * right(i, j);
1395  break;
1396  }
1397  }
1398  }
1399  };
1400  } //namespace
1401 
1402  template<typename DeviceType>
1403  template<typename outputValueType, class ...outputProperties,
1404  typename leftInputValueType, class ...leftInputProperties,
1405  typename rightInputValueType, class ...rightInputProperties>
1406  void
1408  matmatProduct( Kokkos::DynRankView<outputValueType, outputProperties...> output,
1409  const Kokkos::DynRankView<leftInputValueType, leftInputProperties...> leftInput,
1410  const Kokkos::DynRankView<rightInputValueType,rightInputProperties...> rightInput,
1411  const bool hasField,
1412  const bool isTranspose ) {
1413 
1414  typedef Kokkos::DynRankView<outputValueType, outputProperties...> OutputViewType;
1415  typedef const Kokkos::DynRankView<leftInputValueType, leftInputProperties...> leftInputViewType;
1416  typedef const Kokkos::DynRankView<rightInputValueType,rightInputProperties...> rightInputViewType;
1418 
1419  const size_type loopSize = ( hasField ? output.extent(0)*output.extent(1)*output.extent(2) :
1420  output.extent(0)*output.extent(1) );
1421  Kokkos::RangePolicy<ExecSpaceType,Kokkos::Schedule<Kokkos::Static> > policy(0, loopSize);
1422  Kokkos::parallel_for( policy, FunctorType(output, leftInput, rightInput, hasField, isTranspose) );
1423  }
1424 
1425 
1426 
1427 
1428  template<typename DeviceType>
1429  template<typename outputFieldValueType, class ...outputFieldProperties,
1430  typename inputDataValueType, class ...inputDataProperties,
1431  typename inputFieldValueType, class ...inputFieldProperties>
1432  void
1434  matmatProductDataField( Kokkos::DynRankView<outputFieldValueType,outputFieldProperties...> outputFields,
1435  const Kokkos::DynRankView<inputDataValueType, inputDataProperties...> inputData,
1436  const Kokkos::DynRankView<inputFieldValueType, inputFieldProperties...> inputFields,
1437  const char transpose ) {
1438 
1439 #ifdef HAVE_INTREPID2_DEBUG
1440  {
1441  /*
1442  * Check array rank and spatial dimension range (if applicable)
1443  * (1) inputData(C,P), (C,P,D) or (C,P,D,D); P=1 is admissible to allow multiply by const. data
1444  * (2) inputFields(C,F,P,D,D) or (F,P,D,D);
1445  * (3) outputFields(C,F,P,D,D)
1446  */
1447  // (1) inputData is (C,P), (C, P, D) or (C, P, D, D) and 1 <= D <= 3 is required
1448  INTREPID2_TEST_FOR_EXCEPTION( inputData.rank() < 2 ||
1449  inputData.rank() > 4, std::invalid_argument,
1450  ">>> ERROR (ArrayTools::matmatProductDataField): inputData must have rank 2,3 or 4" );
1451  if (inputData.rank() > 2) {
1452  INTREPID2_TEST_FOR_EXCEPTION( inputData.extent(2) < 1 ||
1453  inputData.extent(2) > 3, std::invalid_argument,
1454  ">>> ERROR (ArrayTools::matmatProductDataField): inputData dimension (2) must be 1,2 or 3" );
1455  }
1456  if (inputData.rank() == 4) {
1457  INTREPID2_TEST_FOR_EXCEPTION( inputData.extent(3) < 1 ||
1458  inputData.extent(3) > 3, std::invalid_argument,
1459  ">>> ERROR (ArrayTools::matmatProductDataField): inputData dimension (3) must be 1,2 or 3" );
1460  }
1461 
1462  // (2) inputFields is (C,F,P,D,D) or (F,P,D,D) and 1 <= (dimension(rank-1), (rank-2)) <= 3 is required.
1463  INTREPID2_TEST_FOR_EXCEPTION( inputFields.rank() < 4 ||
1464  inputFields.rank() > 5, std::invalid_argument,
1465  ">>> ERROR (ArrayTools::matmatProductDataField): inputFields must have rank 4 or 5");
1466  INTREPID2_TEST_FOR_EXCEPTION( inputFields.extent(inputFields.rank()-1) < 1 ||
1467  inputFields.extent(inputFields.rank()-1) > 3, std::invalid_argument,
1468  ">>> ERROR (ArrayTools::matmatProductDataField): inputFields dimension (rank-1) must be 1,2 or 3" );
1469  INTREPID2_TEST_FOR_EXCEPTION( inputFields.extent(inputFields.rank()-2) < 1 ||
1470  inputFields.extent(inputFields.rank()-2) > 3, std::invalid_argument,
1471  ">>> ERROR (ArrayTools::matmatProductDataField): inputFields dimension (rank-2) must be 1,2 or 3" );
1472 
1473  // (3) outputFields is (C,F,P,D,D)
1474  INTREPID2_TEST_FOR_EXCEPTION( outputFields.rank() != 5, std::invalid_argument,
1475  ">>> ERROR (ArrayTools::matmatProductDataField): outputFields must have rank 5" );
1476  INTREPID2_TEST_FOR_EXCEPTION( outputFields.extent(3) < 1 ||
1477  outputFields.extent(3) > 3, std::invalid_argument,
1478  ">>> ERROR (ArrayTools::matmatProductDataField): outputFields dimension (3) must be 1,2 or 3" );
1479  INTREPID2_TEST_FOR_EXCEPTION( outputFields.extent(4) < 1 ||
1480  outputFields.extent(4) > 3, std::invalid_argument,
1481  ">>> ERROR (ArrayTools::matmatProductDataField): outputFields dimension (4) must be 1,2 or 3" );
1482 
1483  /*
1484  * Dimension cross-checks:
1485  * (1) inputData vs. inputFields
1486  * (2) outputFields vs. inputData
1487  * (3) outputFields vs. inputFields
1488  *
1489  * Cross-check (2): outputFields(C,F,P,D,D) vs. inputData(C,P), (C,P,D) or (C,P,D,D):
1490  * dimensions C, and D must match in all cases, dimension P must match only when non-constant
1491  * data is specified (P>1). Do not check P dimensions with constant data, i.e., when P=1 in
1492  * inputData(C,1,...)
1493  */
1494  if (inputData.extent(1) > 1) { // check P dimension if P>1 in inputData
1495  INTREPID2_TEST_FOR_EXCEPTION( outputFields.extent(2) != inputData.extent(1), std::invalid_argument,
1496  ">>> ERROR (ArrayTools::matmatProductDataField): outputFields dimension (2) does not match to inputData dimension (1)" );
1497  }
1498  if (inputData.rank() == 2) { // inputData(C,P) -> C match
1499  INTREPID2_TEST_FOR_EXCEPTION( outputFields.extent(0) != inputData.extent(0), std::invalid_argument,
1500  ">>> ERROR (ArrayTools::matmatProductDataField): outputFields dimension (0) does not match to inputData dimension (0)" );
1501  }
1502  if (inputData.rank() == 3) { // inputData(C,P,D) -> C, D match
1503  const size_type f1[] = { 0, 3, 4 }, f2[] = { 0, 2, 2 };
1504  for (size_type i=0; i<3; ++i) {
1505  INTREPID2_TEST_FOR_EXCEPTION( outputFields.extent(f1[i]) != inputData.extent(f2[i]), std::invalid_argument,
1506  ">>> ERROR (ArrayTools::matmatProductDataField): outputFields dimension does not match to inputData dimension" );
1507  }
1508  }
1509  if (inputData.rank() == 4) { // inputData(C,P,D,D) -> C, D, D match
1510  const size_type f1[] = { 0, 3, 4 }, f2[] = { 0, 2, 3 };
1511  for (size_type i=0; i<3; ++i) {
1512  INTREPID2_TEST_FOR_EXCEPTION( outputFields.extent(f1[i]) != inputData.extent(f2[i]), std::invalid_argument,
1513  ">>> ERROR (ArrayTools::matmatProductDataField): outputFields dimension does not match to inputData dimension" );
1514  }
1515  }
1516 
1517  /*
1518  * Cross-checks (1,3):
1519  */
1520  if (inputFields.rank() == 5) {
1521  // Cross-check (1): inputData(C,P), (C,P,D) or (C,P,D,D) vs. inputFields(C,F,P,D,D): dimensions C, P, D must match
1522  if (inputData.extent(1) > 1) { // check P dimension if P>1 in inputData
1523  INTREPID2_TEST_FOR_EXCEPTION( inputData.extent(1) != inputFields.extent(2), std::invalid_argument,
1524  ">>> ERROR (ArrayTools::matmatProductDataField): inputData dimension (1) does not match to inputFields dimension (2)" );
1525  }
1526  if (inputData.rank() == 2) { // inputData(C,P) -> C match
1527  INTREPID2_TEST_FOR_EXCEPTION( inputData.extent(0) != inputFields.extent(0), std::invalid_argument,
1528  ">>> ERROR (ArrayTools::matmatProductDataField): inputData dimension (0) does not match to inputFields dimension (0)" );
1529  }
1530  if (inputData.rank() == 3) { // inputData(C,P,D) -> C, D match
1531 
1532  const size_type f1[] = { 0, 2, 2 }, f2[] = { 0, 3, 4 };
1533  for (size_type i=0; i<3; ++i) {
1534  INTREPID2_TEST_FOR_EXCEPTION( inputData.extent(f1[i]) != inputFields.extent(f2[i]), std::invalid_argument,
1535  ">>> ERROR (ArrayTools::matmatProductDataField): inputData dimension does not match to inputFields dimension" );
1536  }
1537  }
1538  if (inputData.rank() == 4) { // inputData(C,P,D,D) -> C, D, D match
1539  const size_type f1[] = { 0, 2, 3 }, f2[] = { 0, 3, 4 };
1540  for (size_type i=0; i<3; ++i) {
1541  INTREPID2_TEST_FOR_EXCEPTION( inputData.extent(f1[i]) != inputFields.extent(f2[i]), std::invalid_argument,
1542  ">>> ERROR (ArrayTools::matmatProductDataField): inputData dimension does not match to inputFields dimension" );
1543  }
1544  }
1545 
1546  // Cross-check (3): outputFields(C,F,P,D,D) vs. inputFields(C,F,P,D,D): all dimensions C, F, P, D must match
1547  for (size_type i=0; i<outputFields.rank(); ++i) {
1548  INTREPID2_TEST_FOR_EXCEPTION( outputFields.extent(i) != inputFields.extent(i), std::invalid_argument,
1549  ">>> ERROR (ArrayTools::matmatProductDataField): outputFields dimension does not match to inputFields dimension" );
1550  }
1551  } else {
1552  // Cross-check (1): inputData(C,P), (C,P,D) or (C,P,D,D) vs. inputFields(F,P,D,D): dimensions P, D must match
1553  if (inputData.extent(1) > 1) { // check P if P>1 in inputData
1554  INTREPID2_TEST_FOR_EXCEPTION( inputData.extent(1) != inputFields.extent(1), std::invalid_argument,
1555  ">>> ERROR (ArrayTools::matmatProductDataField): inputData dimension (1) does not match to inputFields dimension (1)" );
1556  }
1557  if (inputData.rank() == 3) {
1558  const size_type f1[] = { 2, 2 }, f2[] = { 2, 3 };
1559  for (size_type i=0; i<2; ++i) {
1560  INTREPID2_TEST_FOR_EXCEPTION( inputData.extent(f1[i]) != inputFields.extent(f2[i]), std::invalid_argument,
1561  ">>> ERROR (ArrayTools::matmatProductDataField): inputData dimension does not match to inputFields dimension" );
1562  }
1563  }
1564  if (inputData.rank() == 4) {
1565  const size_type f1[] = { 2, 3 }, f2[] = { 2, 3 };
1566  for (size_type i=0; i<2; ++i) {
1567  INTREPID2_TEST_FOR_EXCEPTION( inputData.extent(f1[i]) != inputFields.extent(f2[i]), std::invalid_argument,
1568  ">>> ERROR (ArrayTools::matmatProductDataField): inputData dimension does not match to inputFields dimension" );
1569  }
1570  }
1571 
1572  // Cross-check (3): outputFields(C,F,P,D,D) vs. inputFields(F,P,D,D): dimensions F, P, D must match
1573  {
1574  const size_type f1[] = { 1, 2, 3, 4 }, f2[] = { 0, 1, 2, 3 };
1575  for (size_type i=0; i<4; ++i) {
1576  INTREPID2_TEST_FOR_EXCEPTION( outputFields.extent(f1[i]) != inputFields.extent(f2[i]), std::invalid_argument,
1577  ">>> ERROR (ArrayTools::matmatProductDataField): outputFields dimension does not match to inputFields dimension" );
1578  }
1579  }
1580  }
1581  }
1582 #endif
1583  // body
1585  inputData,
1586  inputFields,
1587  true,
1588  transpose == 't' || transpose == 'T' );
1589  }
1590 
1591 
1592 
1593  template<typename DeviceType>
1594  template<typename outputDataValueType, class ...outputDataProperties,
1595  typename inputDataLeftValueType, class ...inputDataLeftProperties,
1596  typename inputDataRightValueType, class ...inputDataRightProperties>
1597  void
1598  ArrayTools<DeviceType>::matmatProductDataData( Kokkos::DynRankView<outputDataValueType, outputDataProperties...> outputData,
1599  const Kokkos::DynRankView<inputDataLeftValueType, inputDataLeftProperties...> inputDataLeft,
1600  const Kokkos::DynRankView<inputDataRightValueType,inputDataRightProperties...> inputDataRight,
1601  const char transpose ) {
1602 
1603 #ifdef HAVE_INTREPID2_DEBUG
1604  {
1605  /*
1606  * Check array rank and spatial dimension range (if applicable)
1607  * (1) inputDataLeft(C,P), (C,P,D) or (C,P,D,D); P=1 is admissible to allow multiply by const. left data
1608  * (2) inputDataRight(C,P,D,D) or (P,D,D);
1609  * (3) outputData(C,P,D,D)
1610  */
1611  // (1) inputDataLeft is (C,P), (C,P,D) or (C,P,D,D) and 1 <= D <= 3 is required
1612  INTREPID2_TEST_FOR_EXCEPTION( inputDataLeft.rank() < 2 ||
1613  inputDataLeft.rank() > 4, std::invalid_argument,
1614  ">>> ERROR (ArrayTools::matmatProductDataData): inputDataLeft must have rank 2,3 or 4" );
1615  if (inputDataLeft.rank() > 2) {
1616  INTREPID2_TEST_FOR_EXCEPTION( inputDataLeft.extent(2) < 1 ||
1617  inputDataLeft.extent(2) > 3, std::invalid_argument,
1618  ">>> ERROR (ArrayTools::matmatProductDataData): inputDataLeft dimension (2) must be 1,2 or 3" );
1619  }
1620  if (inputDataLeft.rank() == 4) {
1621  INTREPID2_TEST_FOR_EXCEPTION( inputDataLeft.extent(3) < 1 ||
1622  inputDataLeft.extent(3) > 3, std::invalid_argument,
1623  ">>> ERROR (ArrayTools::matmatProductDataData): inputDataLeft dimension (3) must be 1,2 or 3" );
1624  }
1625 
1626  // (2) inputDataRight is (C,P,D,D) or (P,D,D) and 1 <= (D=dimension(rank-1),(rank-2)) <= 3 is required.
1627  INTREPID2_TEST_FOR_EXCEPTION( inputDataRight.rank() < 3 ||
1628  inputDataRight.rank() > 4, std::invalid_argument,
1629  ">>> ERROR (ArrayTools::matmatProductDataData): inputDataRight must have rank 3 or 4" );
1630  INTREPID2_TEST_FOR_EXCEPTION( inputDataRight.extent(inputDataRight.rank()-1) < 1 ||
1631  inputDataRight.extent(inputDataRight.rank()-1) > 3, std::invalid_argument,
1632  ">>> ERROR (ArrayTools::matmatProductDataData): inputDataRight (rank-1) must be 1,2 or 3" );
1633  INTREPID2_TEST_FOR_EXCEPTION( inputDataRight.extent(inputDataRight.rank()-2) < 1 ||
1634  inputDataRight.extent(inputDataRight.rank()-2) > 3, std::invalid_argument,
1635  ">>> ERROR (ArrayTools::matmatProductDataData): inputDataRight (rank-2) must be 1,2 or 3" );
1636 
1637  // (3) outputData is (C,P,D,D)
1638  INTREPID2_TEST_FOR_EXCEPTION( outputData.rank() != 4, std::invalid_argument,
1639  ">>> ERROR (ArrayTools::matmatProductDataData): outputData must have rank 4" );
1640  INTREPID2_TEST_FOR_EXCEPTION( outputData.extent(2) < 1 ||
1641  outputData.extent(2) > 3, std::invalid_argument,
1642  ">>> ERROR (ArrayTools::matmatProductDataData): outputData (2) must be 1,2 or 3" );
1643  INTREPID2_TEST_FOR_EXCEPTION( outputData.extent(3) < 1 ||
1644  outputData.extent(3) > 3, std::invalid_argument,
1645  ">>> ERROR (ArrayTools::matmatProductDataData): outputData (3) must be 1,2 or 3" );
1646 
1647  /*
1648  * Dimension cross-checks:
1649  * (1) inputDataLeft vs. inputDataRight
1650  * (2) outputData vs. inputDataLeft
1651  * (3) outputData vs. inputDataRight
1652  *
1653  * Cross-check (2): outputData(C,P,D,D) vs. inputDataLeft(C,P), (C,P,D) or (C,P,D,D):
1654  * dimensions C, and D must match in all cases, dimension P must match only when non-constant
1655  * data is specified (P>1). Do not check P dimensions with constant left data, i.e., when P=1 in
1656  * inputDataLeft(C,1,...)
1657  */
1658  if (inputDataLeft.extent(1) > 1) { // check P dimension if P>1 in inputDataLeft
1659  INTREPID2_TEST_FOR_EXCEPTION( outputData.extent(1) != inputDataLeft.extent(1), std::invalid_argument,
1660  ">>> ERROR (ArrayTools::matmatProductDataData): outputData dimension (1) does not match to inputDataLeft dimension (1)" );
1661  }
1662  if (inputDataLeft.rank() == 2) { // inputDataLeft(C,P): check C
1663  INTREPID2_TEST_FOR_EXCEPTION( outputData.extent(0) != inputDataLeft.extent(0), std::invalid_argument,
1664  ">>> ERROR (ArrayTools::matmatProductDataData): outputData dimension (0) does not match to inputDataLeft dimension (0)" );
1665  }
1666  if (inputDataLeft.rank() == 3) { // inputDataLeft(C,P,D): check C and D
1667  const size_type f1[] = { 0, 2, 3 }, f2[] = { 0, 2, 2 };
1668  for (size_type i=0; i<3; ++i) {
1669  INTREPID2_TEST_FOR_EXCEPTION( outputData.extent(f1[i]) != inputDataLeft.extent(f2[i]), std::invalid_argument,
1670  ">>> ERROR (ArrayTools::matmatProductDataData): outputData dimension does not match to inputDataLeft dimension" );
1671  }
1672  }
1673  if (inputDataLeft.rank() == 4) { // inputDataLeft(C,P,D,D): check C and D
1674  const size_type f1[] = { 0, 2, 3 }, f2[] = { 0, 2, 3 };
1675  for (size_type i=0; i<3; ++i) {
1676  INTREPID2_TEST_FOR_EXCEPTION( outputData.extent(f1[i]) != inputDataLeft.extent(f2[i]), std::invalid_argument,
1677  ">>> ERROR (ArrayTools::matmatProductDataData): outputData dimension does not match to inputDataLeft dimension" );
1678  }
1679  }
1680 
1681  /*
1682  * Cross-checks (1,3):
1683  */
1684  if (inputDataRight.rank() == 4) {
1685  // Cross-check (1): inputDataLeft(C,P), (C,P,D), or (C,P,D,D) vs. inputDataRight(C,P,D,D): dimensions C, P, D must match
1686  if (inputDataLeft.extent(1) > 1) { // check P dimension if P>1 in inputDataLeft
1687  INTREPID2_TEST_FOR_EXCEPTION( inputDataLeft.extent(1) != inputDataRight.extent(1), std::invalid_argument,
1688  ">>> ERROR (ArrayTools::matmatProductDataData): inputDataLeft dimension (1) does not match to inputDataRight dimension (1)" );
1689  }
1690  if (inputDataLeft.rank() == 2) { // inputDataLeft(C,P): check C
1691  INTREPID2_TEST_FOR_EXCEPTION( inputDataLeft.extent(0) != inputDataRight.extent(0), std::invalid_argument,
1692  ">>> ERROR (ArrayTools::matmatProductDataData): inputDataLeft dimension (0) does not match to inputDataRight dimension (0)" );
1693  }
1694  if (inputDataLeft.rank() == 3) { // inputDataLeft(C,P,D): check C and D
1695  const size_type f1[] = { 0, 2, 2 }, f2[] = { 0, 2, 3 };
1696  for (size_type i=0; i<3; ++i) {
1697  INTREPID2_TEST_FOR_EXCEPTION( inputDataLeft.extent(f1[i]) != inputDataRight.extent(f2[i]), std::invalid_argument,
1698  ">>> ERROR (ArrayTools::matmatProductDataData): intputDataLeft dimension does not match to inputDataRight dimension" );
1699  }
1700  }
1701  if (inputDataLeft.rank() == 4) { // inputDataLeft(C,P,D,D): check C and D
1702  const size_type f1[] = { 0, 2, 3 }, f2[] = { 0, 2, 3 };
1703  for (size_type i=0; i<3; ++i) {
1704  INTREPID2_TEST_FOR_EXCEPTION( inputDataLeft.extent(f1[i]) != inputDataRight.extent(f2[i]), std::invalid_argument,
1705  ">>> ERROR (ArrayTools::matmatProductDataData): intputDataLeft dimension does not match to inputDataRight dimension" );
1706  }
1707  }
1708 
1709  // Cross-check (3): outputData(C,P,D,D) vs. inputDataRight(C,P,D,D): all dimensions C, P, D must match
1710  for (size_type i=0; i< outputData.rank(); ++i) {
1711  INTREPID2_TEST_FOR_EXCEPTION( outputData.extent(i) != inputDataRight.extent(i), std::invalid_argument,
1712  ">>> ERROR (ArrayTools::matmatProductDataData): outputData dimension does not match to inputDataRight dimension" );
1713  }
1714  } else {
1715  // Cross-check (1): inputDataLeft(C,P), (C,P,D), or (C,P,D,D) vs. inputDataRight(P,D,D): dimensions P, D must match
1716  if (inputDataLeft.extent(1) > 1) { // check P if P>1 in inputData
1717  INTREPID2_TEST_FOR_EXCEPTION( inputDataLeft.extent(1) != inputDataRight.extent(0), std::invalid_argument,
1718  ">>> ERROR (ArrayTools::matmatProductDataData): inputDataLeft dimension (1) does not match to inputDataRight dimension (0)" );
1719  }
1720  if (inputDataLeft.rank() == 3) { // inputDataLeft(C,P,D): check D
1721  const size_type f1[] = { 2, 2 }, f2[] = { 1, 2 };
1722  for (size_type i=0; i<2; ++i) {
1723  INTREPID2_TEST_FOR_EXCEPTION( inputDataLeft.extent(f1[i]) != inputDataRight.extent(f2[i]), std::invalid_argument,
1724  ">>> ERROR (ArrayTools::matmatProductDataData): intputDataLeft dimension does not match to inputDataRight dimension" );
1725  }
1726  }
1727  if (inputDataLeft.rank() == 4) { // inputDataLeft(C,P,D,D): check D
1728  const size_type f1[] = { 2, 3 }, f2[] = { 1, 2 };
1729  for (size_type i=0; i<2; ++i) {
1730  INTREPID2_TEST_FOR_EXCEPTION( inputDataLeft.extent(f1[i]) != inputDataRight.extent(f2[i]), std::invalid_argument,
1731  ">>> ERROR (ArrayTools::matmatProductDataData): intputDataLeft dimension does not match to inputDataRight dimension" );
1732  }
1733  }
1734  // Cross-check (3): outputData(C,P,D,D) vs. inputDataRight(P,D,D): dimensions P, D must match
1735  {
1736  const size_type f1[] = { 1, 2, 3 }, f2[] = { 0, 1, 2 };
1737  for (size_type i=0; i<3; ++i) {
1738  INTREPID2_TEST_FOR_EXCEPTION( outputData.extent(f1[i]) != inputDataRight.extent(f2[i]), std::invalid_argument,
1739  ">>> ERROR (ArrayTools::matmatProductDataData): outputData dimension does not match to inputDataRight dimension" );
1740  }
1741  }
1742  }
1743  }
1744 #endif
1745  // body
1747  inputDataLeft,
1748  inputDataRight,
1749  false,
1750  transpose == 't' || transpose == 'T' );
1751  }
1752 
1753 } // end namespace Intrepid2
1754 #endif
static void matmatProductDataData(Kokkos::DynRankView< outputDataValueType, outputDataProperties...> outputData, const Kokkos::DynRankView< inputDataLeftValueType, inputDataLeftProperties...> inputDataLeft, const Kokkos::DynRankView< inputDataRightValueType, inputDataRightProperties...> inputDataRight, const char transpose= 'N')
There are two use cases: (1) matrix-matrix product of a rank-4 container inputDataRight with dimensio...
Functor for crossProduct see Intrepid2::ArrayTools for more.
Functor for outerProduct see Intrepid2::ArrayTools for more.
static void crossProductDataData(Kokkos::DynRankView< outputDataValueType, outputDataProperties...> outputData, const Kokkos::DynRankView< inputDataLeftValueType, inputDataLeftProperties...> inputDataLeft, const Kokkos::DynRankView< inputDataRightValueType, inputDataRightProperties...> inputDataRight)
There are two use cases: (1) cross product of a rank-3 container inputDataRight with dimensions (C...
static void crossProductDataField(Kokkos::DynRankView< outputFieldValueType, outputFieldProperties...> outputFields, const Kokkos::DynRankView< inputDataValueType, inputDataProperties...> inputData, const Kokkos::DynRankView< inputFieldValueType, inputFieldProperties...> inputFields)
There are two use cases: (1) cross product of a rank-4 container inputFields with dimensions (C...
Functor for matmatProduct see Intrepid2::ArrayTools for more.
static void matvecProductDataField(Kokkos::DynRankView< outputFieldValueType, outputFieldProperties...> outputFields, const Kokkos::DynRankView< inputDataValueType, inputDataProperties...> inputData, const Kokkos::DynRankView< inputFieldValueType, inputFieldProperties...> inputFields, const char transpose= 'N')
There are two use cases: (1) matrix-vector product of a rank-4 container inputFields with dimensions ...
Functor for matvecProduct; new version avoids both subviews and branching. See Intrepid2::ArrayTools ...
static void outerProductDataField(Kokkos::DynRankView< outputFieldValueType, outputFieldProperties...> outputFields, const Kokkos::DynRankView< inputDataValueType, inputDataProperties...> inputData, const Kokkos::DynRankView< inputFieldValueType, inputFieldProperties...> inputFields)
There are two use cases: (1) outer product of a rank-4 container inputFields with dimensions (C...
static void matmatProductDataField(Kokkos::DynRankView< outputFieldValueType, outputFieldProperties...> outputFields, const Kokkos::DynRankView< inputDataValueType, inputDataProperties...> inputData, const Kokkos::DynRankView< inputFieldValueType, inputFieldProperties...> inputFields, const char transpose= 'N')
There are two use cases: (1) matrix-matrix product of a rank-5 container inputFields with dimensions ...
static void outerProductDataData(Kokkos::DynRankView< outputDataValueType, outputDataProperties...> outputData, const Kokkos::DynRankView< inputDataLeftValuetype, inputDataLeftProperties...> inputDataLeft, const Kokkos::DynRankView< inputDataRightValueType, inputDataRightProperties...> inputDataRight)
There are two use cases: (1) outer product of a rank-3 container inputDataRight with dimensions (C...
Utility class that provides methods for higher-order algebraic manipulation of user-defined arrays...
static void matvecProductDataData(Kokkos::DynRankView< outputDataValueType, outputDataProperties...> outputData, const Kokkos::DynRankView< inputDataLeftValueType, inputDataLeftProperties...> inputDataLeft, const Kokkos::DynRankView< inputDataRightValueType, inputDataRightProperties...> inputDataRight, const char transpose= 'N')
There are two use cases: (1) matrix-vector product of a rank-3 container inputDataRight with dimensio...