42#ifndef STOKHOS_SIMPLE_TILED_CRS_PRODUCT_TENSOR_HPP
43#define STOKHOS_SIMPLE_TILED_CRS_PRODUCT_TENSOR_HPP
45#include "Kokkos_Core.hpp"
51#include "Teuchos_ParameterList.hpp"
60template<
typename ValueType,
class ExecutionSpace >
81#if defined( KOKKOS_ENABLE_CUDA )
82 std::is_same<ExecutionSpace,Kokkos::Cuda>::value;
93 typedef Kokkos::View< value_type[], execution_space >
vec_type;
96 typedef Kokkos::View< size_type[][2], Kokkos::LayoutLeft, execution_space >
coord2_array_type;
98 typedef Kokkos::View< size_type*, execution_space >
i_size_type;
99 typedef Kokkos::View< size_type*, execution_space >
num_j_type;
102 typedef Kokkos::View< size_type**, execution_space >
num_k_type;
104 typedef Kokkos::View< size_type***, execution_space >
k_size_type;
106 typedef Kokkos::View< size_type****, Kokkos::LayoutRight, execution_space >
row_map_type;
107 typedef Kokkos::View< size_type****, Kokkos::LayoutRight, execution_space >
num_entry_type;
134 template <
typename coord_t>
220 KOKKOS_INLINE_FUNCTION
224 KOKKOS_INLINE_FUNCTION
228 KOKKOS_INLINE_FUNCTION
232 KOKKOS_INLINE_FUNCTION
236 KOKKOS_INLINE_FUNCTION
240 KOKKOS_INLINE_FUNCTION
244 KOKKOS_INLINE_FUNCTION
250 KOKKOS_INLINE_FUNCTION
256 KOKKOS_INLINE_FUNCTION
261 KOKKOS_INLINE_FUNCTION
268 KOKKOS_INLINE_FUNCTION
275 KOKKOS_INLINE_FUNCTION
282 KOKKOS_INLINE_FUNCTION
289 KOKKOS_INLINE_FUNCTION
296 KOKKOS_INLINE_FUNCTION
302 KOKKOS_INLINE_FUNCTION
308 KOKKOS_INLINE_FUNCTION
314 KOKKOS_INLINE_FUNCTION
319 KOKKOS_INLINE_FUNCTION
324 KOKKOS_INLINE_FUNCTION
328 KOKKOS_INLINE_FUNCTION
331 template <
typename OrdinalType>
335 const Teuchos::ParameterList& params)
339 using Teuchos::ParameterList;
340 using Teuchos::Array;
343 typedef typename Cijk_type::i_iterator i_iterator;
344 typedef typename Cijk_type::ik_iterator ik_iterator;
345 typedef typename Cijk_type::ikj_iterator ikj_iterator;
347 const size_type i_tile_size = params.get<OrdinalType>(
"Tile Size");
352 i_iterator i_end = Cijk.
i_end();
353 for (i_iterator i_it=
i_begin; i_it!=i_end; ++i_it) {
354 OrdinalType i = index(i_it);
356 ik_iterator k_end = Cijk.
k_end(i_it);
357 for (ik_iterator k_it =
k_begin; k_it != k_end; ++k_it) {
358 OrdinalType k = index(k_it);
360 ikj_iterator j_end = Cijk.
j_end(k_it);
361 for (ikj_iterator j_it =
j_begin; j_it != j_end; ++j_it) {
362 OrdinalType
j = index(j_it);
364 ValueType c = Stokhos::value(j_it);
365 Cijk_sym.add_term(i,
j, k, c);
370 Cijk_sym.fillComplete();
375 size_type num_i_parts = (basis_size + i_tile_size-1) / i_tile_size;
378 Array<ITile> i_tiles(num_i_parts);
379 for (
size_type i=0; i<num_i_parts; ++i) {
380 i_tiles[i].lower = i*its;
381 i_tiles[i].upper = std::min(basis_size, (i+1)*its);
382 i_tiles[i].parts.resize(1);
383 i_tiles[i].parts[0].lower = basis_size;
384 i_tiles[i].parts[0].upper = 0;
389 for (i_iterator i_it=Cijk_sym.i_begin(); i_it!=Cijk_sym.i_end(); ++i_it) {
390 OrdinalType i = index(i_it);
394 while (idx < num_i_parts && i >= i_tiles[idx].lower) ++idx;
396 TEUCHOS_ASSERT(idx >= 0 && idx < num_i_parts);
398 ik_iterator
k_begin = Cijk_sym.k_begin(i_it);
399 ik_iterator k_end = Cijk_sym.k_end(i_it);
400 for (ik_iterator k_it =
k_begin; k_it != k_end; ++k_it) {
401 OrdinalType
j = index(k_it);
403 if (
j < i_tiles[idx].parts[0].lower)
404 i_tiles[idx].parts[0].lower =
j;
405 if (
j > i_tiles[idx].parts[0].upper)
406 i_tiles[idx].parts[0].upper =
j;
409 for (
size_type idx=0; idx<num_i_parts; ++idx) {
410 size_type lower = i_tiles[idx].parts[0].lower;
411 size_type upper = i_tiles[idx].parts[0].upper;
413 size_type num_j_parts = (range + j_tile_size-1) / j_tile_size;
417 Array<JTile> j_tiles(num_j_parts);
419 j_tiles[
j].lower = lower +
j*jts;
420 j_tiles[
j].upper = std::min(upper+1, lower + (
j+1)*jts);
421 j_tiles[
j].parts.resize(1);
422 j_tiles[
j].parts[0].lower = basis_size;
423 j_tiles[
j].parts[0].upper = 0;
425 i_tiles[idx].parts.swap(j_tiles);
429 for (i_iterator i_it=Cijk_sym.i_begin(); i_it!=Cijk_sym.i_end(); ++i_it) {
430 OrdinalType i = index(i_it);
434 while (idx < num_i_parts && i >= i_tiles[idx].lower) ++idx;
436 TEUCHOS_ASSERT(idx >= 0 && idx < num_i_parts);
438 ik_iterator
k_begin = Cijk_sym.k_begin(i_it);
439 ik_iterator k_end = Cijk_sym.k_end(i_it);
440 for (ik_iterator k_it =
k_begin; k_it != k_end; ++k_it) {
441 OrdinalType
j = index(k_it);
444 size_type num_j_parts = i_tiles[idx].parts.size();
446 while (jdx < num_j_parts && j >= i_tiles[idx].parts[jdx].lower) ++jdx;
448 TEUCHOS_ASSERT(jdx >= 0 && jdx < num_j_parts);
450 ikj_iterator
j_begin = Cijk_sym.j_begin(k_it);
451 ikj_iterator j_end = Cijk_sym.j_end(k_it);
452 for (ikj_iterator j_it =
j_begin; j_it != j_end; ++j_it) {
453 OrdinalType k = index(j_it);
454 ValueType cijk = Stokhos::value(j_it);
458 i_tiles[idx].parts[jdx].parts[0].parts.push_back(
coord);
459 if (k < i_tiles[idx].parts[jdx].parts[0].lower)
460 i_tiles[idx].parts[jdx].parts[0].lower = k;
461 if (k > i_tiles[idx].parts[jdx].parts[0].upper)
462 i_tiles[idx].parts[jdx].parts[0].upper = k;
470 for (
size_type idx=0; idx<num_i_parts; ++idx) {
471 size_type num_j_parts = i_tiles[idx].parts.size();
472 for (
size_type jdx=0; jdx<num_j_parts; ++jdx) {
473 size_type lower = i_tiles[idx].parts[jdx].parts[0].lower;
474 size_type upper = i_tiles[idx].parts[jdx].parts[0].upper;
476 size_type num_k_parts = (range + j_tile_size-1) / j_tile_size;
480 Array<KTile> k_tiles(num_k_parts);
481 for (
size_type k=0; k<num_k_parts; ++k) {
482 k_tiles[k].lower = lower + k*kts;
483 k_tiles[k].upper = std::min(upper+1, lower + (k+1)*kts);
485 size_type num_k = i_tiles[idx].parts[jdx].parts[0].parts.size();
487 size_type i = i_tiles[idx].parts[jdx].parts[0].parts[l].i;
488 size_type j = i_tiles[idx].parts[jdx].parts[0].parts[l].j;
489 size_type k = i_tiles[idx].parts[jdx].parts[0].parts[l].k;
490 value_type cijk = i_tiles[idx].parts[jdx].parts[0].parts[l].cijk;
494 while (kdx < num_k_parts && k >= k_tiles[kdx].lower) ++kdx;
496 TEUCHOS_ASSERT(kdx >= 0 && kdx < num_k_parts);
500 k_tiles[kdx].parts.push_back(
coord);
502 if (
j != k) ++num_coord;
506 Array<KTile> k_tiles2;
507 for (
size_type k=0; k<num_k_parts; ++k) {
508 if (k_tiles[k].parts.size() > 0)
509 k_tiles2.push_back(k_tiles[k]);
511 i_tiles[idx].parts[jdx].parts.swap(k_tiles2);
518 size_type max_num_j_parts = 0, max_num_k_parts = 0;
519 Array< Array< Array< Array<size_type> > > > coord_work(num_i_parts);
520 for (
size_type idx=0; idx<num_i_parts; ++idx) {
521 size_type num_j_parts = i_tiles[idx].parts.size();
522 max_num_j_parts = std::max(max_num_j_parts, num_j_parts);
523 coord_work[idx].resize(num_j_parts);
524 for (
size_type jdx=0; jdx<num_j_parts; ++jdx) {
525 size_type num_k_parts = i_tiles[idx].parts[jdx].parts.size();
526 max_num_k_parts = std::max(max_num_k_parts, num_k_parts);
527 coord_work[idx][jdx].resize(num_k_parts);
528 for (
size_type kdx=0; kdx<num_k_parts; ++kdx) {
529 size_type num_rows = i_tiles[idx].upper - i_tiles[idx].lower + 1;
530 total_num_rows += num_rows;
531 max_num_rows = std::max(max_num_rows, num_rows);
532 coord_work[idx][jdx][kdx].resize(num_rows, 0);
534 size_type nc = i_tiles[idx].parts[jdx].parts[kdx].parts.size();
536 size_type i = i_tiles[idx].parts[jdx].parts[kdx].parts[c].i;
538 ++(coord_work[idx][jdx][kdx][i-
i_begin]);
546 for (
size_type idx=0; idx<num_i_parts; ++idx) {
547 size_type num_j_parts = i_tiles[idx].parts.size();
548 for (
size_type jdx=0; jdx<num_j_parts; ++jdx) {
549 size_type num_k_parts = i_tiles[idx].parts[jdx].parts.size();
550 for (
size_type kdx=0; kdx<num_k_parts; ++kdx) {
551 size_type sz = coord_work[idx][jdx][kdx].size();
553 const size_t rem = coord_work[idx][jdx][kdx][i] %
tensor_align;
556 coord_work[idx][jdx][kdx][i] += pad;
580 max_num_j_parts, max_num_k_parts,
583 max_num_j_parts, max_num_k_parts,
591 typename value_array_type::HostMirror host_value =
592 Kokkos::create_mirror_view(tensor.
m_value);
593 typename coord_array_type::HostMirror host_coord =
594 Kokkos::create_mirror_view(tensor.
m_coord);
595 typename coord2_array_type::HostMirror host_coord2 =
596 Kokkos::create_mirror_view(tensor.
m_coord2);
597 typename i_begin_type::HostMirror host_i_begin =
598 Kokkos::create_mirror_view(tensor.
m_i_begin);
599 typename i_size_type::HostMirror host_i_size =
600 Kokkos::create_mirror_view(tensor.
m_i_size);
601 typename num_j_type::HostMirror host_num_j =
602 Kokkos::create_mirror_view(tensor.
m_num_j);
603 typename j_begin_type::HostMirror host_j_begin =
604 Kokkos::create_mirror_view(tensor.
m_j_begin);
605 typename j_size_type::HostMirror host_j_size =
606 Kokkos::create_mirror_view(tensor.
m_j_size);
607 typename num_k_type::HostMirror host_num_k =
608 Kokkos::create_mirror_view(tensor.
m_num_k);
609 typename k_begin_type::HostMirror host_k_begin =
610 Kokkos::create_mirror_view(tensor.
m_k_begin);
611 typename k_size_type::HostMirror host_k_size =
612 Kokkos::create_mirror_view(tensor.
m_k_size);
613 typename row_map_type::HostMirror host_row_map =
614 Kokkos::create_mirror_view(tensor.
m_row_map);
615 typename num_entry_type::HostMirror host_num_entry =
620 for (
size_type idx=0; idx<num_i_parts; ++idx) {
621 size_type num_j_parts = i_tiles[idx].parts.size();
622 for (
size_type jdx=0; jdx<num_j_parts; ++jdx) {
623 size_type num_k_parts = i_tiles[idx].parts[jdx].parts.size();
624 for (
size_type kdx=0; kdx<num_k_parts; ++kdx) {
625 size_type nc = coord_work[idx][jdx][kdx].size();
626 host_row_map(idx,jdx,kdx,0) = sum;
628 sum += coord_work[idx][jdx][kdx][t];
629 host_row_map(idx,jdx,kdx,t+1) = sum;
630 host_num_entry(idx,jdx,kdx,t) = 0;
637 for (
size_type idx=0; idx<num_i_parts; ++idx) {
638 size_type num_j_parts = i_tiles[idx].parts.size();
639 for (
size_type jdx=0; jdx<num_j_parts; ++jdx) {
640 size_type num_k_parts = i_tiles[idx].parts[jdx].parts.size();
641 for (
size_type kdx=0; kdx<num_k_parts; ++kdx) {
642 size_type nc = coord_work[idx][jdx][kdx].size();
644 coord_work[idx][jdx][kdx][t] = host_row_map(idx,jdx,kdx,t);
651 for (
size_type idx=0; idx<num_i_parts; ++idx) {
652 host_i_begin(idx) = i_tiles[idx].lower;
653 host_i_size(idx) = i_tiles[idx].upper - i_tiles[idx].lower;
654 TEUCHOS_ASSERT(host_i_size(idx) <= i_tile_size);
655 size_type num_j_parts = i_tiles[idx].parts.size();
656 host_num_j(idx) = num_j_parts;
657 for (
size_type jdx=0; jdx<num_j_parts; ++jdx) {
658 host_j_begin(idx,jdx) = i_tiles[idx].parts[jdx].lower;
659 host_j_size(idx,jdx) = i_tiles[idx].parts[jdx].upper -
660 i_tiles[idx].parts[jdx].lower;
662 size_type num_k_parts = i_tiles[idx].parts[jdx].parts.size();
663 host_num_k(idx,jdx) = num_k_parts;
664 for (
size_type kdx=0; kdx<num_k_parts; ++kdx) {
665 host_k_begin(idx,jdx,kdx) = i_tiles[idx].parts[jdx].parts[kdx].lower;
666 host_k_size(idx,jdx,kdx) = i_tiles[idx].parts[jdx].parts[kdx].upper -
667 i_tiles[idx].parts[jdx].parts[kdx].lower;
670 size_type nc = i_tiles[idx].parts[jdx].parts[kdx].parts.size();
672 Coord s = i_tiles[idx].parts[jdx].parts[kdx].parts[t];
678 const size_type row = i - host_i_begin(idx);
679 const size_type n = coord_work[idx][jdx][kdx][row];
680 ++coord_work[idx][jdx][kdx][row];
682 host_value(n) = (
j != k) ? c : 0.5*c;
683 host_coord2(n,0) =
j - host_j_begin(idx,jdx);
684 host_coord2(n,1) = k - host_k_begin(idx,jdx,kdx);
685 host_coord(n) = (host_coord2(n,1) << 16) | host_coord2(n,0);
687 ++host_num_entry(idx,jdx,kdx,row);
695 Kokkos::deep_copy(tensor.
m_value, host_value);
696 Kokkos::deep_copy(tensor.
m_coord, host_coord);
697 Kokkos::deep_copy(tensor.
m_coord2, host_coord2);
698 Kokkos::deep_copy(tensor.
m_i_begin, host_i_begin);
699 Kokkos::deep_copy(tensor.
m_i_size, host_i_size);
700 Kokkos::deep_copy(tensor.
m_num_j, host_num_j);
701 Kokkos::deep_copy(tensor.
m_j_begin, host_j_begin);
702 Kokkos::deep_copy(tensor.
m_j_size, host_j_size);
703 Kokkos::deep_copy(tensor.
m_num_k, host_num_k);
704 Kokkos::deep_copy(tensor.
m_k_begin, host_k_begin);
705 Kokkos::deep_copy(tensor.
m_k_size, host_k_size);
706 Kokkos::deep_copy(tensor.
m_row_map, host_row_map);
707 Kokkos::deep_copy(tensor.
m_num_entry, host_num_entry);
710 for (
size_type idx=0; idx<num_i_parts; ++idx) {
711 size_type num_j_parts = i_tiles[idx].parts.size();
712 for (
size_type jdx=0; jdx<num_j_parts; ++jdx) {
713 size_type num_k_parts = i_tiles[idx].parts[jdx].parts.size();
714 for (
size_type kdx=0; kdx<num_k_parts; ++kdx) {
715 for (
size_type i = 0; i < host_i_size(idx); ++i) {
716 tensor.
m_flops += 5*host_num_entry(idx,jdx,kdx,i) + 1;
726template<
class Device,
typename OrdinalType,
typename ValueType >
727SimpleTiledCrsProductTensor<ValueType, Device>
731 const Teuchos::ParameterList& params)
734 basis, Cijk, params);
737template <
typename ValueType,
typename Device >
745 template<
typename MatrixValue ,
typename VectorValue >
746 KOKKOS_INLINE_FUNCTION
748 const MatrixValue *
const a ,
749 const VectorValue *
const x ,
750 VectorValue *
const y )
756 for (
size_type i_tile = 0; i_tile<n_i_tile; ++i_tile) {
761 for (
size_type j_tile = 0; j_tile<n_j_tile; ++j_tile) {
766 for (
size_type k_tile = 0; k_tile<n_k_tile; ++k_tile) {
773 tensor.
num_entry(i_tile,j_tile,k_tile,i);
776 const size_type iEntryEnd = iEntryBeg + nEntry;
779 VectorValue ytmp = 0 ;
782 if (block_size > 1) {
783 const size_type nBlock = nEntry / block_size;
784 const size_type nEntryB = nBlock * block_size;
785 const size_type iEnd = iEntryBeg + nEntryB;
789 int j[block_size], k[block_size];
791 for ( ; iEntry < iEnd ; iEntry += block_size ) {
793 for (
size_type ii=0; ii<block_size; ++ii) {
794 j[ii] = tensor.
coord(iEntry+ii,0) + j_begin;
795 k[ii] = tensor.
coord(iEntry+ii,1) + k_begin;
797 TV aj(a,
j), ak(a, k), xj(x,
j), xk(x, k),
798 c(&(tensor.
value(iEntry)));
813 for ( ; iEntry<iEntryEnd; ++iEntry) {
817 ytmp += tensor.
value(iEntry) * ( a[
j] * x[k] + a[k] * x[
j] );
820 y[i+i_begin] += ytmp;
828 KOKKOS_INLINE_FUNCTION
832 KOKKOS_INLINE_FUNCTION
static KOKKOS_INLINE_FUNCTION size_type vector_size(const tensor_type &tensor)
SimpleTiledCrsProductTensor< ValueType, Device > tensor_type
static KOKKOS_INLINE_FUNCTION size_type matrix_size(const tensor_type &tensor)
static KOKKOS_INLINE_FUNCTION void apply(const tensor_type &tensor, const MatrixValue *const a, const VectorValue *const x, VectorValue *const y)
Device::size_type size_type
virtual ordinal_type size() const =0
Return total size of basis.
Abstract base class for multivariate orthogonal polynomials generated from tensor products of univari...
KOKKOS_INLINE_FUNCTION size_type num_non_zeros() const
Number of non-zero's.
KOKKOS_INLINE_FUNCTION size_type num_k_tiles(const size_type i, const size_type j) const
Number k-tiles.
static const size_type cuda_vectorsize
Kokkos::View< size_type ***, execution_space > k_size_type
KOKKOS_INLINE_FUNCTION size_type max_jk_tile_size() const
Max size of any j/k tile.
coord2_array_type m_coord2
static const bool use_intrinsics
KOKKOS_INLINE_FUNCTION size_type j_begin(const size_type i, const size_type j) const
Begin entries with for tile 'i,j'.
Kokkos::View< size_type ****, Kokkos::LayoutRight, execution_space > num_entry_type
KOKKOS_INLINE_FUNCTION size_type k_begin(const size_type i, const size_type j, const size_type k) const
Begin entries with for tile 'i,j,k'.
KOKKOS_INLINE_FUNCTION size_type num_j_tiles(const size_type i) const
Number j-tiles.
KOKKOS_INLINE_FUNCTION size_type entry_end(const size_type i, const size_type j, const size_type k, const size_type r) const
End entries for tile (i,j,k) and row r.
static const size_type host_vectorsize
KOKKOS_INLINE_FUNCTION size_type i_begin(const size_type i) const
Begin entries with for tile 'i'.
~SimpleTiledCrsProductTensor()
KOKKOS_INLINE_FUNCTION size_type num_flops() const
Number flop's per multiply-add.
static const bool is_cuda
SimpleTiledCrsProductTensor & operator=(const SimpleTiledCrsProductTensor &rhs)
Kokkos::View< size_type **, execution_space > j_size_type
KOKKOS_INLINE_FUNCTION size_type max_i_tile_size() const
Max size of any i tile.
Kokkos::View< size_type ****, Kokkos::LayoutRight, execution_space > row_map_type
KOKKOS_INLINE_FUNCTION size_type dimension() const
Dimension of the tensor.
KOKKOS_INLINE_FUNCTION const size_type & coord(const size_type entry) const
Coordinates of an entry.
Kokkos::View< value_type[], execution_space > value_array_type
KOKKOS_INLINE_FUNCTION size_type k_size(const size_type i, const size_type j, const size_type k) const
Number of entries with for tile 'i,j'.
Kokkos::View< size_type *, execution_space > i_begin_type
KOKKOS_INLINE_FUNCTION size_type entry_begin(const size_type i, const size_type j, const size_type k, const size_type r) const
Begin entries for tile (i,j,k) and row r.
static const size_type vectorsize
static SimpleTiledCrsProductTensor create(const Stokhos::ProductBasis< OrdinalType, ValueType > &basis, const Stokhos::Sparse3Tensor< OrdinalType, ValueType > &Cijk, const Teuchos::ParameterList ¶ms)
KOKKOS_INLINE_FUNCTION size_type entry_count() const
Number of sparse entries.
KOKKOS_INLINE_FUNCTION size_type num_entry(const size_type i, const size_type j, const size_type k, const size_type r) const
Number of entries for tile (i,j,k) and row r.
Kokkos::View< size_type **, execution_space > num_k_type
Kokkos::View< size_type ***, execution_space > k_begin_type
SimpleTiledCrsProductTensor()
KOKKOS_INLINE_FUNCTION size_type num_i_tiles() const
Number i-tiles.
static const size_type tensor_align
Kokkos::View< size_type[], execution_space > coord_array_type
ExecutionSpace execution_space
size_type m_max_i_tile_size
Kokkos::View< size_type *, execution_space > num_j_type
num_entry_type m_num_entry
Kokkos::View< size_type[][2], Kokkos::LayoutLeft, execution_space > coord2_array_type
KOKKOS_INLINE_FUNCTION const size_type & coord(const size_type entry, const size_type c) const
Coordinates of an entry.
KOKKOS_INLINE_FUNCTION size_type i_size(const size_type i) const
Number of entries with for tile 'i'.
size_type m_max_jk_tile_size
Kokkos::View< value_type[], execution_space > vec_type
Kokkos::View< size_type **, execution_space > j_begin_type
Kokkos::View< size_type *, execution_space > i_size_type
SimpleTiledCrsProductTensor(const SimpleTiledCrsProductTensor &rhs)
KOKKOS_INLINE_FUNCTION const value_type & value(const size_type entry) const
Value of an entry.
KOKKOS_INLINE_FUNCTION size_type j_size(const size_type i, const size_type j) const
Number of entries with for tile 'i,j'.
Data structure storing a sparse 3-tensor C(i,j,k) in a a compressed format.
kj_iterator j_end(const k_iterator &k) const
Iterator pointing to last j entry for given k.
k_iterator k_begin() const
Iterator pointing to first k entry.
kji_iterator i_begin(const kj_iterator &j) const
Iterator pointing to first i entry for given j and k.
kj_iterator j_begin(const k_iterator &k) const
Iterator pointing to first j entry for given k.
kji_iterator i_end(const kj_iterator &j) const
Iterator pointing to last i entry for given j and k.
ordinal_type num_entries() const
Return number of non-zero entries.
k_iterator k_end() const
Iterator pointing to last k entry.
Top-level namespace for Stokhos classes and functions.
SimpleTiledCrsProductTensor< ValueType, Device > create_simple_tiled_product_tensor(const Stokhos::ProductBasis< OrdinalType, ValueType > &basis, const Stokhos::Sparse3Tensor< OrdinalType, ValueType > &Cijk, const Teuchos::ParameterList ¶ms)
Teuchos::Array< coord_t > parts