15 #ifndef Intrepid2_TensorBasis_h
16 #define Intrepid2_TensorBasis_h
18 #include <Kokkos_DynRankView.hpp>
20 #include <Teuchos_RCP.hpp>
22 #include <Intrepid2_config.h>
38 template<ordinal_type spaceDim>
39 KOKKOS_INLINE_FUNCTION
40 ordinal_type getDkEnumeration(
const Kokkos::Array<int,spaceDim> &entries);
42 template<ordinal_type spaceDim>
43 KOKKOS_INLINE_FUNCTION
44 void getDkEnumerationInverse(Kokkos::Array<int,spaceDim> &entries,
const ordinal_type dkEnum,
const ordinal_type operatorOrder);
47 KOKKOS_INLINE_FUNCTION
48 void getDkEnumerationInverse<1>(Kokkos::Array<int,1> &entries,
const ordinal_type dkEnum,
const ordinal_type operatorOrder)
50 entries[0] = operatorOrder;
54 KOKKOS_INLINE_FUNCTION
55 void getDkEnumerationInverse<2>(Kokkos::Array<int,2> &entries,
const ordinal_type dkEnum,
const ordinal_type operatorOrder)
57 entries[0] = operatorOrder - dkEnum;
62 KOKKOS_INLINE_FUNCTION
63 void getDkEnumerationInverse<3>(Kokkos::Array<int,3> &entries,
const ordinal_type dkEnum,
const ordinal_type operatorOrder)
68 for (ordinal_type yMult=0; yMult<=operatorOrder; yMult++)
70 for (ordinal_type zMult=0; zMult<=operatorOrder-yMult; zMult++)
72 const ordinal_type xMult = operatorOrder-(zMult+yMult);
73 if (dkEnum == getDkEnumeration<3>(xMult,yMult,zMult))
84 template<ordinal_type spaceDim>
85 KOKKOS_INLINE_FUNCTION
86 void getDkEnumerationInverse(Kokkos::Array<int,spaceDim> &entries,
const ordinal_type dkEnum,
const ordinal_type operatorOrder)
93 for (
int k0=0; k0<=operatorOrder; k0++)
96 for (
int d=1; d<spaceDim-1; d++)
101 if (spaceDim > 1) entries[spaceDim-1] = operatorOrder - k0;
102 else if (k0 != operatorOrder)
continue;
103 const ordinal_type dkEnumFor_k0 = getDkEnumeration<spaceDim>(entries);
105 if (dkEnumFor_k0 > dkEnum)
continue;
106 else if (dkEnumFor_k0 == dkEnum)
return;
115 constexpr ordinal_type sizeForSubArray = (spaceDim > 2) ? spaceDim - 1 : 1;
116 Kokkos::Array<int,sizeForSubArray> subEntries = {};
119 getDkEnumerationInverse<spaceDim-1>(subEntries, dkEnum - dkEnumFor_k0 - 1, operatorOrder - entries[0]);
121 for (
int i=1; i<spaceDim; i++)
123 entries[i] = subEntries[i-1];
132 KOKKOS_INLINE_FUNCTION
133 ordinal_type getDkEnumeration<1>(
const Kokkos::Array<int,1> &entries)
135 return getDkEnumeration<1>(entries[0]);
138 template<ordinal_type spaceDim>
139 KOKKOS_INLINE_FUNCTION
140 ordinal_type getDkEnumeration(
const Kokkos::Array<int,spaceDim> &entries)
142 ordinal_type k_minus_k0 = 0;
146 constexpr ordinal_type sizeForSubArray = (spaceDim > 2) ? spaceDim - 1 : 1;
147 Kokkos::Array<int,sizeForSubArray> remainingEntries;
148 for (
int i=1; i<spaceDim; i++)
150 k_minus_k0 += entries[i];
151 remainingEntries[i-1] = entries[i];
160 EOperator opFor_k_minus_k0_minus_1 = (k_minus_k0 > 1) ? EOperator(OPERATOR_D1 + k_minus_k0 - 2) : EOperator(OPERATOR_VALUE);
161 const ordinal_type dkCardinality = getDkCardinality(opFor_k_minus_k0_minus_1, spaceDim);
162 const ordinal_type dkEnum = dkCardinality + getDkEnumeration<sizeForSubArray>(remainingEntries);
167 template<ordinal_type spaceDim1, ordinal_type spaceDim2>
168 KOKKOS_INLINE_FUNCTION
169 ordinal_type getDkTensorIndex(
const ordinal_type dkEnum1,
const ordinal_type operatorOrder1,
170 const ordinal_type dkEnum2,
const ordinal_type operatorOrder2)
172 Kokkos::Array<int,spaceDim1> entries1 = {};
173 getDkEnumerationInverse<spaceDim1>(entries1, dkEnum1, operatorOrder1);
175 Kokkos::Array<int,spaceDim2> entries2 = {};
176 getDkEnumerationInverse<spaceDim2>(entries2, dkEnum2, operatorOrder2);
178 const int spaceDim = spaceDim1 + spaceDim2;
179 Kokkos::Array<int,spaceDim> entries;
181 for (ordinal_type d=0; d<spaceDim1; d++)
183 entries[d] = entries1[d];
186 for (ordinal_type d=0; d<spaceDim2; d++)
188 entries[d+spaceDim1] = entries2[d];
191 return getDkEnumeration<spaceDim>(entries);
194 template<
typename BasisBase>
203 std::vector< std::vector<EOperator> > ops;
204 std::vector<double> weights;
205 ordinal_type numBasisComponents_;
206 bool rotateXYNinetyDegrees_ =
false;
208 OperatorTensorDecomposition(
const std::vector<EOperator> &opsBasis1,
const std::vector<EOperator> &opsBasis2,
const std::vector<double> vectorComponentWeights)
210 weights(vectorComponentWeights),
211 numBasisComponents_(2)
213 const ordinal_type size = opsBasis1.size();
214 const ordinal_type opsBasis2Size = opsBasis2.size();
215 const ordinal_type weightsSize = weights.size();
216 INTREPID2_TEST_FOR_EXCEPTION(size != opsBasis2Size, std::invalid_argument,
"opsBasis1.size() != opsBasis2.size()");
217 INTREPID2_TEST_FOR_EXCEPTION(size != weightsSize, std::invalid_argument,
"opsBasis1.size() != weights.size()");
219 for (ordinal_type i=0; i<size; i++)
221 ops.push_back(std::vector<EOperator>{opsBasis1[i],opsBasis2[i]});
225 OperatorTensorDecomposition(
const std::vector< std::vector<EOperator> > &vectorEntryOps,
const std::vector<double> &vectorComponentWeights)
228 weights(vectorComponentWeights)
230 const ordinal_type numVectorComponents = ops.size();
231 const ordinal_type weightsSize = weights.size();
232 INTREPID2_TEST_FOR_EXCEPTION(numVectorComponents != weightsSize, std::invalid_argument,
"opsBasis1.size() != weights.size()");
234 INTREPID2_TEST_FOR_EXCEPTION(numVectorComponents == 0, std::invalid_argument,
"must have at least one entry!");
236 ordinal_type numBases = 0;
237 for (ordinal_type i=0; i<numVectorComponents; i++)
241 numBases = ops[i].size();
243 else if (ops[i].size() != 0)
245 const ordinal_type opsiSize = ops[i].size();
246 INTREPID2_TEST_FOR_EXCEPTION(numBases != opsiSize, std::invalid_argument,
"must have one operator for each basis in each nontrivial entry in vectorEntryOps");
249 INTREPID2_TEST_FOR_EXCEPTION(numBases == 0, std::invalid_argument,
"at least one vectorEntryOps entry must be non-trivial");
250 numBasisComponents_ = numBases;
257 numBasisComponents_(basisOps.size())
262 ops({ std::vector<EOperator>{opBasis1, opBasis2} }),
264 numBasisComponents_(2)
269 ops({ std::vector<EOperator>{opBasis1, opBasis2, opBasis3} }),
271 numBasisComponents_(3)
274 ordinal_type numVectorComponents()
const
279 ordinal_type numBasisComponents()
const
281 return numBasisComponents_;
284 double weight(
const ordinal_type &vectorComponentOrdinal)
const
286 return weights[vectorComponentOrdinal];
289 bool identicallyZeroComponent(
const ordinal_type &vectorComponentOrdinal)
const
293 return ops[vectorComponentOrdinal].size() == 0;
296 EOperator op(
const ordinal_type &vectorComponentOrdinal,
const ordinal_type &basisOrdinal)
const
300 if (identicallyZeroComponent(vectorComponentOrdinal))
308 return ops[vectorComponentOrdinal][basisOrdinal];
313 template<
typename DeviceType,
typename OutputValueType,
class Po
intValueType>
316 const ordinal_type basesSize = bases.size();
317 INTREPID2_TEST_FOR_EXCEPTION(basesSize != numBasisComponents_, std::invalid_argument,
"The number of bases provided must match the number of basis components in this decomposition");
319 ordinal_type numExpandedBasisComponents = 0;
322 std::vector<TensorBasis*> basesAsTensorBasis(numBasisComponents_);
323 for (ordinal_type basisComponentOrdinal=0; basisComponentOrdinal<numBasisComponents_; basisComponentOrdinal++)
325 TensorBasis* basisAsTensorBasis =
dynamic_cast<TensorBasis*
>(bases[basisComponentOrdinal].get());
326 basesAsTensorBasis[basisComponentOrdinal] = basisAsTensorBasis;
327 if (basisAsTensorBasis)
329 numExpandedBasisComponents += basisAsTensorBasis->getTensorBasisComponents().size();
333 numExpandedBasisComponents += 1;
337 std::vector< std::vector<EOperator> > expandedOps;
338 std::vector<double> expandedWeights;
339 const ordinal_type opsSize = ops.size();
340 for (ordinal_type simpleVectorEntryOrdinal=0; simpleVectorEntryOrdinal<opsSize; simpleVectorEntryOrdinal++)
342 if (identicallyZeroComponent(simpleVectorEntryOrdinal))
344 expandedOps.push_back(std::vector<EOperator>{});
345 expandedWeights.push_back(0.0);
349 std::vector< std::vector<EOperator> > expandedBasisOpsForSimpleVectorEntry(1);
352 auto addExpandedOp = [&expandedBasisOpsForSimpleVectorEntry](
const EOperator &op)
354 const ordinal_type size = expandedBasisOpsForSimpleVectorEntry.size();
355 for (ordinal_type i=0; i<size; i++)
357 expandedBasisOpsForSimpleVectorEntry[i].push_back(op);
363 auto vectorizeExpandedOps = [&expandedBasisOpsForSimpleVectorEntry](
const int &numSubVectors)
366 INTREPID2_TEST_FOR_EXCEPTION(expandedBasisOpsForSimpleVectorEntry.size() != 1, std::invalid_argument,
"multiple basis components may not be vector-valued!");
367 for (ordinal_type i=1; i<numSubVectors; i++)
369 expandedBasisOpsForSimpleVectorEntry.push_back(expandedBasisOpsForSimpleVectorEntry[0]);
373 std::vector<EOperator> subVectorOps;
374 std::vector<double> subVectorWeights {weights[simpleVectorEntryOrdinal]};
375 for (ordinal_type basisComponentOrdinal=0; basisComponentOrdinal<numBasisComponents_; basisComponentOrdinal++)
377 const auto &op = ops[simpleVectorEntryOrdinal][basisComponentOrdinal];
379 if (! basesAsTensorBasis[basisComponentOrdinal])
386 if (basisOpDecomposition.numVectorComponents() > 1)
389 INTREPID2_TEST_FOR_EXCEPTION(subVectorWeights.size() > 1, std::invalid_argument,
"Unhandled case: multiple component bases are vector-valued");
391 ordinal_type numSubVectors = basisOpDecomposition.numVectorComponents();
392 vectorizeExpandedOps(numSubVectors);
394 double weightSoFar = subVectorWeights[0];
395 for (ordinal_type subVectorEntryOrdinal=1; subVectorEntryOrdinal<numSubVectors; subVectorEntryOrdinal++)
397 subVectorWeights.push_back(weightSoFar * basisOpDecomposition.weight(subVectorEntryOrdinal));
399 subVectorWeights[0] *= basisOpDecomposition.weight(0);
400 for (ordinal_type subVectorEntryOrdinal=0; subVectorEntryOrdinal<numSubVectors; subVectorEntryOrdinal++)
402 for (ordinal_type subComponentBasis=0; subComponentBasis<basisOpDecomposition.numBasisComponents(); subComponentBasis++)
404 const auto &basisOp = basisOpDecomposition.op(subVectorEntryOrdinal, subComponentBasis);
405 expandedBasisOpsForSimpleVectorEntry[subVectorEntryOrdinal].push_back(basisOp);
411 double componentWeight = basisOpDecomposition.weight(0);
412 const ordinal_type size = subVectorWeights.size();
413 for (ordinal_type i=0; i<size; i++)
415 subVectorWeights[i] *= componentWeight;
417 ordinal_type subVectorEntryOrdinal = 0;
418 const ordinal_type numBasisComponents = basisOpDecomposition.numBasisComponents();
419 for (ordinal_type subComponentBasis=0; subComponentBasis<numBasisComponents; subComponentBasis++)
421 const auto &basisOp = basisOpDecomposition.op(subVectorEntryOrdinal, basisComponentOrdinal);
422 addExpandedOp( basisOp );
429 for (ordinal_type i=0; i<static_cast<ordinal_type>(expandedBasisOpsForSimpleVectorEntry.size()); i++)
431 const ordinal_type size = expandedBasisOpsForSimpleVectorEntry[i].size();
432 INTREPID2_TEST_FOR_EXCEPTION(size != numExpandedBasisComponents, std::logic_error,
"each vector in expandedBasisOpsForSimpleVectorEntry should have as many entries as there are expanded basis components");
435 expandedOps.insert(expandedOps.end(), expandedBasisOpsForSimpleVectorEntry.begin(), expandedBasisOpsForSimpleVectorEntry.end());
436 expandedWeights.insert(expandedWeights.end(), subVectorWeights.begin(), subVectorWeights.end());
439 INTREPID2_TEST_FOR_EXCEPTION(expandedOps.size() != expandedWeights.size(), std::logic_error,
"expandedWeights and expandedOps do not agree on the number of vector components");
442 result.setRotateXYNinetyDegrees(rotateXYNinetyDegrees_);
449 return rotateXYNinetyDegrees_;
452 void setRotateXYNinetyDegrees(
const bool &value)
454 rotateXYNinetyDegrees_ = value;
463 template<
class ExecutionSpace,
class OutputScalar,
class OutputFieldType>
466 using ScratchSpace =
typename ExecutionSpace::scratch_memory_space;
467 using OutputScratchView = Kokkos::View<OutputScalar*,ScratchSpace,Kokkos::MemoryTraits<Kokkos::Unmanaged>>;
469 using TeamPolicy = Kokkos::TeamPolicy<ExecutionSpace>;
470 using TeamMember =
typename TeamPolicy::member_type;
473 using RankCombinationType =
typename TensorViewIteratorType::RankCombinationType;
475 OutputFieldType output_;
476 OutputFieldType input1_;
477 OutputFieldType input2_;
479 int numFields_, numPoints_;
480 int numFields1_, numPoints1_;
481 int numFields2_, numPoints2_;
485 using RankCombinationViewType =
typename TensorViewIteratorType::RankCombinationViewType;
486 RankCombinationViewType rank_combinations_;
492 TensorViewFunctor(OutputFieldType output, OutputFieldType inputValues1, OutputFieldType inputValues2,
493 bool tensorPoints,
double weight)
494 : output_(output), input1_(inputValues1), input2_(inputValues2), tensorPoints_(tensorPoints), weight_(weight)
496 numFields_ = output.extent_int(0);
497 numPoints_ = output.extent_int(1);
499 numFields1_ = inputValues1.extent_int(0);
500 numPoints1_ = inputValues1.extent_int(1);
502 numFields2_ = inputValues2.extent_int(0);
503 numPoints2_ = inputValues2.extent_int(1);
508 INTREPID2_TEST_FOR_EXCEPTION(numPoints_ != numPoints1_, std::invalid_argument,
"incompatible point counts");
509 INTREPID2_TEST_FOR_EXCEPTION(numPoints_ != numPoints2_, std::invalid_argument,
"incompatible point counts");
513 INTREPID2_TEST_FOR_EXCEPTION(numPoints_ != numPoints1_ * numPoints2_, std::invalid_argument,
"incompatible point counts");
516 INTREPID2_TEST_FOR_EXCEPTION(numFields_ != numFields1_ * numFields2_, std::invalid_argument,
"incompatible field sizes");
518 const ordinal_type max_rank = std::max(inputValues1.rank(),inputValues2.rank());
521 const ordinal_type outputRank = output.rank();
522 INTREPID2_TEST_FOR_EXCEPTION(outputRank > max_rank, std::invalid_argument,
"Unsupported view combination.");
523 rank_combinations_ = RankCombinationViewType(
"Rank_combinations_", max_rank);
524 auto rank_combinations_host = Kokkos::create_mirror_view(rank_combinations_);
526 rank_combinations_host[0] = TensorViewIteratorType::TENSOR_PRODUCT;
527 rank_combinations_host[1] = tensorPoints ? TensorViewIteratorType::TENSOR_PRODUCT : TensorViewIteratorType::DIMENSION_MATCH;
528 for (ordinal_type d=2; d<max_rank; d++)
532 if ((inputValues1.extent_int(d) == inputValues2.extent_int(d)) && (output.extent_int(d) == 1))
534 rank_combinations_host[d] = TensorViewIteratorType::TENSOR_CONTRACTION;
536 else if (((inputValues1.extent_int(d) == output.extent_int(d)) && (inputValues2.extent_int(d) == 1))
537 || ((inputValues2.extent_int(d) == output.extent_int(d)) && (inputValues1.extent_int(d) == 1))
542 rank_combinations_host[d] = TensorViewIteratorType::TENSOR_PRODUCT;
544 else if ((inputValues1.extent_int(d) == inputValues2.extent_int(d)) && (output.extent_int(d) == inputValues1.extent_int(d) * inputValues2.extent_int(d)))
547 rank_combinations_host[d] = TensorViewIteratorType::TENSOR_PRODUCT;
549 else if ((inputValues1.extent_int(d) == inputValues2.extent_int(d)) && (output.extent_int(d) == inputValues1.extent_int(d)))
553 rank_combinations_host[d] = TensorViewIteratorType::DIMENSION_MATCH;
557 std::cout <<
"inputValues1.extent_int(" << d <<
") = " << inputValues1.extent_int(d) << std::endl;
558 std::cout <<
"inputValues2.extent_int(" << d <<
") = " << inputValues2.extent_int(d) << std::endl;
559 std::cout <<
"output.extent_int(" << d <<
") = " << output.extent_int(d) << std::endl;
560 INTREPID2_TEST_FOR_EXCEPTION(
true, std::invalid_argument,
"unable to find an interpretation for this combination of views");
563 Kokkos::deep_copy(rank_combinations_,rank_combinations_host);
566 KOKKOS_INLINE_FUNCTION
567 void operator()(
const TeamMember & teamMember )
const
569 auto fieldOrdinal1 = teamMember.league_rank();
571 Kokkos::parallel_for(Kokkos::TeamThreadRange(teamMember,0,numFields2_), [&] (
const int& fieldOrdinal2) {
573 const int FIELD_ORDINAL_DIMENSION = 0;
574 it.
setLocation({fieldOrdinal1,0,0,0,0,0,0},{fieldOrdinal2,0,0,0,0,0,0});
575 int next_increment_rank = FIELD_ORDINAL_DIMENSION;
576 OutputScalar accumulator = 0;
583 if ((next_increment_rank < 0) || (rank_combinations_[next_increment_rank] != TensorViewIteratorType::TENSOR_CONTRACTION))
590 }
while (it.
increment() > FIELD_ORDINAL_DIMENSION);
608 template<
typename BasisBaseClass =
void>
611 public BasisBaseClass
614 using BasisBase = BasisBaseClass;
615 using BasisPtr = Teuchos::RCP<BasisBase>;
621 std::vector<BasisPtr> tensorComponents_;
625 int numTensorialExtrusions_;
627 using DeviceType =
typename BasisBase::DeviceType;
628 using ExecutionSpace =
typename BasisBase::ExecutionSpace;
629 using OutputValueType =
typename BasisBase::OutputValueType;
630 using PointValueType =
typename BasisBase::PointValueType;
632 using OrdinalTypeArray1DHost =
typename BasisBase::OrdinalTypeArray1DHost;
633 using OrdinalTypeArray2DHost =
typename BasisBase::OrdinalTypeArray2DHost;
634 using OutputViewType =
typename BasisBase::OutputViewType;
635 using PointViewType =
typename BasisBase::PointViewType;
644 Basis_TensorBasis(BasisPtr basis1, BasisPtr basis2, EFunctionSpace functionSpace = FUNCTION_SPACE_MAX,
645 const bool useShardsCellTopologyAndTags =
false)
647 basis1_(basis1),basis2_(basis2)
649 this->functionSpace_ = functionSpace;
654 auto basis1Components = basis1AsTensor->getTensorBasisComponents();
655 tensorComponents_.insert(tensorComponents_.end(), basis1Components.begin(), basis1Components.end());
659 tensorComponents_.push_back(basis1_);
665 auto basis2Components = basis2AsTensor->getTensorBasisComponents();
666 tensorComponents_.insert(tensorComponents_.end(), basis2Components.begin(), basis2Components.end());
670 tensorComponents_.push_back(basis2_);
673 this->basisCardinality_ = basis1->getCardinality() * basis2->getCardinality();
674 this->basisDegree_ = std::max(basis1->getDegree(), basis2->getDegree());
677 std::ostringstream basisName;
678 basisName << basis1->getName() <<
" x " << basis2->getName();
679 name_ = basisName.str();
683 this->basisCellTopologyKey_ = tensorComponents_[0]->getBaseCellTopology().getKey();
684 this->numTensorialExtrusions_ = tensorComponents_.size() - 1;
686 this->basisType_ = basis1_->getBasisType();
687 this->basisCoordinates_ = COORDINATES_CARTESIAN;
689 ordinal_type spaceDim1 = basis1_->getDomainDimension();
690 ordinal_type spaceDim2 = basis2_->getDomainDimension();
692 INTREPID2_TEST_FOR_EXCEPTION(spaceDim2 != 1, std::invalid_argument,
"TensorBasis only supports 1D bases in basis2_ position");
694 if (this->getBasisType() == BASIS_FEM_HIERARCHICAL)
697 int degreeSize = basis1_->getPolynomialDegreeLength() + basis2_->getPolynomialDegreeLength();
698 this->fieldOrdinalPolynomialDegree_ = OrdinalTypeArray2DHost(
"TensorBasis - field ordinal polynomial degree", this->basisCardinality_, degreeSize);
699 this->fieldOrdinalH1PolynomialDegree_ = OrdinalTypeArray2DHost(
"TensorBasis - field ordinal polynomial H^1 degree", this->basisCardinality_, degreeSize);
701 const ordinal_type basis1Cardinality = basis1_->getCardinality();
702 const ordinal_type basis2Cardinality = basis2_->getCardinality();
704 int degreeLengthField1 = basis1_->getPolynomialDegreeLength();
705 int degreeLengthField2 = basis2_->getPolynomialDegreeLength();
707 for (ordinal_type fieldOrdinal1 = 0; fieldOrdinal1 < basis1Cardinality; fieldOrdinal1++)
709 OrdinalTypeArray1DHost degreesField1 = basis1_->getPolynomialDegreeOfField(fieldOrdinal1);
710 OrdinalTypeArray1DHost h1DegreesField1 = basis1_->getH1PolynomialDegreeOfField(fieldOrdinal1);
711 for (ordinal_type fieldOrdinal2 = 0; fieldOrdinal2 < basis2Cardinality; fieldOrdinal2++)
713 OrdinalTypeArray1DHost degreesField2 = basis2_->getPolynomialDegreeOfField(fieldOrdinal2);
714 OrdinalTypeArray1DHost h1DegreesField2 = basis2_->getH1PolynomialDegreeOfField(fieldOrdinal2);
715 const ordinal_type tensorFieldOrdinal = fieldOrdinal2 * basis1Cardinality + fieldOrdinal1;
717 for (
int d3=0; d3<degreeLengthField1; d3++)
719 this->fieldOrdinalPolynomialDegree_ (tensorFieldOrdinal,d3) = degreesField1(d3);
720 this->fieldOrdinalH1PolynomialDegree_(tensorFieldOrdinal,d3) = h1DegreesField1(d3);
722 for (
int d3=0; d3<degreeLengthField2; d3++)
724 this->fieldOrdinalPolynomialDegree_ (tensorFieldOrdinal,d3+degreeLengthField1) = degreesField2(d3);
725 this->fieldOrdinalH1PolynomialDegree_(tensorFieldOrdinal,d3+degreeLengthField1) = h1DegreesField2(d3);
731 if (useShardsCellTopologyAndTags)
733 setShardsTopologyAndTags();
739 const auto & cardinality = this->basisCardinality_;
742 const ordinal_type tagSize = 4;
743 const ordinal_type posScDim = 0;
744 const ordinal_type posScOrd = 1;
745 const ordinal_type posDfOrd = 2;
746 const ordinal_type posDfCnt = 3;
748 OrdinalTypeArray1DHost tagView(
"tag view", cardinality*tagSize);
752 auto basis1Topo = cellTopo->getTensorialComponent();
754 const ordinal_type spaceDim = spaceDim1 + spaceDim2;
755 const ordinal_type sideDim = spaceDim - 1;
757 const OrdinalTypeArray2DHost ordinalToTag1 = basis1_->getAllDofTags();
758 const OrdinalTypeArray2DHost ordinalToTag2 = basis2_->getAllDofTags();
760 for (
int fieldOrdinal1=0; fieldOrdinal1<basis1_->getCardinality(); fieldOrdinal1++)
762 ordinal_type subcellDim1 = ordinalToTag1(fieldOrdinal1,posScDim);
763 ordinal_type subcellOrd1 = ordinalToTag1(fieldOrdinal1,posScOrd);
764 ordinal_type subcellDfCnt1 = ordinalToTag1(fieldOrdinal1,posDfCnt);
765 for (
int fieldOrdinal2=0; fieldOrdinal2<basis2_->getCardinality(); fieldOrdinal2++)
767 ordinal_type subcellDim2 = ordinalToTag2(fieldOrdinal2,posScDim);
768 ordinal_type subcellOrd2 = ordinalToTag2(fieldOrdinal2,posScOrd);
769 ordinal_type subcellDfCnt2 = ordinalToTag2(fieldOrdinal2,posDfCnt);
771 ordinal_type subcellDim = subcellDim1 + subcellDim2;
772 ordinal_type subcellOrd;
773 if (subcellDim2 == 0)
777 ordinal_type sideOrdinal = cellTopo->getTensorialComponentSideOrdinal(subcellOrd2);
779 subcellDim1, subcellOrd1);
784 subcellOrd = cellTopo->getExtrudedSubcellOrdinal(subcellDim1, subcellOrd1);
785 if (subcellOrd == -1)
787 std::cout <<
"ERROR: -1 subcell ordinal.\n";
788 subcellOrd = cellTopo->getExtrudedSubcellOrdinal(subcellDim1, subcellOrd1);
791 ordinal_type tensorFieldOrdinal = fieldOrdinal2 * basis1_->getCardinality() + fieldOrdinal1;
793 ordinal_type dofOffsetOrdinal1 = ordinalToTag1(fieldOrdinal1,posDfOrd);
794 ordinal_type dofOffsetOrdinal2 = ordinalToTag2(fieldOrdinal2,posDfOrd);
795 ordinal_type dofsForSubcell1 = ordinalToTag1(fieldOrdinal1,posDfCnt);
796 ordinal_type dofOffsetOrdinal = dofOffsetOrdinal2 * dofsForSubcell1 + dofOffsetOrdinal1;
797 tagView(tagSize*tensorFieldOrdinal + posScDim) = subcellDim;
798 tagView(tagSize*tensorFieldOrdinal + posScOrd) = subcellOrd;
799 tagView(tagSize*tensorFieldOrdinal + posDfOrd) = dofOffsetOrdinal;
800 tagView(tagSize*tensorFieldOrdinal + posDfCnt) = subcellDfCnt1 * subcellDfCnt2;
806 this->setOrdinalTagData(this->tagToOrdinal_,
809 this->basisCardinality_,
817 void setShardsTopologyAndTags()
819 shards::CellTopology cellTopo1 = basis1_->getBaseCellTopology();
820 shards::CellTopology cellTopo2 = basis2_->getBaseCellTopology();
822 auto cellKey1 = basis1_->getBaseCellTopology().getKey();
823 auto cellKey2 = basis2_->getBaseCellTopology().getKey();
825 const int numTensorialExtrusions = basis1_->getNumTensorialExtrusions() + basis2_->getNumTensorialExtrusions();
826 if ((cellKey1 == shards::Line<2>::key) && (cellKey2 == shards::Line<2>::key) && (numTensorialExtrusions == 0))
828 this->basisCellTopologyKey_ = shards::Quadrilateral<4>::key;
830 else if ( ((cellKey1 == shards::Quadrilateral<4>::key) && (cellKey2 == shards::Line<2>::key))
831 || ((cellKey2 == shards::Quadrilateral<4>::key) && (cellKey1 == shards::Line<2>::key))
832 || ((cellKey1 == shards::Line<2>::key) && (cellKey2 == shards::Line<2>::key) && (numTensorialExtrusions == 1))
835 this->basisCellTopologyKey_ = shards::Hexahedron<8>::key;
837 else if ((cellKey1 == shards::Triangle<3>::key) && (cellKey2 == shards::Line<2>::key))
839 this->basisCellTopologyKey_ = shards::Wedge<6>::key;
843 INTREPID2_TEST_FOR_EXCEPTION(
true, std::invalid_argument,
"Cell topology combination not yet supported");
847 numTensorialExtrusions_ = 0;
851 const auto & cardinality = this->basisCardinality_;
854 const ordinal_type tagSize = 4;
855 const ordinal_type posScDim = 0;
856 const ordinal_type posScOrd = 1;
857 const ordinal_type posDfOrd = 2;
859 OrdinalTypeArray1DHost tagView(
"tag view", cardinality*tagSize);
861 shards::CellTopology cellTopo = this->getBaseCellTopology();
863 ordinal_type tensorSpaceDim = cellTopo.getDimension();
864 ordinal_type spaceDim1 = cellTopo1.getDimension();
865 ordinal_type spaceDim2 = cellTopo2.getDimension();
867 TensorTopologyMap topoMap(cellTopo1, cellTopo2);
869 for (ordinal_type d=0; d<=tensorSpaceDim; d++)
871 ordinal_type d2_max = std::min(spaceDim2, d);
872 for (ordinal_type d2=0; d2<=d2_max; d2++)
874 ordinal_type d1 = d-d2;
875 if (d1 > spaceDim1)
continue;
877 ordinal_type subcellCount2 = cellTopo2.getSubcellCount(d2);
878 ordinal_type subcellCount1 = cellTopo1.getSubcellCount(d1);
879 for (ordinal_type subcellOrdinal2=0; subcellOrdinal2<subcellCount2; subcellOrdinal2++)
881 ordinal_type subcellDofCount2 = basis2_->getDofCount(d2, subcellOrdinal2);
882 for (ordinal_type subcellOrdinal1=0; subcellOrdinal1<subcellCount1; subcellOrdinal1++)
884 ordinal_type subcellDofCount1 = basis1_->getDofCount(d1, subcellOrdinal1);
885 ordinal_type tensorLocalDofCount = subcellDofCount1 * subcellDofCount2;
886 for (ordinal_type localDofID2 = 0; localDofID2<subcellDofCount2; localDofID2++)
888 ordinal_type fieldOrdinal2 = basis2_->getDofOrdinal(d2, subcellOrdinal2, localDofID2);
889 OrdinalTypeArray1DHost degreesField2;
890 if (this->basisType_ == BASIS_FEM_HIERARCHICAL) degreesField2 = basis2_->getPolynomialDegreeOfField(fieldOrdinal2);
891 for (ordinal_type localDofID1 = 0; localDofID1<subcellDofCount1; localDofID1++)
893 ordinal_type fieldOrdinal1 = basis1_->getDofOrdinal(d1, subcellOrdinal1, localDofID1);
894 ordinal_type tensorLocalDofID = localDofID2 * subcellDofCount1 + localDofID1;
895 ordinal_type tensorFieldOrdinal = fieldOrdinal2 * basis1_->getCardinality() + fieldOrdinal1;
896 tagView(tensorFieldOrdinal*tagSize+0) = d;
897 tagView(tensorFieldOrdinal*tagSize+1) = topoMap.getCompositeSubcellOrdinal(d1, subcellOrdinal1, d2, subcellOrdinal2);
898 tagView(tensorFieldOrdinal*tagSize+2) = tensorLocalDofID;
899 tagView(tensorFieldOrdinal*tagSize+3) = tensorLocalDofCount;
909 this->setOrdinalTagData(this->tagToOrdinal_,
912 this->basisCardinality_,
920 virtual int getNumTensorialExtrusions()
const override
922 return numTensorialExtrusions_;
934 ordinal_type dkEnum2, ordinal_type operatorOrder2)
const
936 ordinal_type spaceDim1 = basis1_->getDomainDimension();
937 ordinal_type spaceDim2 = basis2_->getDomainDimension();
944 INTREPID2_TEST_FOR_EXCEPTION(operatorOrder1 > 0, std::invalid_argument,
"For spaceDim1 = 0, operatorOrder1 must be 0.");
950 case 1:
return getDkTensorIndex<1, 1>(dkEnum1, operatorOrder1, dkEnum2, operatorOrder2);
951 case 2:
return getDkTensorIndex<1, 2>(dkEnum1, operatorOrder1, dkEnum2, operatorOrder2);
952 case 3:
return getDkTensorIndex<1, 3>(dkEnum1, operatorOrder1, dkEnum2, operatorOrder2);
953 case 4:
return getDkTensorIndex<1, 4>(dkEnum1, operatorOrder1, dkEnum2, operatorOrder2);
954 case 5:
return getDkTensorIndex<1, 5>(dkEnum1, operatorOrder1, dkEnum2, operatorOrder2);
955 case 6:
return getDkTensorIndex<1, 6>(dkEnum1, operatorOrder1, dkEnum2, operatorOrder2);
957 INTREPID2_TEST_FOR_EXCEPTION(
true, std::invalid_argument,
"Unsupported dimension combination");
962 case 1:
return getDkTensorIndex<2, 1>(dkEnum1, operatorOrder1, dkEnum2, operatorOrder2);
963 case 2:
return getDkTensorIndex<2, 2>(dkEnum1, operatorOrder1, dkEnum2, operatorOrder2);
964 case 3:
return getDkTensorIndex<2, 3>(dkEnum1, operatorOrder1, dkEnum2, operatorOrder2);
965 case 4:
return getDkTensorIndex<2, 4>(dkEnum1, operatorOrder1, dkEnum2, operatorOrder2);
966 case 5:
return getDkTensorIndex<2, 5>(dkEnum1, operatorOrder1, dkEnum2, operatorOrder2);
968 INTREPID2_TEST_FOR_EXCEPTION(
true, std::invalid_argument,
"Unsupported dimension combination");
973 case 1:
return getDkTensorIndex<3, 1>(dkEnum1, operatorOrder1, dkEnum2, operatorOrder2);
974 case 2:
return getDkTensorIndex<3, 2>(dkEnum1, operatorOrder1, dkEnum2, operatorOrder2);
975 case 3:
return getDkTensorIndex<3, 3>(dkEnum1, operatorOrder1, dkEnum2, operatorOrder2);
976 case 4:
return getDkTensorIndex<3, 4>(dkEnum1, operatorOrder1, dkEnum2, operatorOrder2);
978 INTREPID2_TEST_FOR_EXCEPTION(
true, std::invalid_argument,
"Unsupported dimension combination");
983 case 1:
return getDkTensorIndex<4, 1>(dkEnum1, operatorOrder1, dkEnum2, operatorOrder2);
984 case 2:
return getDkTensorIndex<4, 2>(dkEnum1, operatorOrder1, dkEnum2, operatorOrder2);
985 case 3:
return getDkTensorIndex<4, 3>(dkEnum1, operatorOrder1, dkEnum2, operatorOrder2);
987 INTREPID2_TEST_FOR_EXCEPTION(
true, std::invalid_argument,
"Unsupported dimension combination");
992 case 1:
return getDkTensorIndex<5, 1>(dkEnum1, operatorOrder1, dkEnum2, operatorOrder2);
993 case 2:
return getDkTensorIndex<5, 2>(dkEnum1, operatorOrder1, dkEnum2, operatorOrder2);
995 INTREPID2_TEST_FOR_EXCEPTION(
true, std::invalid_argument,
"Unsupported dimension combination");
1000 case 1:
return getDkTensorIndex<6, 1>(dkEnum1, operatorOrder1, dkEnum2, operatorOrder2);
1002 INTREPID2_TEST_FOR_EXCEPTION(
true, std::invalid_argument,
"Unsupported dimension combination");
1005 INTREPID2_TEST_FOR_EXCEPTION(
true, std::invalid_argument,
"Unsupported dimension combination");
1015 const int spaceDim = this->getDomainDimension();
1017 const EOperator VALUE = Intrepid2::OPERATOR_VALUE;
1019 std::vector< std::vector<EOperator> > opsVALUE{{VALUE, VALUE}};
1021 std::vector< std::vector<EOperator> > ops(spaceDim);
1023 switch (operatorType)
1031 INTREPID2_TEST_FOR_EXCEPTION(
true, std::invalid_argument,
"Unsupported operator type - TensorBasis subclass should override");
1046 auto opOrder = getOperatorOrder(operatorType);
1047 const int dkCardinality = getDkCardinality(operatorType, 2);
1049 ops = std::vector< std::vector<EOperator> >(dkCardinality);
1053 for (
int derivativeCountComp2=0; derivativeCountComp2<=opOrder; derivativeCountComp2++)
1055 int derivativeCountComp1=opOrder-derivativeCountComp2;
1056 EOperator op1 = (derivativeCountComp1 == 0) ? OPERATOR_VALUE : EOperator(OPERATOR_D1 + (derivativeCountComp1 - 1));
1057 EOperator op2 = (derivativeCountComp2 == 0) ? OPERATOR_VALUE : EOperator(OPERATOR_D1 + (derivativeCountComp2 - 1));
1059 int dkCardinality1 = getDkCardinality(op1, 1);
1060 int dkCardinality2 = getDkCardinality(op2, 1);
1062 for (
int dkEnum1=0; dkEnum1<dkCardinality1; dkEnum1++)
1064 for (
int dkEnum2=0; dkEnum2<dkCardinality2; dkEnum2++)
1066 ordinal_type dkTensorIndex = getDkTensorIndex<1, 1>(dkEnum1, derivativeCountComp1, dkEnum2, derivativeCountComp2);
1067 ops[dkTensorIndex] = std::vector<EOperator>{op1, op2};
1075 std::vector<double> weights(ops.size(), 1.0);
1083 if (((operatorType >= OPERATOR_D1) && (operatorType <= OPERATOR_D10)) || (operatorType == OPERATOR_GRAD))
1090 ordinal_type numBasisComponents = tensorComponents_.size();
1092 auto opOrder = getOperatorOrder(operatorType);
1093 const int dkCardinality = getDkCardinality(operatorType, numBasisComponents);
1095 std::vector< std::vector<EOperator> > ops(dkCardinality);
1097 std::vector<EOperator> prevEntry(numBasisComponents, OPERATOR_VALUE);
1098 prevEntry[0] = operatorType;
1102 for (ordinal_type dkOrdinal=1; dkOrdinal<dkCardinality; dkOrdinal++)
1104 std::vector<EOperator> entry = prevEntry;
1113 ordinal_type cumulativeOpOrder = 0;
1114 ordinal_type finalOpOrder = getOperatorOrder(entry[numBasisComponents-1]);
1115 for (ordinal_type compOrdinal=0; compOrdinal<numBasisComponents; compOrdinal++)
1117 const ordinal_type thisOpOrder = getOperatorOrder(entry[compOrdinal]);
1118 cumulativeOpOrder += thisOpOrder;
1119 if (cumulativeOpOrder + finalOpOrder == opOrder)
1122 EOperator decrementedOp;
1123 if (thisOpOrder == 1)
1125 decrementedOp = OPERATOR_VALUE;
1129 decrementedOp =
static_cast<EOperator
>(OPERATOR_D1 + ((thisOpOrder - 1) - 1));
1131 entry[compOrdinal] = decrementedOp;
1132 const ordinal_type remainingOpOrder = opOrder - cumulativeOpOrder + 1;
1133 entry[compOrdinal+1] =
static_cast<EOperator
>(OPERATOR_D1 + (remainingOpOrder - 1));
1134 for (ordinal_type i=compOrdinal+2; i<numBasisComponents; i++)
1136 entry[i] = OPERATOR_VALUE;
1141 ops[dkOrdinal] = entry;
1144 std::vector<double> weights(dkCardinality, 1.0);
1151 std::vector<BasisPtr> componentBases {basis1_, basis2_};
1162 const bool operatorIsDk = (operatorType >= OPERATOR_D1) && (operatorType <= OPERATOR_D10);
1163 const bool operatorSupported = (operatorType == OPERATOR_VALUE) || (operatorType == OPERATOR_GRAD) || (operatorType == OPERATOR_CURL) || (operatorType == OPERATOR_DIV) || operatorIsDk;
1164 INTREPID2_TEST_FOR_EXCEPTION(!operatorSupported, std::invalid_argument,
"operator is not supported by allocateBasisValues");
1167 const int spaceDim = this->getDomainDimension();
1168 INTREPID2_TEST_FOR_EXCEPTION(spaceDim != points.
extent_int(1), std::invalid_argument,
"points must be shape (P,D), with D equal to the dimension of the basis domain");
1171 ordinal_type numBasisComponents = tensorComponents_.size();
1177 INTREPID2_TEST_FOR_EXCEPTION(points.
numTensorComponents() != 1, std::invalid_argument,
"If points does not have the same number of tensor components as the basis, then it should have trivial tensor structure.");
1178 const ordinal_type numPoints = points.
extent_int(0);
1179 auto outputView = this->allocateOutputView(numPoints, operatorType);
1186 INTREPID2_TEST_FOR_EXCEPTION(numBasisComponents > points.
numTensorComponents(), std::invalid_argument,
"points must have at least as many tensorial components as basis.");
1190 ordinal_type numVectorComponents = opDecomposition.numVectorComponents();
1191 const bool useVectorData = numVectorComponents > 1;
1193 std::vector<ordinal_type> componentPointCounts(numBasisComponents);
1194 ordinal_type pointComponentNumber = 0;
1195 for (ordinal_type r=0; r<numBasisComponents; r++)
1197 const ordinal_type compSpaceDim = tensorComponents_[r]->getDomainDimension();
1198 ordinal_type dimsSoFar = 0;
1199 ordinal_type numPointsForBasisComponent = 1;
1200 while (dimsSoFar < compSpaceDim)
1202 INTREPID2_TEST_FOR_EXCEPTION(pointComponentNumber >= points.
numTensorComponents(), std::invalid_argument,
"Error in processing points container; perhaps it is mis-sized?");
1204 const int numComponentDims = points.
getTensorComponent(pointComponentNumber).extent_int(1);
1205 numPointsForBasisComponent *= numComponentPoints;
1206 dimsSoFar += numComponentDims;
1207 INTREPID2_TEST_FOR_EXCEPTION(dimsSoFar > points.
numTensorComponents(), std::invalid_argument,
"Error in processing points container; perhaps it is mis-sized?");
1208 pointComponentNumber++;
1210 componentPointCounts[r] = numPointsForBasisComponent;
1215 const int numFamilies = 1;
1218 const int familyOrdinal = 0;
1219 for (ordinal_type vectorComponentOrdinal=0; vectorComponentOrdinal<numVectorComponents; vectorComponentOrdinal++)
1221 if (!opDecomposition.identicallyZeroComponent(vectorComponentOrdinal))
1223 std::vector< Data<OutputValueType,DeviceType> > componentData;
1224 for (ordinal_type r=0; r<numBasisComponents; r++)
1226 const int numComponentPoints = componentPointCounts[r];
1227 const EOperator op = opDecomposition.op(vectorComponentOrdinal, r);
1228 auto componentView = tensorComponents_[r]->allocateOutputView(numComponentPoints, op);
1240 std::vector< Data<OutputValueType,DeviceType> > componentData;
1242 const ordinal_type vectorComponentOrdinal = 0;
1243 for (ordinal_type r=0; r<numBasisComponents; r++)
1245 const int numComponentPoints = componentPointCounts[r];
1246 const EOperator op = opDecomposition.op(vectorComponentOrdinal, r);
1247 auto componentView = tensorComponents_[r]->allocateOutputView(numComponentPoints, op);
1252 const Kokkos::Array<int,7> extents {componentView.extent_int(0), componentView.extent_int(1), 1,1,1,1,1};
1253 Kokkos::Array<DataVariationType,7> variationType {GENERAL, GENERAL, CONSTANT, CONSTANT, CONSTANT, CONSTANT, CONSTANT };
1259 std::vector< TensorData<OutputValueType,DeviceType> > tensorDataEntries {tensorData};
1267 using BasisBase::getValues;
1281 PointViewType & inputPoints1, PointViewType & inputPoints2,
bool &tensorDecompositionSucceeded)
const
1283 INTREPID2_TEST_FOR_EXCEPTION(attemptTensorDecomposition, std::invalid_argument,
"tensor decomposition not yet supported");
1297 int spaceDim1 = basis1_->getDomainDimension();
1298 int spaceDim2 = basis2_->getDomainDimension();
1300 int totalSpaceDim = inputPoints.extent_int(1);
1302 TEUCHOS_ASSERT(spaceDim1 + spaceDim2 == totalSpaceDim);
1306 inputPoints1 = Kokkos::subview(inputPoints,Kokkos::ALL(),std::make_pair(0,spaceDim1));
1307 inputPoints2 = Kokkos::subview(inputPoints,Kokkos::ALL(),std::make_pair(spaceDim1,totalSpaceDim));
1313 tensorDecompositionSucceeded =
false;
1324 virtual void getDofCoords(
typename BasisBase::ScalarViewType dofCoords )
const override
1326 int spaceDim1 = basis1_->getBaseCellTopology().getDimension();
1327 int spaceDim2 = basis2_->getBaseCellTopology().getDimension();
1329 using ValueType =
typename BasisBase::ScalarViewType::value_type;
1330 using ResultLayout =
typename DeduceLayout< typename BasisBase::ScalarViewType >::result_layout;
1331 using ViewType = Kokkos::DynRankView<ValueType, ResultLayout, DeviceType >;
1333 const ordinal_type basisCardinality1 = basis1_->getCardinality();
1334 const ordinal_type basisCardinality2 = basis2_->getCardinality();
1336 ViewType dofCoords1(
"dofCoords1",basisCardinality1,spaceDim1);
1337 ViewType dofCoords2(
"dofCoords2",basisCardinality2,spaceDim2);
1339 basis1_->getDofCoords(dofCoords1);
1340 basis2_->getDofCoords(dofCoords2);
1342 Kokkos::RangePolicy<ExecutionSpace> policy(0, basisCardinality2);
1343 Kokkos::parallel_for(policy, KOKKOS_LAMBDA (
const int fieldOrdinal2)
1345 for (
int fieldOrdinal1=0; fieldOrdinal1<basisCardinality1; fieldOrdinal1++)
1347 const ordinal_type fieldOrdinal = fieldOrdinal1 + fieldOrdinal2 * basisCardinality1;
1348 for (
int d1=0; d1<spaceDim1; d1++)
1350 dofCoords(fieldOrdinal,d1) = dofCoords1(fieldOrdinal1,d1);
1352 for (
int d2=0; d2<spaceDim2; d2++)
1354 dofCoords(fieldOrdinal,spaceDim1+d2) = dofCoords2(fieldOrdinal2,d2);
1370 virtual void getDofCoeffs(
typename BasisBase::ScalarViewType dofCoeffs )
const override
1372 using ValueType =
typename BasisBase::ScalarViewType::value_type;
1373 using ResultLayout =
typename DeduceLayout< typename BasisBase::ScalarViewType >::result_layout;
1374 using ViewType = Kokkos::DynRankView<ValueType, ResultLayout, DeviceType >;
1376 const ordinal_type basisCardinality1 = basis1_->getCardinality();
1377 const ordinal_type basisCardinality2 = basis2_->getCardinality();
1379 bool isVectorBasis1 = getFieldRank(basis1_->getFunctionSpace()) == 1;
1380 bool isVectorBasis2 = getFieldRank(basis2_->getFunctionSpace()) == 1;
1382 INTREPID2_TEST_FOR_EXCEPTION(isVectorBasis1 && isVectorBasis2, std::invalid_argument,
"the case in which basis1 and basis2 are vector bases is not supported");
1384 int basisDim1 = isVectorBasis1 ? basis1_->getBaseCellTopology().getDimension() : 1;
1385 int basisDim2 = isVectorBasis2 ? basis2_->getBaseCellTopology().getDimension() : 1;
1387 auto dofCoeffs1 = isVectorBasis1 ? ViewType(
"dofCoeffs1",basis1_->getCardinality(), basisDim1) : ViewType(
"dofCoeffs1",basis1_->getCardinality());
1388 auto dofCoeffs2 = isVectorBasis2 ? ViewType(
"dofCoeffs2",basis2_->getCardinality(), basisDim2) : ViewType(
"dofCoeffs2",basis2_->getCardinality());
1390 basis1_->getDofCoeffs(dofCoeffs1);
1391 basis2_->getDofCoeffs(dofCoeffs2);
1393 Kokkos::RangePolicy<ExecutionSpace> policy(0, basisCardinality2);
1394 Kokkos::parallel_for(policy, KOKKOS_LAMBDA (
const int fieldOrdinal2)
1396 for (
int fieldOrdinal1=0; fieldOrdinal1<basisCardinality1; fieldOrdinal1++)
1398 const ordinal_type fieldOrdinal = fieldOrdinal1 + fieldOrdinal2 * basisCardinality1;
1399 for (
int d1 = 0; d1 <basisDim1; d1++) {
1400 for (
int d2 = 0; d2 <basisDim2; d2++) {
1401 dofCoeffs.access(fieldOrdinal,d1+d2) = dofCoeffs1.access(fieldOrdinal1,d1);
1402 dofCoeffs.access(fieldOrdinal,d1+d2) *= dofCoeffs2.access(fieldOrdinal2,d2);
1416 return name_.c_str();
1419 std::vector<BasisPtr> getTensorBasisComponents()
const
1421 return tensorComponents_;
1439 const EOperator operatorType = OPERATOR_VALUE )
const override
1441 const ordinal_type numTensorComponents = tensorComponents_.size();
1445 INTREPID2_TEST_FOR_EXCEPTION( inputPoints.
numTensorComponents() != 1, std::invalid_argument,
"If inputPoints differs from the tensor basis in component count, then inputPoints must have trivial tensor product structure" );
1446 INTREPID2_TEST_FOR_EXCEPTION( outputValues.
numFamilies() != 1, std::invalid_argument,
"If inputPoints differs from the tensor basis in component count, outputValues must have a single family with trivial tensor product structure" );
1447 INTREPID2_TEST_FOR_EXCEPTION( outputValues.
tensorData().numTensorComponents() != 1, std::invalid_argument,
"If inputPoints differs from the tensor basis in component count, outputValues must have a single family with trivial tensor product structure" );
1449 OutputViewType outputView = outputValues.
tensorData().getTensorComponent(0).getUnderlyingView();
1451 this->
getValues(outputView, pointView, operatorType);
1457 const ordinal_type numVectorComponents = operatorDecomposition.numVectorComponents();
1458 const bool useVectorData = numVectorComponents > 1;
1459 const ordinal_type numBasisComponents = operatorDecomposition.numBasisComponents();
1461 for (ordinal_type vectorComponentOrdinal=0; vectorComponentOrdinal<numVectorComponents; vectorComponentOrdinal++)
1463 const double weight = operatorDecomposition.weight(vectorComponentOrdinal);
1464 ordinal_type pointComponentOrdinal = 0;
1465 for (ordinal_type basisOrdinal=0; basisOrdinal<numBasisComponents; basisOrdinal++, pointComponentOrdinal++)
1467 const EOperator op = operatorDecomposition.op(vectorComponentOrdinal, basisOrdinal);
1469 if (op != OPERATOR_MAX)
1471 const int vectorFamily = 0;
1472 auto tensorData = useVectorData ? outputValues.
vectorData().getComponent(vectorFamily,vectorComponentOrdinal) : outputValues.
tensorData();
1473 INTREPID2_TEST_FOR_EXCEPTION( ! tensorData.getTensorComponent(basisOrdinal).isValid(), std::invalid_argument,
"Invalid output component encountered");
1479 const ordinal_type basisDomainDimension = tensorComponents_[basisOrdinal]->getDomainDimension();
1480 if (pointView.extent_int(1) == basisDomainDimension)
1482 tensorComponents_[basisOrdinal]->getValues(basisValueView, pointView, op);
1489 ordinal_type dimsSoFar = 0;
1490 std::vector< ScalarView<PointValueType,DeviceType> > basisPointComponents;
1491 while (dimsSoFar < basisDomainDimension)
1493 INTREPID2_TEST_FOR_EXCEPTION(pointComponentOrdinal >= inputPoints.
numTensorComponents(), std::invalid_argument,
"Error in processing points container; perhaps it is mis-sized?");
1495 const ordinal_type numComponentDims = pointComponent.extent_int(1);
1496 dimsSoFar += numComponentDims;
1497 INTREPID2_TEST_FOR_EXCEPTION(dimsSoFar > inputPoints.
numTensorComponents(), std::invalid_argument,
"Error in processing points container; perhaps it is mis-sized?");
1498 basisPointComponents.push_back(pointComponent);
1499 if (dimsSoFar < basisDomainDimension)
1502 pointComponentOrdinal++;
1508 bool useVectorData2 = (basisValueView.rank() == 3);
1522 tensorComponents_[basisOrdinal]->getValues(basisValues, basisPoints, op);
1530 const bool spansXY = (vectorComponentOrdinal == 0) && (basisValueView.extent_int(2) == 2);
1534 auto policy = Kokkos::MDRangePolicy<ExecutionSpace,Kokkos::Rank<2>>({0,0},{basisValueView.extent_int(0),basisValueView.extent_int(1)});
1535 Kokkos::parallel_for(
"rotateXYNinetyDegrees", policy,
1536 KOKKOS_LAMBDA (
const int &fieldOrdinal,
const int &pointOrdinal) {
1537 const auto f_x = basisValueView(fieldOrdinal,pointOrdinal,0);
1538 const auto &f_y = basisValueView(fieldOrdinal,pointOrdinal,1);
1539 basisValueView(fieldOrdinal,pointOrdinal,0) = -f_y;
1540 basisValueView(fieldOrdinal,pointOrdinal,1) = f_x;
1546 if ((weight != 1.0) && (basisOrdinal == 0))
1548 if (basisValueView.rank() == 2)
1550 auto policy = Kokkos::MDRangePolicy<ExecutionSpace,Kokkos::Rank<2>>({0,0},{basisValueView.extent_int(0),basisValueView.extent_int(1)});
1551 Kokkos::parallel_for(
"multiply basisValueView by weight", policy,
1552 KOKKOS_LAMBDA (
const int &fieldOrdinal,
const int &pointOrdinal) {
1553 basisValueView(fieldOrdinal,pointOrdinal) *= weight;
1556 else if (basisValueView.rank() == 3)
1558 auto policy = Kokkos::MDRangePolicy<ExecutionSpace,Kokkos::Rank<3>>({0,0,0},{basisValueView.extent_int(0),basisValueView.extent_int(1),basisValueView.extent_int(2)});
1559 Kokkos::parallel_for(
"multiply basisValueView by weight", policy,
1560 KOKKOS_LAMBDA (
const int &fieldOrdinal,
const int &pointOrdinal,
const int &d) {
1561 basisValueView(fieldOrdinal,pointOrdinal,d) *= weight;
1566 INTREPID2_TEST_FOR_EXCEPTION(
true, std::invalid_argument,
"Unsupported rank for basisValueView");
1592 void getValues( OutputViewType outputValues,
const PointViewType inputPoints,
1593 const EOperator operatorType = OPERATOR_VALUE )
const override
1596 bool attemptTensorDecomposition =
false;
1597 PointViewType inputPoints1, inputPoints2;
1598 getComponentPoints(inputPoints, attemptTensorDecomposition, inputPoints1, inputPoints2, tensorPoints);
1600 const auto functionSpace = this->getFunctionSpace();
1602 if ((functionSpace == FUNCTION_SPACE_HVOL) || (functionSpace == FUNCTION_SPACE_HGRAD))
1605 switch (operatorType)
1607 case OPERATOR_VALUE:
1620 auto opOrder = getOperatorOrder(operatorType);
1623 for (
int derivativeCountComp2=0; derivativeCountComp2<=opOrder; derivativeCountComp2++)
1625 int derivativeCountComp1=opOrder-derivativeCountComp2;
1626 EOperator op1 = (derivativeCountComp1 == 0) ? OPERATOR_VALUE : EOperator(OPERATOR_D1 + (derivativeCountComp1 - 1));
1627 EOperator op2 = (derivativeCountComp2 == 0) ? OPERATOR_VALUE : EOperator(OPERATOR_D1 + (derivativeCountComp2 - 1));
1629 int spaceDim1 = inputPoints1.extent_int(1);
1630 int spaceDim2 = inputPoints2.extent_int(1);
1632 int dkCardinality1 = (op1 != OPERATOR_VALUE) ? getDkCardinality(op1, spaceDim1) : 1;
1633 int dkCardinality2 = (op2 != OPERATOR_VALUE) ? getDkCardinality(op2, spaceDim2) : 1;
1635 int basisCardinality1 = basis1_->getCardinality();
1636 int basisCardinality2 = basis2_->getCardinality();
1638 int totalPointCount = tensorPoints ? inputPoints1.extent_int(0) * inputPoints2.extent_int(0) : inputPoints1.extent_int(0);
1640 int pointCount1, pointCount2;
1643 pointCount1 = inputPoints1.extent_int(0);
1644 pointCount2 = inputPoints2.extent_int(0);
1648 pointCount1 = totalPointCount;
1649 pointCount2 = totalPointCount;
1652 OutputViewType outputValues1, outputValues2;
1653 if (op1 == OPERATOR_VALUE)
1654 outputValues1 = getMatchingViewWithLabel(outputValues,
"output values - basis 1",basisCardinality1,pointCount1);
1656 outputValues1 = getMatchingViewWithLabel(outputValues,
"output values - basis 1",basisCardinality1,pointCount1,dkCardinality1);
1658 if (op2 == OPERATOR_VALUE)
1659 outputValues2 = getMatchingViewWithLabel(outputValues,
"output values - basis 2",basisCardinality2,pointCount2);
1661 outputValues2 = getMatchingViewWithLabel(outputValues,
"output values - basis 2",basisCardinality2,pointCount2,dkCardinality2);
1663 basis1_->getValues(outputValues1,inputPoints1,op1);
1664 basis2_->getValues(outputValues2,inputPoints2,op2);
1666 const int outputVectorSize = getVectorSizeForHierarchicalParallelism<OutputValueType>();
1667 const int pointVectorSize = getVectorSizeForHierarchicalParallelism<PointValueType>();
1668 const int vectorSize = std::max(outputVectorSize,pointVectorSize);
1670 auto policy = Kokkos::TeamPolicy<ExecutionSpace>(basisCardinality1,Kokkos::AUTO(),vectorSize);
1672 double weight = 1.0;
1675 for (
int dkEnum1=0; dkEnum1<dkCardinality1; dkEnum1++)
1677 auto outputValues1_dkEnum1 = (op1 != OPERATOR_VALUE) ? Kokkos::subview(outputValues1,Kokkos::ALL(),Kokkos::ALL(),dkEnum1)
1678 : Kokkos::subview(outputValues1,Kokkos::ALL(),Kokkos::ALL());
1679 for (
int dkEnum2=0; dkEnum2<dkCardinality2; dkEnum2++)
1681 auto outputValues2_dkEnum2 = (op2 != OPERATOR_VALUE) ? Kokkos::subview(outputValues2,Kokkos::ALL(),Kokkos::ALL(),dkEnum2)
1682 : Kokkos::subview(outputValues2,Kokkos::ALL(),Kokkos::ALL());
1684 ordinal_type dkTensorIndex =
getTensorDkEnumeration(dkEnum1, derivativeCountComp1, dkEnum2, derivativeCountComp2);
1685 auto outputValues_dkTensor = Kokkos::subview(outputValues,Kokkos::ALL(),Kokkos::ALL(),dkTensorIndex);
1691 FunctorType functor(outputValues_dkTensor, outputValues1_dkEnum1, outputValues2_dkEnum2, tensorPoints, weight);
1692 Kokkos::parallel_for(
"TensorViewFunctor", policy , functor);
1699 this->
getValues(outputValues, operatorType, inputPoints1, inputPoints2, tensorPoints);
1705 this->
getValues(outputValues, operatorType, inputPoints1, inputPoints2, tensorPoints);
1734 virtual void getValues(OutputViewType outputValues,
const EOperator operatorType,
1735 const PointViewType inputPoints1,
const PointViewType inputPoints2,
1736 bool tensorPoints)
const
1738 INTREPID2_TEST_FOR_EXCEPTION(
true, std::invalid_argument,
"one-operator, two-inputPoints getValues should be overridden by TensorBasis subclasses");
1765 const PointViewType inputPoints1,
const EOperator operatorType1,
1766 const PointViewType inputPoints2,
const EOperator operatorType2,
1767 bool tensorPoints,
double weight=1.0)
const
1769 int basisCardinality1 = basis1_->getCardinality();
1770 int basisCardinality2 = basis2_->getCardinality();
1772 int totalPointCount = tensorPoints ? inputPoints1.extent_int(0) * inputPoints2.extent_int(0) : inputPoints1.extent_int(0);
1774 int pointCount1, pointCount2;
1777 pointCount1 = inputPoints1.extent_int(0);
1778 pointCount2 = inputPoints2.extent_int(0);
1782 pointCount1 = totalPointCount;
1783 pointCount2 = totalPointCount;
1786 const ordinal_type spaceDim1 = inputPoints1.extent_int(1);
1787 const ordinal_type spaceDim2 = inputPoints2.extent_int(1);
1789 INTREPID2_TEST_FOR_EXCEPTION(!tensorPoints && (totalPointCount != inputPoints2.extent_int(0)),
1790 std::invalid_argument,
"If tensorPoints is false, the point counts must match!");
1792 const ordinal_type opRank1 = getOperatorRank(basis1_->getFunctionSpace(), operatorType1, spaceDim1);
1793 const ordinal_type opRank2 = getOperatorRank(basis2_->getFunctionSpace(), operatorType2, spaceDim2);
1795 const ordinal_type outputRank1 = opRank1 + getFieldRank(basis1_->getFunctionSpace());
1796 const ordinal_type outputRank2 = opRank2 + getFieldRank(basis2_->getFunctionSpace());
1798 OutputViewType outputValues1, outputValues2;
1799 if (outputRank1 == 0)
1801 outputValues1 = getMatchingViewWithLabel(outputValues,
"output values - basis 1",basisCardinality1,pointCount1);
1803 else if (outputRank1 == 1)
1805 outputValues1 = getMatchingViewWithLabel(outputValues,
"output values - basis 1",basisCardinality1,pointCount1,spaceDim1);
1809 INTREPID2_TEST_FOR_EXCEPTION(
true, std::invalid_argument,
"Unsupported opRank1");
1812 if (outputRank2 == 0)
1814 outputValues2 = getMatchingViewWithLabel(outputValues,
"output values - basis 2",basisCardinality2,pointCount2);
1816 else if (outputRank2 == 1)
1818 outputValues2 = getMatchingViewWithLabel(outputValues,
"output values - basis 2",basisCardinality2,pointCount2,spaceDim2);
1822 INTREPID2_TEST_FOR_EXCEPTION(
true, std::invalid_argument,
"Unsupported opRank2");
1825 basis1_->getValues(outputValues1,inputPoints1,operatorType1);
1826 basis2_->getValues(outputValues2,inputPoints2,operatorType2);
1828 const int outputVectorSize = getVectorSizeForHierarchicalParallelism<OutputValueType>();
1829 const int pointVectorSize = getVectorSizeForHierarchicalParallelism<PointValueType>();
1830 const int vectorSize = std::max(outputVectorSize,pointVectorSize);
1832 auto policy = Kokkos::TeamPolicy<ExecutionSpace>(basisCardinality1,Kokkos::AUTO(),vectorSize);
1836 FunctorType functor(outputValues, outputValues1, outputValues2, tensorPoints, weight);
1837 Kokkos::parallel_for(
"TensorViewFunctor", policy , functor);
1844 virtual HostBasisPtr<OutputValueType, PointValueType>
1846 TEUCHOS_TEST_FOR_EXCEPTION(
true, std::invalid_argument,
"TensorBasis subclasses must override getHostBasis");
1857 template<
class ExecutionSpace,
class OutputScalar,
class OutputFieldType>
1860 using ScratchSpace =
typename ExecutionSpace::scratch_memory_space;
1861 using OutputScratchView = Kokkos::View<OutputScalar*,ScratchSpace,Kokkos::MemoryTraits<Kokkos::Unmanaged>>;
1863 using TeamPolicy = Kokkos::TeamPolicy<ExecutionSpace>;
1864 using TeamMember =
typename TeamPolicy::member_type;
1866 OutputFieldType output_;
1867 OutputFieldType input1_;
1868 OutputFieldType input2_;
1869 OutputFieldType input3_;
1871 int numFields_, numPoints_;
1872 int numFields1_, numPoints1_;
1873 int numFields2_, numPoints2_;
1874 int numFields3_, numPoints3_;
1880 TensorBasis3_Functor(OutputFieldType output, OutputFieldType inputValues1, OutputFieldType inputValues2, OutputFieldType inputValues3,
1881 bool tensorPoints,
double weight)
1882 : output_(output), input1_(inputValues1), input2_(inputValues2), input3_(inputValues3), tensorPoints_(tensorPoints), weight_(weight)
1884 numFields_ = output.extent_int(0);
1885 numPoints_ = output.extent_int(1);
1887 numFields1_ = inputValues1.extent_int(0);
1888 numPoints1_ = inputValues1.extent_int(1);
1890 numFields2_ = inputValues2.extent_int(0);
1891 numPoints2_ = inputValues2.extent_int(1);
1893 numFields3_ = inputValues3.extent_int(0);
1894 numPoints3_ = inputValues3.extent_int(1);
1901 INTREPID2_TEST_FOR_EXCEPTION(inputValues1.rank() > 3, std::invalid_argument,
"ranks greater than 3 not yet supported");
1902 INTREPID2_TEST_FOR_EXCEPTION(inputValues2.rank() > 3, std::invalid_argument,
"ranks greater than 3 not yet supported");
1903 INTREPID2_TEST_FOR_EXCEPTION(inputValues3.rank() > 3, std::invalid_argument,
"ranks greater than 3 not yet supported");
1904 INTREPID2_TEST_FOR_EXCEPTION((inputValues1.rank() == 3) && (inputValues2.rank() == 3), std::invalid_argument,
"two vector-valued input ranks not yet supported");
1905 INTREPID2_TEST_FOR_EXCEPTION((inputValues1.rank() == 3) && (inputValues3.rank() == 3), std::invalid_argument,
"two vector-valued input ranks not yet supported");
1906 INTREPID2_TEST_FOR_EXCEPTION((inputValues2.rank() == 3) && (inputValues3.rank() == 3), std::invalid_argument,
"two vector-valued input ranks not yet supported");
1911 INTREPID2_TEST_FOR_EXCEPTION(numPoints_ != numPoints1_, std::invalid_argument,
"incompatible point counts");
1912 INTREPID2_TEST_FOR_EXCEPTION(numPoints_ != numPoints2_, std::invalid_argument,
"incompatible point counts");
1913 INTREPID2_TEST_FOR_EXCEPTION(numPoints_ != numPoints3_, std::invalid_argument,
"incompatible point counts");
1917 INTREPID2_TEST_FOR_EXCEPTION(numPoints_ != numPoints1_ * numPoints2_ * numPoints3_, std::invalid_argument,
"incompatible point counts");
1920 INTREPID2_TEST_FOR_EXCEPTION(numFields_ != numFields1_ * numFields2_ * numFields3_, std::invalid_argument,
"incompatible field sizes");
1923 KOKKOS_INLINE_FUNCTION
1924 void operator()(
const TeamMember & teamMember )
const
1926 auto fieldOrdinal1 = teamMember.league_rank();
1930 if ((input1_.rank() == 2) && (input2_.rank() == 2) && (input3_.rank() == 2))
1932 Kokkos::parallel_for(Kokkos::TeamThreadRange(teamMember,0,numFields2_), [&] (
const int& fieldOrdinal2) {
1933 for (
int fieldOrdinal3=0; fieldOrdinal3 < numFields3_; fieldOrdinal3++)
1935 int fieldOrdinal = (fieldOrdinal3 * numFields2_ + fieldOrdinal2) * numFields1_ + fieldOrdinal1;
1936 for (
int pointOrdinal=0; pointOrdinal<numPoints_; pointOrdinal++)
1938 output_(fieldOrdinal,pointOrdinal) = weight_ * input1_(fieldOrdinal1,pointOrdinal) * input2_(fieldOrdinal2,pointOrdinal) * input3_(fieldOrdinal3,pointOrdinal);
1943 else if (input1_.rank() == 3)
1945 int spaceDim = input1_.extent_int(2);
1946 Kokkos::parallel_for(Kokkos::TeamThreadRange(teamMember,0,numFields2_), [&] (
const int& fieldOrdinal2) {
1947 for (
int fieldOrdinal3=0; fieldOrdinal3 < numFields3_; fieldOrdinal3++)
1949 int fieldOrdinal = (fieldOrdinal3 * numFields2_ + fieldOrdinal2) * numFields1_ + fieldOrdinal1;
1950 for (
int pointOrdinal=0; pointOrdinal<numPoints_; pointOrdinal++)
1952 for (
int d=0; d<spaceDim; d++)
1954 output_(fieldOrdinal,pointOrdinal,d) = weight_ * input1_(fieldOrdinal1,pointOrdinal,d) * input2_(fieldOrdinal2,pointOrdinal) * input3_(fieldOrdinal3,pointOrdinal);
1960 else if (input2_.rank() == 3)
1962 int spaceDim = input2_.extent_int(2);
1963 Kokkos::parallel_for(Kokkos::TeamThreadRange(teamMember,0,numFields2_), [&] (
const int& fieldOrdinal2) {
1964 for (
int fieldOrdinal3=0; fieldOrdinal3 < numFields3_; fieldOrdinal3++)
1966 int fieldOrdinal = (fieldOrdinal3 * numFields2_ + fieldOrdinal2) * numFields1_ + fieldOrdinal1;
1967 for (
int pointOrdinal=0; pointOrdinal<numPoints_; pointOrdinal++)
1969 for (
int d=0; d<spaceDim; d++)
1971 output_(fieldOrdinal,pointOrdinal,d) = weight_ * input1_(fieldOrdinal1,pointOrdinal) * input2_(fieldOrdinal2,pointOrdinal,d) * input3_(fieldOrdinal3,pointOrdinal);
1977 else if (input3_.rank() == 3)
1979 int spaceDim = input3_.extent_int(2);
1980 Kokkos::parallel_for(Kokkos::TeamThreadRange(teamMember,0,numFields2_), [&] (
const int& fieldOrdinal2) {
1981 for (
int fieldOrdinal3=0; fieldOrdinal3 < numFields3_; fieldOrdinal3++)
1983 int fieldOrdinal = (fieldOrdinal3 * numFields2_ + fieldOrdinal2) * numFields1_ + fieldOrdinal1;
1984 for (
int pointOrdinal=0; pointOrdinal<numPoints_; pointOrdinal++)
1986 for (
int d=0; d<spaceDim; d++)
1988 output_(fieldOrdinal,pointOrdinal,d) = weight_ * input1_(fieldOrdinal1,pointOrdinal) * input2_(fieldOrdinal2,pointOrdinal) * input3_(fieldOrdinal3,pointOrdinal,d);
2001 if ((input1_.rank() == 2) && (input2_.rank() == 2) && (input3_.rank() == 2) )
2003 Kokkos::parallel_for(Kokkos::TeamThreadRange(teamMember,0,numFields2_), [&] (
const int& fieldOrdinal2) {
2004 for (
int fieldOrdinal3=0; fieldOrdinal3 < numFields3_; fieldOrdinal3++)
2006 int fieldOrdinal = (fieldOrdinal3 * numFields2_ + fieldOrdinal2) * numFields1_ + fieldOrdinal1;
2007 for (
int pointOrdinal3=0; pointOrdinal3<numPoints3_; pointOrdinal3++)
2009 for (
int pointOrdinal2=0; pointOrdinal2<numPoints2_; pointOrdinal2++)
2011 for (
int pointOrdinal1=0; pointOrdinal1<numPoints1_; pointOrdinal1++)
2013 int pointOrdinal = (pointOrdinal3 * numPoints2_ + pointOrdinal2) * numPoints1_ + pointOrdinal1;
2014 output_(fieldOrdinal,pointOrdinal) = weight_ * input1_(fieldOrdinal1,pointOrdinal1) * input2_(fieldOrdinal2,pointOrdinal2) * input3_(fieldOrdinal3,pointOrdinal3);
2021 else if (input1_.rank() == 3)
2023 int spaceDim = input1_.extent_int(2);
2024 Kokkos::parallel_for(Kokkos::TeamThreadRange(teamMember,0,numFields2_), [&] (
const int& fieldOrdinal2) {
2025 for (
int fieldOrdinal3=0; fieldOrdinal3 < numFields3_; fieldOrdinal3++)
2027 int fieldOrdinal = (fieldOrdinal3 * numFields2_ + fieldOrdinal2) * numFields1_ + fieldOrdinal1;
2028 for (
int pointOrdinal3=0; pointOrdinal3<numPoints3_; pointOrdinal3++)
2030 for (
int pointOrdinal2=0; pointOrdinal2<numPoints2_; pointOrdinal2++)
2032 for (
int pointOrdinal1=0; pointOrdinal1<numPoints1_; pointOrdinal1++)
2034 int pointOrdinal = (pointOrdinal3 * numPoints2_ + pointOrdinal2) * numPoints1_ + pointOrdinal1;
2035 for (
int d=0; d<spaceDim; d++)
2037 output_(fieldOrdinal,pointOrdinal,d) = weight_ * input1_(fieldOrdinal1,pointOrdinal1,d) * input2_(fieldOrdinal2,pointOrdinal2) * input3_(fieldOrdinal3,pointOrdinal3);
2045 else if (input2_.rank() == 3)
2047 int spaceDim = input2_.extent_int(2);
2048 Kokkos::parallel_for(Kokkos::TeamThreadRange(teamMember,0,numFields2_), [&] (
const int& fieldOrdinal2) {
2049 for (
int fieldOrdinal3=0; fieldOrdinal3 < numFields3_; fieldOrdinal3++)
2051 int fieldOrdinal = (fieldOrdinal3 * numFields2_ + fieldOrdinal2) * numFields1_ + fieldOrdinal1;
2052 for (
int pointOrdinal3=0; pointOrdinal3<numPoints3_; pointOrdinal3++)
2054 for (
int pointOrdinal2=0; pointOrdinal2<numPoints2_; pointOrdinal2++)
2056 for (
int pointOrdinal1=0; pointOrdinal1<numPoints1_; pointOrdinal1++)
2058 int pointOrdinal = (pointOrdinal3 * numPoints2_ + pointOrdinal2) * numPoints1_ + pointOrdinal1;
2059 for (
int d=0; d<spaceDim; d++)
2061 output_(fieldOrdinal,pointOrdinal,d) = weight_ * input1_(fieldOrdinal1,pointOrdinal1) * input2_(fieldOrdinal2,pointOrdinal2,d) * input3_(fieldOrdinal3,pointOrdinal3);
2069 else if (input3_.rank() == 3)
2071 int spaceDim = input3_.extent_int(2);
2072 Kokkos::parallel_for(Kokkos::TeamThreadRange(teamMember,0,numFields2_), [&] (
const int& fieldOrdinal2) {
2073 for (
int fieldOrdinal3=0; fieldOrdinal3 < numFields3_; fieldOrdinal3++)
2075 int fieldOrdinal = (fieldOrdinal3 * numFields2_ + fieldOrdinal2) * numFields1_ + fieldOrdinal1;
2076 for (
int pointOrdinal3=0; pointOrdinal3<numPoints3_; pointOrdinal3++)
2078 for (
int pointOrdinal2=0; pointOrdinal2<numPoints2_; pointOrdinal2++)
2080 for (
int pointOrdinal1=0; pointOrdinal1<numPoints1_; pointOrdinal1++)
2082 int pointOrdinal = (pointOrdinal3 * numPoints2_ + pointOrdinal2) * numPoints1_ + pointOrdinal1;
2083 for (
int d=0; d<spaceDim; d++)
2085 output_(fieldOrdinal,pointOrdinal,d) = weight_ * input1_(fieldOrdinal1,pointOrdinal1) * input2_(fieldOrdinal2,pointOrdinal2) * input3_(fieldOrdinal3,pointOrdinal3,d);
2102 template<
typename BasisBaseClass =
void>
2106 using BasisBase = BasisBaseClass;
2109 using typename BasisBase::OutputViewType;
2110 using typename BasisBase::PointViewType;
2111 using typename BasisBase::ScalarViewType;
2113 using typename BasisBase::OutputValueType;
2114 using typename BasisBase::PointValueType;
2116 using typename BasisBase::ExecutionSpace;
2118 using BasisPtr = Teuchos::RCP<BasisBase>;
2124 Basis_TensorBasis3(BasisPtr basis1, BasisPtr basis2, BasisPtr basis3,
const bool useShardsCellTopologyAndTags =
false)
2126 TensorBasis(Teuchos::rcp(
new TensorBasis(basis1,basis2,FUNCTION_SPACE_MAX,useShardsCellTopologyAndTags)),
2128 FUNCTION_SPACE_MAX,useShardsCellTopologyAndTags),
2143 std::vector<BasisPtr> componentBases {basis1_, basis2_, basis3_};
2173 virtual void getValues(OutputViewType outputValues,
const EOperator operatorType,
2174 const PointViewType inputPoints12,
const PointViewType inputPoints3,
2175 bool tensorPoints)
const override
2179 int spaceDim1 = basis1_->getDomainDimension();
2180 int spaceDim2 = basis2_->getDomainDimension();
2182 int totalSpaceDim12 = inputPoints12.extent_int(1);
2184 TEUCHOS_ASSERT(spaceDim1 + spaceDim2 == totalSpaceDim12);
2188 auto inputPoints1 = Kokkos::subview(inputPoints12,Kokkos::ALL(),std::make_pair(0,spaceDim1));
2189 auto inputPoints2 = Kokkos::subview(inputPoints12,Kokkos::ALL(),std::make_pair(spaceDim1,totalSpaceDim12));
2191 this->
getValues(outputValues, operatorType, inputPoints1, inputPoints2, inputPoints3, tensorPoints);
2198 INTREPID2_TEST_FOR_EXCEPTION(
true, std::invalid_argument,
"This method does not yet handle tensorPoints=true");
2229 virtual void getValues(OutputViewType outputValues,
const EOperator operatorType,
2230 const PointViewType inputPoints1,
const PointViewType inputPoints2,
const PointViewType inputPoints3,
2231 bool tensorPoints)
const = 0;
2261 const PointViewType inputPoints1,
const EOperator operatorType1,
2262 const PointViewType inputPoints2,
const EOperator operatorType2,
2263 const PointViewType inputPoints3,
const EOperator operatorType3,
2264 bool tensorPoints,
double weight=1.0)
const
2266 int basisCardinality1 = basis1_->getCardinality();
2267 int basisCardinality2 = basis2_->getCardinality();
2268 int basisCardinality3 = basis3_->getCardinality();
2270 int spaceDim1 = inputPoints1.extent_int(1);
2271 int spaceDim2 = inputPoints2.extent_int(1);
2272 int spaceDim3 = inputPoints3.extent_int(1);
2274 int totalPointCount;
2275 int pointCount1, pointCount2, pointCount3;
2278 pointCount1 = inputPoints1.extent_int(0);
2279 pointCount2 = inputPoints2.extent_int(0);
2280 pointCount3 = inputPoints3.extent_int(0);
2281 totalPointCount = pointCount1 * pointCount2 * pointCount3;
2285 totalPointCount = inputPoints1.extent_int(0);
2286 pointCount1 = totalPointCount;
2287 pointCount2 = totalPointCount;
2288 pointCount3 = totalPointCount;
2290 INTREPID2_TEST_FOR_EXCEPTION((totalPointCount != inputPoints2.extent_int(0)) || (totalPointCount != inputPoints3.extent_int(0)),
2291 std::invalid_argument,
"If tensorPoints is false, the point counts must match!");
2310 OutputViewType outputValues1, outputValues2, outputValues3;
2314 if ((spaceDim1 == 1) && (operatorType1 == OPERATOR_VALUE))
2317 outputValues1 = getMatchingViewWithLabel(outputValues,
"output values - basis 1",basisCardinality1,pointCount1);
2321 outputValues1 = getMatchingViewWithLabel(outputValues,
"output values - basis 1",basisCardinality1,pointCount1,spaceDim1);
2323 if ((spaceDim2 == 1) && (operatorType2 == OPERATOR_VALUE))
2326 outputValues2 = getMatchingViewWithLabel(outputValues,
"output values - basis 2",basisCardinality2,pointCount2);
2330 outputValues2 = getMatchingViewWithLabel(outputValues,
"output values - basis 2",basisCardinality2,pointCount2,spaceDim2);
2332 if ((spaceDim3 == 1) && (operatorType3 == OPERATOR_VALUE))
2335 outputValues3 = getMatchingViewWithLabel(outputValues,
"output values - basis 3",basisCardinality3,pointCount3);
2339 outputValues3 = getMatchingViewWithLabel(outputValues,
"output values - basis 3",basisCardinality3,pointCount3,spaceDim3);
2342 basis1_->getValues(outputValues1,inputPoints1,operatorType1);
2343 basis2_->getValues(outputValues2,inputPoints2,operatorType2);
2344 basis3_->getValues(outputValues3,inputPoints3,operatorType3);
2346 const int outputVectorSize = getVectorSizeForHierarchicalParallelism<OutputValueType>();
2347 const int pointVectorSize = getVectorSizeForHierarchicalParallelism<PointValueType>();
2348 const int vectorSize = std::max(outputVectorSize,pointVectorSize);
2350 auto policy = Kokkos::TeamPolicy<ExecutionSpace>(basisCardinality1,Kokkos::AUTO(),vectorSize);
2353 FunctorType functor(outputValues, outputValues1, outputValues2, outputValues3, tensorPoints, weight);
2354 Kokkos::parallel_for(
"TensorBasis3_Functor", policy , functor);
2364 virtual void getDofCoeffs(
typename BasisBase::ScalarViewType dofCoeffs )
const override
2366 using ValueType =
typename BasisBase::ScalarViewType::value_type;
2367 using ResultLayout =
typename DeduceLayout< typename BasisBase::ScalarViewType >::result_layout;
2368 using ViewType = Kokkos::DynRankView<ValueType, ResultLayout, typename TensorBasis::DeviceType >;
2370 const ordinal_type basisCardinality1 = basis1_->getCardinality();
2371 const ordinal_type basisCardinality2 = basis2_->getCardinality();
2372 const ordinal_type basisCardinality3 = basis3_->getCardinality();
2374 auto dofCoeffs1 = ViewType(
"dofCoeffs1",basisCardinality1);
2375 auto dofCoeffs2 = ViewType(
"dofCoeffs2",basisCardinality2);
2376 auto dofCoeffs3 = ViewType(
"dofCoeffs3",basisCardinality3);
2378 basis1_->getDofCoeffs(dofCoeffs1);
2379 basis2_->getDofCoeffs(dofCoeffs2);
2380 basis3_->getDofCoeffs(dofCoeffs3);
2382 Kokkos::RangePolicy<ExecutionSpace> policy(0, basisCardinality3);
2383 Kokkos::parallel_for(policy, KOKKOS_LAMBDA (
const int fieldOrdinal3)
2385 for (
int fieldOrdinal2=0; fieldOrdinal2<basisCardinality2; fieldOrdinal2++)
2386 for (
int fieldOrdinal1=0; fieldOrdinal1<basisCardinality1; fieldOrdinal1++)
2388 const ordinal_type fieldOrdinal = fieldOrdinal1 + fieldOrdinal2 * basisCardinality1 + fieldOrdinal3 * (basisCardinality1*basisCardinality2);
2389 dofCoeffs(fieldOrdinal) = dofCoeffs1(fieldOrdinal1);
2390 dofCoeffs(fieldOrdinal) *= dofCoeffs2(fieldOrdinal2) * dofCoeffs3(fieldOrdinal3);
2399 virtual HostBasisPtr<OutputValueType, PointValueType>
2401 TEUCHOS_TEST_FOR_EXCEPTION(
true, std::invalid_argument,
"TensorBasis3 subclasses must override getHostBasis");
KOKKOS_INLINE_FUNCTION ScalarType getView1Entry()
Functor for computing values for the TensorBasis class.
ordinal_type getTensorDkEnumeration(ordinal_type dkEnum1, ordinal_type operatorOrder1, ordinal_type dkEnum2, ordinal_type operatorOrder2) const
Given "Dk" enumeration indices for the component bases, returns a Dk enumeration index for the compos...
Implements arbitrary-dimensional extrusion of a base shards::CellTopology.
View-like interface to tensor points; point components are stored separately; the appropriate coordin...
#define INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE(test, x, msg)
An abstract base class that defines interface for concrete basis implementations for Finite Element (...
void getValues(OutputViewType outputValues, const PointViewType inputPoints, const EOperator operatorType=OPERATOR_VALUE) const override
Evaluation of a FEM basis on a reference cell.
const VectorDataType & vectorData() const
VectorData accessor.
KOKKOS_INLINE_FUNCTION enable_if_t< rank==1, const Kokkos::View< typename RankExpander< DataScalar, rank >::value_type, DeviceType > & > getUnderlyingView() const
Returns the underlying view. Throws an exception if the underlying view is not rank 1...
For a multi-component tensor basis, specifies the operators to be applied to the components to produc...
virtual void getValues(OutputViewType outputValues, const EOperator operatorType, const PointViewType inputPoints12, const PointViewType inputPoints3, bool tensorPoints) const override
Evaluation of a tensor FEM basis on a reference cell.
Wrapper around a Kokkos::View that allows data that is constant or repeating in various logical dimen...
virtual void getValues(BasisValues< OutputValueType, DeviceType > outputValues, const TensorPoints< PointValueType, DeviceType > inputPoints, const EOperator operatorType=OPERATOR_VALUE) const override
Evaluation of a FEM basis on a reference cell, using point and output value containers that allow pre...
void getComponentPoints(const PointViewType inputPoints, const bool attemptTensorDecomposition, PointViewType &inputPoints1, PointViewType &inputPoints2, bool &tensorDecompositionSucceeded) const
Method to extract component points from composite points.
Header function for Intrepid2::Util class and other utility functions.
void getValues(OutputViewType outputValues, const PointViewType inputPoints1, const EOperator operatorType1, const PointViewType inputPoints2, const EOperator operatorType2, bool tensorPoints, double weight=1.0) const
Evaluation of a tensor FEM basis on a reference cell.
Implementation of an assert that can safely be called from device code.
Basis_TensorBasis(BasisPtr basis1, BasisPtr basis2, EFunctionSpace functionSpace=FUNCTION_SPACE_MAX, const bool useShardsCellTopologyAndTags=false)
Constructor.
TensorDataType & tensorData()
TensorData accessor for single-family scalar data.
The data containers in Intrepid2 that support sum factorization and other reduced-data optimizations ...
bool rotateXYNinetyDegrees() const
If true, this flag indicates that a vector component that spans the first two dimensions should be ro...
virtual OperatorTensorDecomposition getOperatorDecomposition(const EOperator operatorType) const
Returns a full decomposition of the specified operator. (Full meaning that all TensorBasis components...
KOKKOS_INLINE_FUNCTION int numFamilies() const
For valid vectorData, returns the number of families in vectorData; otherwise, returns number of Tens...
KOKKOS_INLINE_FUNCTION void set(ScalarType value)
KOKKOS_INLINE_FUNCTION int increment()
KOKKOS_INLINE_FUNCTION void setLocation(const Kokkos::Array< int, 7 > location)
KOKKOS_INLINE_FUNCTION ordinal_type numTensorComponents() const
Returns the number of tensorial components.
KOKKOS_INLINE_FUNCTION ScalarType getView2Entry()
virtual HostBasisPtr< OutputValueType, PointValueType > getHostBasis() const override
Creates and returns a Basis object whose DeviceType template argument is Kokkos::HostSpace::device_ty...
virtual OperatorTensorDecomposition getSimpleOperatorDecomposition(const EOperator &operatorType) const
Returns a simple decomposition of the specified operator: what operator(s) should be applied to basis...
static CellTopoPtr cellTopology(const shards::CellTopology &shardsCellTopo, ordinal_type tensorialDegree=0)
static accessor that returns a CellTopoPtr; these are lazily constructed and cached.
virtual void getDofCoords(typename BasisBase::ScalarViewType dofCoords) const override
Fills in spatial locations (coordinates) of degrees of freedom (nodes) on the reference cell...
virtual const char * getName() const override
Returns basis name.
Implementation of support for traversing component views alongside a view that represents a combinati...
virtual BasisValues< OutputValueType, DeviceType > allocateBasisValues(TensorPoints< PointValueType, DeviceType > points, const EOperator operatorType=OPERATOR_VALUE) const override
Allocate BasisValues container suitable for passing to the getValues() variant that takes a TensorPoi...
KOKKOS_INLINE_FUNCTION int nextIncrementRank()
virtual void getDofCoeffs(typename BasisBase::ScalarViewType dofCoeffs) const override
Fills in coefficients of degrees of freedom on the reference cell.
ordinal_type componentPointCount(const ordinal_type &tensorComponentOrdinal) const
Returns the number of points in the indicated component.
virtual void getDofCoeffs(typename BasisBase::ScalarViewType dofCoeffs) const override
Fills in coefficients of degrees of freedom on the reference cell.
OperatorTensorDecomposition expandedDecomposition(std::vector< Teuchos::RCP< Basis< DeviceType, OutputValueType, PointValueType > > > &bases)
takes as argument bases that are components in this decomposition, and decomposes them further if the...
Class that defines mappings from component cell topologies to their tensor product topologies...
virtual HostBasisPtr< OutputValueType, PointValueType > getHostBasis() const override
Creates and returns a Basis object whose DeviceType template argument is Kokkos::HostSpace::device_ty...
View-like interface to tensor data; tensor components are stored separately and multiplied together a...
virtual void getValues(OutputViewType outputValues, const EOperator operatorType, const PointViewType inputPoints1, const PointViewType inputPoints2, bool tensorPoints) const
Evaluation of a tensor FEM basis on a reference cell; subclasses should override this.
virtual OperatorTensorDecomposition getOperatorDecomposition(const EOperator operatorType) const override
Returns a full decomposition of the specified operator. (Full meaning that all TensorBasis components...
A helper class that allows iteration over three Kokkos Views simultaneously, according to tensor comb...
Basis defined as the tensor product of two component bases.
static ordinal_type getSubcellOrdinalMap(CellTopoPtr cellTopo, ordinal_type subcdim, ordinal_type subcord, ordinal_type subsubcdim, ordinal_type subsubcord)
Maps the from a subcell within a subcell of the present CellTopology to the subcell in the present Ce...
KOKKOS_INLINE_FUNCTION ScalarView< PointScalar, DeviceType > getTensorComponent(const ordinal_type &r) const
Returns the requested tensor component.
void getValues(OutputViewType outputValues, const PointViewType inputPoints1, const EOperator operatorType1, const PointViewType inputPoints2, const EOperator operatorType2, const PointViewType inputPoints3, const EOperator operatorType3, bool tensorPoints, double weight=1.0) const
Evaluation of a tensor FEM basis on a reference cell; subclasses should override this.
Reference-space field values for a basis, designed to support typical vector-valued bases...
Functor for computing values for the TensorBasis3 class.
KOKKOS_INLINE_FUNCTION std::enable_if< std::is_integral< iType >::value, int >::type extent_int(const iType &r) const
Returns the logical extent in the requested dimension.
Header file for the abstract base class Intrepid2::Basis.