49 #ifndef Intrepid2_TensorBasis_h
50 #define Intrepid2_TensorBasis_h
52 #include <Kokkos_View.hpp>
53 #include <Kokkos_DynRankView.hpp>
55 #include <Intrepid2_config.h>
69 template<
unsigned spaceDim>
70 KOKKOS_INLINE_FUNCTION
71 void getDkEnumerationInverse(Kokkos::Array<int,spaceDim> &entries,
const ordinal_type dkEnum,
const ordinal_type operatorOrder);
74 KOKKOS_INLINE_FUNCTION
75 void getDkEnumerationInverse<1>(Kokkos::Array<int,1> &entries,
const ordinal_type dkEnum,
const ordinal_type operatorOrder)
77 entries[0] = operatorOrder;
81 KOKKOS_INLINE_FUNCTION
82 void getDkEnumerationInverse<2>(Kokkos::Array<int,2> &entries,
const ordinal_type dkEnum,
const ordinal_type operatorOrder)
84 entries[0] = operatorOrder - dkEnum;
89 KOKKOS_INLINE_FUNCTION
90 void getDkEnumerationInverse<3>(Kokkos::Array<int,3> &entries,
const ordinal_type dkEnum,
const ordinal_type operatorOrder)
95 for (ordinal_type yMult=0; yMult<=operatorOrder; yMult++)
97 for (ordinal_type zMult=0; zMult<=operatorOrder-yMult; zMult++)
99 const ordinal_type xMult = operatorOrder-(zMult+yMult);
100 if (dkEnum == getDkEnumeration<3>(xMult,yMult,zMult))
110 template<
unsigned spaceDim>
111 ordinal_type getDkEnumeration(Kokkos::Array<int,spaceDim> &entries);
114 inline ordinal_type getDkEnumeration<1>(Kokkos::Array<int,1> &entries)
116 return getDkEnumeration<1>(entries[0]);
120 inline ordinal_type getDkEnumeration<2>(Kokkos::Array<int,2> &entries)
122 return getDkEnumeration<2>(entries[0],entries[1]);
126 inline ordinal_type getDkEnumeration<3>(Kokkos::Array<int,3> &entries)
128 return getDkEnumeration<3>(entries[0],entries[1],entries[2]);
131 template<
unsigned spaceDim1,
unsigned spaceDim2>
132 inline ordinal_type getDkTensorIndex(
const ordinal_type dkEnum1,
const ordinal_type operatorOrder1,
133 const ordinal_type dkEnum2,
const ordinal_type operatorOrder2)
135 Kokkos::Array<int,spaceDim1> entries1;
136 getDkEnumerationInverse<spaceDim1>(entries1, dkEnum1, operatorOrder1);
138 Kokkos::Array<int,spaceDim2> entries2;
139 getDkEnumerationInverse<spaceDim2>(entries2, dkEnum2, operatorOrder2);
141 const int spaceDim = spaceDim1 + spaceDim2;
142 Kokkos::Array<int,spaceDim> entries;
144 for (
unsigned d=0; d<spaceDim1; d++)
146 entries[d] = entries1[d];
149 for (
unsigned d=0; d<spaceDim2; d++)
151 entries[d+spaceDim1] = entries2[d];
154 return getDkEnumeration<spaceDim>(entries);
162 template<
class ExecutionSpace,
class OutputScalar,
class OutputFieldType>
165 using ScratchSpace =
typename ExecutionSpace::scratch_memory_space;
166 using OutputScratchView = Kokkos::View<OutputScalar*,ScratchSpace,Kokkos::MemoryTraits<Kokkos::Unmanaged>>;
168 using TeamPolicy = Kokkos::TeamPolicy<ExecutionSpace>;
169 using TeamMember =
typename TeamPolicy::member_type;
172 using RankCombinationType =
typename TensorViewIteratorType::RankCombinationType;
174 OutputFieldType output_;
175 OutputFieldType input1_;
176 OutputFieldType input2_;
178 int numFields_, numPoints_;
179 int numFields1_, numPoints1_;
180 int numFields2_, numPoints2_;
184 Kokkos::vector<RankCombinationType> rank_combinations_;
190 TensorViewFunctor(OutputFieldType output, OutputFieldType inputValues1, OutputFieldType inputValues2,
191 bool tensorPoints,
double weight)
192 : output_(output), input1_(inputValues1), input2_(inputValues2), tensorPoints_(tensorPoints), weight_(weight)
194 numFields_ = output.extent_int(0);
195 numPoints_ = output.extent_int(1);
197 numFields1_ = inputValues1.extent_int(0);
198 numPoints1_ = inputValues1.extent_int(1);
200 numFields2_ = inputValues2.extent_int(0);
201 numPoints2_ = inputValues2.extent_int(1);
206 INTREPID2_TEST_FOR_EXCEPTION(numPoints_ != numPoints1_, std::invalid_argument,
"incompatible point counts");
207 INTREPID2_TEST_FOR_EXCEPTION(numPoints_ != numPoints2_, std::invalid_argument,
"incompatible point counts");
211 INTREPID2_TEST_FOR_EXCEPTION(numPoints_ != numPoints1_ * numPoints2_, std::invalid_argument,
"incompatible point counts");
214 INTREPID2_TEST_FOR_EXCEPTION(numFields_ != numFields1_ * numFields2_, std::invalid_argument,
"incompatible field sizes");
216 unsigned max_rank = std::max(inputValues1.rank(),inputValues2.rank());
218 INTREPID2_TEST_FOR_EXCEPTION(output.rank() > max_rank, std::invalid_argument,
"Unsupported view combination.");
219 rank_combinations_ = Kokkos::vector<RankCombinationType>(max_rank);
221 rank_combinations_[0] = TensorViewIteratorType::TENSOR_PRODUCT;
222 rank_combinations_[1] = tensorPoints ? TensorViewIteratorType::TENSOR_PRODUCT : TensorViewIteratorType::DIMENSION_MATCH;
223 for (
unsigned d=2; d<max_rank; d++)
227 if ((inputValues1.extent_int(d) == inputValues2.extent_int(d)) && (output.extent_int(d) == 1))
229 rank_combinations_[d] = TensorViewIteratorType::TENSOR_CONTRACTION;
231 else if (((inputValues1.extent_int(d) == output.extent_int(d)) && (inputValues2.extent_int(d) == 1))
232 || ((inputValues2.extent_int(d) == output.extent_int(d)) && (inputValues1.extent_int(d) == 1))
237 rank_combinations_[d] = TensorViewIteratorType::TENSOR_PRODUCT;
239 else if ((inputValues1.extent_int(d) == inputValues2.extent_int(d)) && (output.extent_int(d) == inputValues1.extent_int(d) * inputValues2.extent_int(d)))
242 rank_combinations_[d] = TensorViewIteratorType::TENSOR_PRODUCT;
244 else if ((inputValues1.extent_int(d) == inputValues2.extent_int(d)) && (output.extent_int(d) == inputValues1.extent_int(d)))
248 rank_combinations_[d] = TensorViewIteratorType::DIMENSION_MATCH;
252 std::cout <<
"inputValues1.extent_int(" << d <<
") = " << inputValues1.extent_int(d) << std::endl;
253 std::cout <<
"inputValues2.extent_int(" << d <<
") = " << inputValues2.extent_int(d) << std::endl;
254 std::cout <<
"output.extent_int(" << d <<
") = " << output.extent_int(d) << std::endl;
255 INTREPID2_TEST_FOR_EXCEPTION(
true, std::invalid_argument,
"unable to find an interpretation for this combination of views");
260 KOKKOS_INLINE_FUNCTION
261 void operator()(
const TeamMember & teamMember )
const
263 auto fieldOrdinal1 = teamMember.league_rank();
265 Kokkos::parallel_for(Kokkos::TeamThreadRange(teamMember,0,numFields2_), [&] (
const int& fieldOrdinal2) {
267 const int FIELD_ORDINAL_DIMENSION = 0;
268 it.
setLocation({fieldOrdinal1,0,0,0,0,0,0},{fieldOrdinal2,0,0,0,0,0,0});
269 int next_increment_rank = FIELD_ORDINAL_DIMENSION;
270 OutputScalar accumulator = 0;
277 if ((next_increment_rank < 0) || (rank_combinations_[next_increment_rank] != TensorViewIteratorType::TENSOR_CONTRACTION))
284 }
while (it.
increment() > FIELD_ORDINAL_DIMENSION);
302 template<
typename Basis1,
typename Basis2>
305 public Basis<typename Basis1::ExecutionSpace,typename Basis1::OutputValueType,typename Basis1::PointValueType>
330 basis1_(basis1),basis2_(basis2)
333 this->
basisDegree_ = std::max(basis1.getDegree(), basis2.getDegree());
336 std::ostringstream basisName;
337 basisName << basis1.getName() <<
" x " << basis2.getName();
338 name_ = basisName.str();
342 shards::CellTopology cellTopo1 = basis1.getBaseCellTopology();
343 shards::CellTopology cellTopo2 = basis2.getBaseCellTopology();
345 auto cellKey1 = basis1.getBaseCellTopology().getKey();
346 auto cellKey2 = basis2.getBaseCellTopology().getKey();
347 if ((cellKey1 == shards::Line<2>::key) && (cellKey2 == shards::Line<2>::key))
349 this->
basisCellTopology_ = shards::CellTopology(shards::getCellTopologyData<shards::Quadrilateral<4> >() );
351 else if (((cellKey1 == shards::Quadrilateral<4>::key) && (cellKey2 == shards::Line<2>::key))
352 || ((cellKey2 == shards::Quadrilateral<4>::key) && (cellKey1 == shards::Line<2>::key)))
354 this->
basisCellTopology_ = shards::CellTopology(shards::getCellTopologyData<shards::Hexahedron<8> >() );
358 INTREPID2_TEST_FOR_EXCEPTION(
true, std::invalid_argument,
"Cell topology combination not yet supported");
369 const ordinal_type tagSize = 4;
370 const ordinal_type posScDim = 0;
371 const ordinal_type posScOrd = 1;
372 const ordinal_type posDfOrd = 2;
378 int tensorSpaceDim = cellTopo.getDimension();
379 int spaceDim1 = cellTopo1.getDimension();
380 int spaceDim2 = cellTopo2.getDimension();
384 int degreeSize = basis1_.getPolynomialDegreeLength() + basis2_.getPolynomialDegreeLength();
390 for (
int d=0; d<=tensorSpaceDim; d++)
392 int d2_max = std::min(spaceDim2,d);
393 int subcellOffset = 0;
394 for (
int d2=0; d2<=d2_max; d2++)
397 if (d1 > spaceDim1)
continue;
399 unsigned subcellCount2 = cellTopo2.getSubcellCount(d2);
400 unsigned subcellCount1 = cellTopo1.getSubcellCount(d1);
401 for (
unsigned subcellOrdinal2=0; subcellOrdinal2<subcellCount2; subcellOrdinal2++)
403 ordinal_type subcellDofCount2 = basis2_.getDofCount(d2, subcellOrdinal2);
404 for (
unsigned subcellOrdinal1=0; subcellOrdinal1<subcellCount1; subcellOrdinal1++)
406 ordinal_type subcellDofCount1 = basis1_.getDofCount(d1, subcellOrdinal1);
407 ordinal_type tensorLocalDofCount = subcellDofCount1 * subcellDofCount2;
408 for (ordinal_type localDofID2 = 0; localDofID2<subcellDofCount2; localDofID2++)
410 ordinal_type fieldOrdinal2 = basis2_.getDofOrdinal(d2, subcellOrdinal2, localDofID2);
412 if (this->
basisType_ == BASIS_FEM_HIERARCHICAL) degreesField2 = basis2_.getPolynomialDegreeOfField(fieldOrdinal2);
413 for (ordinal_type localDofID1 = 0; localDofID1<subcellDofCount1; localDofID1++)
415 ordinal_type fieldOrdinal1 = basis1_.getDofOrdinal(d1, subcellOrdinal1, localDofID1);
416 ordinal_type tensorLocalDofID = localDofID2 * subcellDofCount1 + localDofID1;
417 ordinal_type tensorFieldOrdinal = fieldOrdinal2 * basis1_.getCardinality() + fieldOrdinal1;
418 tagView(tensorFieldOrdinal*tagSize+0) = d;
420 tagView(tensorFieldOrdinal*tagSize+2) = tensorLocalDofID;
421 tagView(tensorFieldOrdinal*tagSize+3) = tensorLocalDofCount;
423 if (this->
basisType_ == BASIS_FEM_HIERARCHICAL)
428 int degreeLengthField1 = degreesField1.extent_int(0);
429 int degreeLengthField2 = degreesField2.extent_int(0);
430 for (
int d3=0; d3<degreeLengthField1; d3++)
434 for (
int d3=0; d3<degreeLengthField2; d3++)
443 subcellOffset += subcellCount1 * subcellCount2;
479 INTREPID2_TEST_FOR_EXCEPTION(attemptTensorDecomposition, std::invalid_argument,
"tensor decomposition not yet supported");
493 int spaceDim1 = basis1_.getBaseCellTopology().getDimension();
494 int spaceDim2 = basis2_.getBaseCellTopology().getDimension();
496 int totalSpaceDim = inputPoints.extent_int(1);
498 TEUCHOS_ASSERT(spaceDim1 + spaceDim2 == totalSpaceDim);
502 inputPoints1 = Kokkos::subview(inputPoints,Kokkos::ALL(),std::make_pair(0,spaceDim1));
503 inputPoints2 = Kokkos::subview(inputPoints,Kokkos::ALL(),std::make_pair(spaceDim1,totalSpaceDim));
509 tensorDecompositionSucceeded =
false;
522 int spaceDim1 = basis1_.getBaseCellTopology().getDimension();
523 int spaceDim2 = basis2_.getBaseCellTopology().getDimension();
525 using ValueType =
typename BasisSuper::ScalarViewType::value_type;
526 using ResultLayout =
typename DeduceLayout< typename BasisSuper::ScalarViewType >::result_layout;
527 using DeviceType =
typename BasisSuper::ScalarViewType::device_type;
528 using ViewType = Kokkos::DynRankView<ValueType, ResultLayout, DeviceType >;
530 ViewType dofCoords1(
"dofCoords1",basis1_.getCardinality(),spaceDim1);
531 ViewType dofCoords2(
"dofCoords2",basis2_.getCardinality(),spaceDim2);
533 basis1_.getDofCoords(dofCoords1);
534 basis2_.getDofCoords(dofCoords2);
536 const ordinal_type basisCardinality1 = basis1_.getCardinality();
537 const ordinal_type basisCardinality2 = basis2_.getCardinality();
539 Kokkos::parallel_for(basisCardinality2, KOKKOS_LAMBDA (
const int fieldOrdinal2)
541 for (
int fieldOrdinal1=0; fieldOrdinal1<basisCardinality1; fieldOrdinal1++)
543 const ordinal_type fieldOrdinal = fieldOrdinal1 + fieldOrdinal2 * basisCardinality1;
544 for (
int d1=0; d1<spaceDim1; d1++)
546 dofCoords(fieldOrdinal,d1) = dofCoords1(fieldOrdinal1,d1);
548 for (
int d2=0; d2<spaceDim2; d2++)
550 dofCoords(fieldOrdinal,spaceDim1+d2) = dofCoords2(fieldOrdinal2,d2);
563 return name_.c_str();
575 ordinal_type dkEnum2, ordinal_type operatorOrder2)
const
577 unsigned spaceDim1 = basis1_.getBaseCellTopology().getDimension();
578 unsigned spaceDim2 = basis2_.getBaseCellTopology().getDimension();
588 return getDkTensorIndex<1, 1>(dkEnum1, operatorOrder1, dkEnum2, operatorOrder2);
590 return getDkTensorIndex<1, 2>(dkEnum1, operatorOrder1, dkEnum2, operatorOrder2);
592 INTREPID2_TEST_FOR_EXCEPTION(
true, std::invalid_argument,
"Unsupported dimension combination");
598 return getDkTensorIndex<2, 1>(dkEnum1, operatorOrder1, dkEnum2, operatorOrder2);
600 INTREPID2_TEST_FOR_EXCEPTION(
true, std::invalid_argument,
"Unsupported dimension combination");
615 INTREPID2_TEST_FOR_EXCEPTION(
true, std::invalid_argument,
"Unsupported dimension combination");
638 const EOperator operatorType = OPERATOR_VALUE )
const override
641 bool attemptTensorDecomposition =
false;
643 getComponentPoints(inputPoints, attemptTensorDecomposition, inputPoints1, inputPoints2, tensorPoints);
645 switch (operatorType)
658 auto opOrder = getOperatorOrder(operatorType);
661 for (
int derivativeCountComp2=0; derivativeCountComp2<=opOrder; derivativeCountComp2++)
663 int derivativeCountComp1=opOrder-derivativeCountComp2;
664 EOperator op1 = (derivativeCountComp1 == 0) ? OPERATOR_VALUE : EOperator(OPERATOR_D1 + (derivativeCountComp1 - 1));
665 EOperator op2 = (derivativeCountComp2 == 0) ? OPERATOR_VALUE : EOperator(OPERATOR_D1 + (derivativeCountComp2 - 1));
667 int spaceDim1 = inputPoints1.extent_int(1);
668 int spaceDim2 = inputPoints2.extent_int(1);
670 int dkCardinality1 = (op1 != OPERATOR_VALUE) ? getDkCardinality(op1, spaceDim1) : 1;
671 int dkCardinality2 = (op2 != OPERATOR_VALUE) ? getDkCardinality(op2, spaceDim2) : 1;
673 int basisCardinality1 = basis1_.getCardinality();
674 int basisCardinality2 = basis2_.getCardinality();
676 int totalPointCount = tensorPoints ? inputPoints1.extent_int(0) * inputPoints2.extent_int(0) : inputPoints1.extent_int(0);
678 int pointCount1, pointCount2;
681 pointCount1 = inputPoints1.extent_int(0);
682 pointCount2 = inputPoints2.extent_int(0);
686 pointCount1 = totalPointCount;
687 pointCount2 = totalPointCount;
691 if (op1 == OPERATOR_VALUE)
692 outputValues1 = getMatchingViewWithLabel(outputValues,
"output values - basis 1",basisCardinality1,pointCount1);
694 outputValues1 = getMatchingViewWithLabel(outputValues,
"output values - basis 1",basisCardinality1,pointCount1,dkCardinality1);
696 if (op2 == OPERATOR_VALUE)
697 outputValues2 = getMatchingViewWithLabel(outputValues,
"output values - basis 2",basisCardinality2,pointCount2);
699 outputValues2 = getMatchingViewWithLabel(outputValues,
"output values - basis 2",basisCardinality2,pointCount2,dkCardinality2);
701 basis1_.getValues(outputValues1,inputPoints1,op1);
702 basis2_.getValues(outputValues2,inputPoints2,op2);
704 const int outputVectorSize = getVectorSizeForHierarchicalParallelism<OutputValueType>();
705 const int pointVectorSize = getVectorSizeForHierarchicalParallelism<PointValueType>();
706 const int vectorSize = std::max(outputVectorSize,pointVectorSize);
708 auto policy = Kokkos::TeamPolicy<ExecutionSpace>(basisCardinality1,Kokkos::AUTO(),vectorSize);
713 for (
int dkEnum1=0; dkEnum1<dkCardinality1; dkEnum1++)
715 auto outputValues1_dkEnum1 = (op1 != OPERATOR_VALUE) ? Kokkos::subview(outputValues1,Kokkos::ALL(),Kokkos::ALL(),dkEnum1)
716 : Kokkos::subview(outputValues1,Kokkos::ALL(),Kokkos::ALL());
717 for (
int dkEnum2=0; dkEnum2<dkCardinality2; dkEnum2++)
719 auto outputValues2_dkEnum2 = (op2 != OPERATOR_VALUE) ? Kokkos::subview(outputValues2,Kokkos::ALL(),Kokkos::ALL(),dkEnum2)
720 : Kokkos::subview(outputValues2,Kokkos::ALL(),Kokkos::ALL());
722 ordinal_type dkTensorIndex =
getTensorDkEnumeration(dkEnum1, derivativeCountComp1, dkEnum2, derivativeCountComp2);
723 auto outputValues_dkTensor = Kokkos::subview(outputValues,Kokkos::ALL(),Kokkos::ALL(),dkTensorIndex);
729 FunctorType functor(outputValues_dkTensor, outputValues1_dkEnum1, outputValues2_dkEnum2, tensorPoints, weight);
730 Kokkos::parallel_for( policy , functor,
"TensorViewFunctor");
737 this->
getValues(outputValues, operatorType, inputPoints1, inputPoints2, tensorPoints);
768 bool tensorPoints)
const
770 INTREPID2_TEST_FOR_EXCEPTION(
true, std::invalid_argument,
"one-operator, two-inputPoints getValues should be overridden by TensorBasis subclasses");
797 const PointViewType inputPoints1,
const EOperator operatorType1,
798 const PointViewType inputPoints2,
const EOperator operatorType2,
799 bool tensorPoints,
double weight=1.0)
const
801 int basisCardinality1 = basis1_.getCardinality();
802 int basisCardinality2 = basis2_.getCardinality();
804 int totalPointCount = tensorPoints ? inputPoints1.extent_int(0) * inputPoints2.extent_int(0) : inputPoints1.extent_int(0);
806 int pointCount1, pointCount2;
809 pointCount1 = inputPoints1.extent_int(0);
810 pointCount2 = inputPoints2.extent_int(0);
814 pointCount1 = totalPointCount;
815 pointCount2 = totalPointCount;
818 int spaceDim1 = inputPoints1.extent_int(1);
819 int spaceDim2 = inputPoints2.extent_int(1);
821 INTREPID2_TEST_FOR_EXCEPTION(!tensorPoints && (totalPointCount != inputPoints2.extent_int(0)),
822 std::invalid_argument,
"If tensorPoints is false, the point counts must match!");
824 int opRank1 = getOperatorRank(basis1_.getFunctionSpace(), operatorType1, spaceDim1);
825 int opRank2 = getOperatorRank(basis2_.getFunctionSpace(), operatorType2, spaceDim2);
830 outputValues1 = getMatchingViewWithLabel(outputValues,
"output values - basis 1",basisCardinality1,pointCount1);
832 else if (opRank1 == 1)
834 outputValues1 = getMatchingViewWithLabel(outputValues,
"output values - basis 1",basisCardinality1,pointCount1,spaceDim1);
838 INTREPID2_TEST_FOR_EXCEPTION(
true, std::invalid_argument,
"Unsupported opRank1");
843 outputValues2 = getMatchingViewWithLabel(outputValues,
"output values - basis 2",basisCardinality2,pointCount2);
845 else if (opRank2 == 1)
847 outputValues2 = getMatchingViewWithLabel(outputValues,
"output values - basis 2",basisCardinality2,pointCount2,spaceDim2);
851 INTREPID2_TEST_FOR_EXCEPTION(
true, std::invalid_argument,
"Unsupported opRank2");
854 basis1_.getValues(outputValues1,inputPoints1,operatorType1);
855 basis2_.getValues(outputValues2,inputPoints2,operatorType2);
857 const int outputVectorSize = getVectorSizeForHierarchicalParallelism<OutputValueType>();
858 const int pointVectorSize = getVectorSizeForHierarchicalParallelism<PointValueType>();
859 const int vectorSize = std::max(outputVectorSize,pointVectorSize);
861 auto policy = Kokkos::TeamPolicy<ExecutionSpace>(basisCardinality1,Kokkos::AUTO(),vectorSize);
865 FunctorType functor(outputValues, outputValues1, outputValues2, tensorPoints, weight);
866 Kokkos::parallel_for( policy , functor,
"TensorViewFunctor");
877 template<
class ExecutionSpace,
class OutputScalar,
class OutputFieldType>
880 using ScratchSpace =
typename ExecutionSpace::scratch_memory_space;
881 using OutputScratchView = Kokkos::View<OutputScalar*,ScratchSpace,Kokkos::MemoryTraits<Kokkos::Unmanaged>>;
883 using TeamPolicy = Kokkos::TeamPolicy<ExecutionSpace>;
884 using TeamMember =
typename TeamPolicy::member_type;
886 OutputFieldType output_;
887 OutputFieldType input1_;
888 OutputFieldType input2_;
889 OutputFieldType input3_;
891 int numFields_, numPoints_;
892 int numFields1_, numPoints1_;
893 int numFields2_, numPoints2_;
894 int numFields3_, numPoints3_;
900 TensorBasis3_Functor(OutputFieldType output, OutputFieldType inputValues1, OutputFieldType inputValues2, OutputFieldType inputValues3,
901 bool tensorPoints,
double weight)
902 : output_(output), input1_(inputValues1), input2_(inputValues2), input3_(inputValues3), tensorPoints_(tensorPoints), weight_(weight)
904 numFields_ = output.extent_int(0);
905 numPoints_ = output.extent_int(1);
907 numFields1_ = inputValues1.extent_int(0);
908 numPoints1_ = inputValues1.extent_int(1);
910 numFields2_ = inputValues2.extent_int(0);
911 numPoints2_ = inputValues2.extent_int(1);
913 numFields3_ = inputValues3.extent_int(0);
914 numPoints3_ = inputValues3.extent_int(1);
921 INTREPID2_TEST_FOR_EXCEPTION(inputValues1.rank() > 3, std::invalid_argument,
"ranks greater than 3 not yet supported");
922 INTREPID2_TEST_FOR_EXCEPTION(inputValues2.rank() > 3, std::invalid_argument,
"ranks greater than 3 not yet supported");
923 INTREPID2_TEST_FOR_EXCEPTION(inputValues3.rank() > 3, std::invalid_argument,
"ranks greater than 3 not yet supported");
924 INTREPID2_TEST_FOR_EXCEPTION((inputValues1.rank() == 3) && (inputValues2.rank() == 3), std::invalid_argument,
"two vector-valued input ranks not yet supported");
925 INTREPID2_TEST_FOR_EXCEPTION((inputValues1.rank() == 3) && (inputValues3.rank() == 3), std::invalid_argument,
"two vector-valued input ranks not yet supported");
926 INTREPID2_TEST_FOR_EXCEPTION((inputValues2.rank() == 3) && (inputValues3.rank() == 3), std::invalid_argument,
"two vector-valued input ranks not yet supported");
931 INTREPID2_TEST_FOR_EXCEPTION(numPoints_ != numPoints1_, std::invalid_argument,
"incompatible point counts");
932 INTREPID2_TEST_FOR_EXCEPTION(numPoints_ != numPoints2_, std::invalid_argument,
"incompatible point counts");
933 INTREPID2_TEST_FOR_EXCEPTION(numPoints_ != numPoints3_, std::invalid_argument,
"incompatible point counts");
937 INTREPID2_TEST_FOR_EXCEPTION(numPoints_ != numPoints1_ * numPoints2_ * numPoints3_, std::invalid_argument,
"incompatible point counts");
940 INTREPID2_TEST_FOR_EXCEPTION(numFields_ != numFields1_ * numFields2_ * numFields3_, std::invalid_argument,
"incompatible field sizes");
943 KOKKOS_INLINE_FUNCTION
944 void operator()(
const TeamMember & teamMember )
const
946 auto fieldOrdinal1 = teamMember.league_rank();
950 if ((input1_.rank() == 2) && (input2_.rank() == 2) && (input3_.rank() == 2))
952 Kokkos::parallel_for(Kokkos::TeamThreadRange(teamMember,0,numFields2_), [&] (
const int& fieldOrdinal2) {
953 for (
int fieldOrdinal3=0; fieldOrdinal3 < numFields3_; fieldOrdinal3++)
955 int fieldOrdinal = (fieldOrdinal3 * numFields2_ + fieldOrdinal2) * numFields1_ + fieldOrdinal1;
956 for (
int pointOrdinal=0; pointOrdinal<numPoints_; pointOrdinal++)
958 output_(fieldOrdinal,pointOrdinal) = weight_ * input1_(fieldOrdinal1,pointOrdinal) * input2_(fieldOrdinal2,pointOrdinal) * input3_(fieldOrdinal3,pointOrdinal);
963 else if (input1_.rank() == 3)
965 int spaceDim = input1_.extent_int(2);
966 Kokkos::parallel_for(Kokkos::TeamThreadRange(teamMember,0,numFields2_), [&] (
const int& fieldOrdinal2) {
967 for (
int fieldOrdinal3=0; fieldOrdinal3 < numFields3_; fieldOrdinal3++)
969 int fieldOrdinal = (fieldOrdinal3 * numFields2_ + fieldOrdinal2) * numFields1_ + fieldOrdinal1;
970 for (
int pointOrdinal=0; pointOrdinal<numPoints_; pointOrdinal++)
972 for (
int d=0; d<spaceDim; d++)
974 output_(fieldOrdinal,pointOrdinal,d) = weight_ * input1_(fieldOrdinal1,pointOrdinal,d) * input2_(fieldOrdinal2,pointOrdinal) * input3_(fieldOrdinal3,pointOrdinal);
980 else if (input2_.rank() == 3)
982 int spaceDim = input2_.extent_int(2);
983 Kokkos::parallel_for(Kokkos::TeamThreadRange(teamMember,0,numFields2_), [&] (
const int& fieldOrdinal2) {
984 for (
int fieldOrdinal3=0; fieldOrdinal3 < numFields3_; fieldOrdinal3++)
986 int fieldOrdinal = (fieldOrdinal3 * numFields2_ + fieldOrdinal2) * numFields1_ + fieldOrdinal1;
987 for (
int pointOrdinal=0; pointOrdinal<numPoints_; pointOrdinal++)
989 for (
int d=0; d<spaceDim; d++)
991 output_(fieldOrdinal,pointOrdinal,d) = weight_ * input1_(fieldOrdinal1,pointOrdinal) * input2_(fieldOrdinal2,pointOrdinal,d) * input3_(fieldOrdinal3,pointOrdinal);
997 else if (input3_.rank() == 3)
999 int spaceDim = input3_.extent_int(2);
1000 Kokkos::parallel_for(Kokkos::TeamThreadRange(teamMember,0,numFields2_), [&] (
const int& fieldOrdinal2) {
1001 for (
int fieldOrdinal3=0; fieldOrdinal3 < numFields3_; fieldOrdinal3++)
1003 int fieldOrdinal = (fieldOrdinal3 * numFields2_ + fieldOrdinal2) * numFields1_ + fieldOrdinal1;
1004 for (
int pointOrdinal=0; pointOrdinal<numPoints_; pointOrdinal++)
1006 for (
int d=0; d<spaceDim; d++)
1008 output_(fieldOrdinal,pointOrdinal,d) = weight_ * input1_(fieldOrdinal1,pointOrdinal) * input2_(fieldOrdinal2,pointOrdinal) * input3_(fieldOrdinal3,pointOrdinal,d);
1021 if ((input1_.rank() == 2) && (input2_.rank() == 2) && (input3_.rank() == 2) )
1023 Kokkos::parallel_for(Kokkos::TeamThreadRange(teamMember,0,numFields2_), [&] (
const int& fieldOrdinal2) {
1024 for (
int fieldOrdinal3=0; fieldOrdinal3 < numFields3_; fieldOrdinal3++)
1026 int fieldOrdinal = (fieldOrdinal3 * numFields2_ + fieldOrdinal2) * numFields1_ + fieldOrdinal1;
1027 for (
int pointOrdinal3=0; pointOrdinal3<numPoints3_; pointOrdinal3++)
1029 for (
int pointOrdinal2=0; pointOrdinal2<numPoints2_; pointOrdinal2++)
1031 for (
int pointOrdinal1=0; pointOrdinal1<numPoints1_; pointOrdinal1++)
1033 int pointOrdinal = (pointOrdinal3 * numPoints2_ + pointOrdinal2) * numPoints1_ + pointOrdinal1;
1034 output_(fieldOrdinal,pointOrdinal) = weight_ * input1_(fieldOrdinal1,pointOrdinal1) * input2_(fieldOrdinal2,pointOrdinal2) * input3_(fieldOrdinal3,pointOrdinal3);
1041 else if (input1_.rank() == 3)
1043 int spaceDim = input1_.extent_int(2);
1044 Kokkos::parallel_for(Kokkos::TeamThreadRange(teamMember,0,numFields2_), [&] (
const int& fieldOrdinal2) {
1045 for (
int fieldOrdinal3=0; fieldOrdinal3 < numFields3_; fieldOrdinal3++)
1047 int fieldOrdinal = (fieldOrdinal3 * numFields2_ + fieldOrdinal2) * numFields1_ + fieldOrdinal1;
1048 for (
int pointOrdinal3=0; pointOrdinal3<numPoints3_; pointOrdinal3++)
1050 for (
int pointOrdinal2=0; pointOrdinal2<numPoints2_; pointOrdinal2++)
1052 for (
int pointOrdinal1=0; pointOrdinal1<numPoints1_; pointOrdinal1++)
1054 int pointOrdinal = (pointOrdinal3 * numPoints2_ + pointOrdinal2) * numPoints1_ + pointOrdinal1;
1055 for (
int d=0; d<spaceDim; d++)
1057 output_(fieldOrdinal,pointOrdinal,d) = weight_ * input1_(fieldOrdinal1,pointOrdinal1,d) * input2_(fieldOrdinal2,pointOrdinal2) * input3_(fieldOrdinal3,pointOrdinal3);
1065 else if (input2_.rank() == 3)
1067 int spaceDim = input2_.extent_int(2);
1068 Kokkos::parallel_for(Kokkos::TeamThreadRange(teamMember,0,numFields2_), [&] (
const int& fieldOrdinal2) {
1069 for (
int fieldOrdinal3=0; fieldOrdinal3 < numFields3_; fieldOrdinal3++)
1071 int fieldOrdinal = (fieldOrdinal3 * numFields2_ + fieldOrdinal2) * numFields1_ + fieldOrdinal1;
1072 for (
int pointOrdinal3=0; pointOrdinal3<numPoints3_; pointOrdinal3++)
1074 for (
int pointOrdinal2=0; pointOrdinal2<numPoints2_; pointOrdinal2++)
1076 for (
int pointOrdinal1=0; pointOrdinal1<numPoints1_; pointOrdinal1++)
1078 int pointOrdinal = (pointOrdinal3 * numPoints2_ + pointOrdinal2) * numPoints1_ + pointOrdinal1;
1079 for (
int d=0; d<spaceDim; d++)
1081 output_(fieldOrdinal,pointOrdinal,d) = weight_ * input1_(fieldOrdinal1,pointOrdinal1) * input2_(fieldOrdinal2,pointOrdinal2,d) * input3_(fieldOrdinal3,pointOrdinal3);
1089 else if (input3_.rank() == 3)
1091 int spaceDim = input3_.extent_int(2);
1092 Kokkos::parallel_for(Kokkos::TeamThreadRange(teamMember,0,numFields2_), [&] (
const int& fieldOrdinal2) {
1093 for (
int fieldOrdinal3=0; fieldOrdinal3 < numFields3_; fieldOrdinal3++)
1095 int fieldOrdinal = (fieldOrdinal3 * numFields2_ + fieldOrdinal2) * numFields1_ + fieldOrdinal1;
1096 for (
int pointOrdinal3=0; pointOrdinal3<numPoints3_; pointOrdinal3++)
1098 for (
int pointOrdinal2=0; pointOrdinal2<numPoints2_; pointOrdinal2++)
1100 for (
int pointOrdinal1=0; pointOrdinal1<numPoints1_; pointOrdinal1++)
1102 int pointOrdinal = (pointOrdinal3 * numPoints2_ + pointOrdinal2) * numPoints1_ + pointOrdinal1;
1103 for (
int d=0; d<spaceDim; d++)
1105 output_(fieldOrdinal,pointOrdinal,d) = weight_ * input1_(fieldOrdinal1,pointOrdinal1) * input2_(fieldOrdinal2,pointOrdinal2) * input3_(fieldOrdinal3,pointOrdinal3,d);
1122 template<
typename Basis1,
typename Basis2,
typename Basis3,
1123 typename ExecutionSpace=
typename Basis1::ExecutionSpace,
1124 typename OutputScalar = double,
1125 typename PointScalar =
double>
1134 using OutputViewType =
typename TensorBasis123::OutputViewType;
1135 using PointViewType =
typename TensorBasis123::PointViewType;
1138 using OutputValueType =
typename TensorBasis123::OutputValueType;
1139 using PointValueType =
typename TensorBasis123::PointValueType;
1179 virtual void getValues(OutputViewType outputValues,
const EOperator operatorType,
1180 const PointViewType inputPoints12,
const PointViewType inputPoints3,
1181 bool tensorPoints)
const override
1185 int spaceDim1 = basis1_.getBaseCellTopology().getDimension();
1186 int spaceDim2 = basis2_.getBaseCellTopology().getDimension();
1188 int totalSpaceDim12 = inputPoints12.extent_int(1);
1190 TEUCHOS_ASSERT(spaceDim1 + spaceDim2 == totalSpaceDim12);
1194 auto inputPoints1 = Kokkos::subview(inputPoints12,Kokkos::ALL(),std::make_pair(0,spaceDim1));
1195 auto inputPoints2 = Kokkos::subview(inputPoints12,Kokkos::ALL(),std::make_pair(spaceDim1,totalSpaceDim12));
1197 this->
getValues(outputValues, operatorType, inputPoints1, inputPoints2, inputPoints3, tensorPoints);
1204 INTREPID2_TEST_FOR_EXCEPTION(
true, std::invalid_argument,
"This method does not yet handle tensorPoints=true");
1235 virtual void getValues(OutputViewType outputValues,
const EOperator operatorType,
1236 const PointViewType inputPoints1,
const PointViewType inputPoints2,
const PointViewType inputPoints3,
1237 bool tensorPoints)
const = 0;
1267 const PointViewType inputPoints1,
const EOperator operatorType1,
1268 const PointViewType inputPoints2,
const EOperator operatorType2,
1269 const PointViewType inputPoints3,
const EOperator operatorType3,
1270 bool tensorPoints,
double weight=1.0)
const
1272 int basisCardinality1 = basis1_.getCardinality();
1273 int basisCardinality2 = basis2_.getCardinality();
1274 int basisCardinality3 = basis3_.getCardinality();
1276 int spaceDim1 = inputPoints1.extent_int(1);
1277 int spaceDim2 = inputPoints2.extent_int(1);
1278 int spaceDim3 = inputPoints3.extent_int(1);
1280 int totalPointCount;
1281 int pointCount1, pointCount2, pointCount3;
1284 pointCount1 = inputPoints1.extent_int(0);
1285 pointCount2 = inputPoints2.extent_int(0);
1286 pointCount3 = inputPoints3.extent_int(0);
1287 totalPointCount = pointCount1 * pointCount2 * pointCount3;
1291 totalPointCount = inputPoints1.extent_int(0);
1292 pointCount1 = totalPointCount;
1293 pointCount2 = totalPointCount;
1294 pointCount3 = totalPointCount;
1296 INTREPID2_TEST_FOR_EXCEPTION((totalPointCount != inputPoints2.extent_int(0)) || (totalPointCount != inputPoints3.extent_int(0)),
1297 std::invalid_argument,
"If tensorPoints is false, the point counts must match!");
1316 OutputViewType outputValues1, outputValues2, outputValues3;
1320 if ((spaceDim1 == 1) && (operatorType1 == OPERATOR_VALUE))
1323 outputValues1 = getMatchingViewWithLabel(outputValues,
"output values - basis 1",basisCardinality1,pointCount1);
1327 outputValues1 = getMatchingViewWithLabel(outputValues,
"output values - basis 1",basisCardinality1,pointCount1,spaceDim1);
1329 if ((spaceDim2 == 1) && (operatorType2 == OPERATOR_VALUE))
1332 outputValues2 = getMatchingViewWithLabel(outputValues,
"output values - basis 2",basisCardinality2,pointCount2);
1336 outputValues2 = getMatchingViewWithLabel(outputValues,
"output values - basis 2",basisCardinality2,pointCount2,spaceDim2);
1338 if ((spaceDim3 == 1) && (operatorType3 == OPERATOR_VALUE))
1341 outputValues3 = getMatchingViewWithLabel(outputValues,
"output values - basis 3",basisCardinality3,pointCount3);
1345 outputValues3 = getMatchingViewWithLabel(outputValues,
"output values - basis 3",basisCardinality3,pointCount3,spaceDim3);
1348 basis1_.getValues(outputValues1,inputPoints1,operatorType1);
1349 basis2_.getValues(outputValues2,inputPoints2,operatorType2);
1350 basis3_.getValues(outputValues3,inputPoints3,operatorType3);
1352 const int outputVectorSize = getVectorSizeForHierarchicalParallelism<OutputScalar>();
1353 const int pointVectorSize = getVectorSizeForHierarchicalParallelism<PointScalar>();
1354 const int vectorSize = std::max(outputVectorSize,pointVectorSize);
1356 auto policy = Kokkos::TeamPolicy<ExecutionSpace>(basisCardinality1,Kokkos::AUTO(),vectorSize);
1359 FunctorType functor(outputValues, outputValues1, outputValues2, outputValues3, tensorPoints, weight);
1360 Kokkos::parallel_for( policy , functor,
"TensorBasis3_Functor");
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.
KOKKOS_INLINE_FUNCTION ScalarType getView1Entry()
pointValueType PointValueType
Point value type for basis; default is double.
Functor for computing values for the TensorBasis class.
Kokkos::View< ordinal_type *, typename ExecSpaceType::array_layout, Kokkos::HostSpace > OrdinalTypeArray1DHost
View type for 1d host array.
Kokkos::View< ordinal_type **, typename ExecSpaceType::array_layout, Kokkos::HostSpace > OrdinalTypeArray2DHost
View type for 2d host array.
OrdinalTypeArray3DHost tagToOrdinal_
DoF tag to ordinal lookup table.
virtual const char * getName() const override
Returns basis name.
ordinal_type basisCardinality_
Cardinality of the basis, i.e., the number of basis functions/degrees-of-freedom. ...
ECoordinates basisCoordinates_
The coordinate system for which the basis is defined.
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...
An abstract base class that defines interface for concrete basis implementations for Finite Element (...
virtual void getDofCoords(typename BasisSuper::ScalarViewType dofCoords) const override
Fills in spatial locations (coordinates) of degrees of freedom (nodes) on the reference cell...
void getValues(OutputViewType outputValues, const PointViewType inputPoints, const EOperator operatorType=OPERATOR_VALUE) const override
Evaluation of a FEM basis on a reference cell.
Basis_TensorBasis(Basis1 basis1, Basis2 basis2)
Constructor.
virtual void getValues(OutputViewType, const PointViewType, const EOperator=OPERATOR_VALUE) const
Evaluation of a FEM basis on a reference cell.
ordinal_type basisDegree_
Degree of the largest complete polynomial space that can be represented by the basis.
For two cell topologies whose tensor product is a third, this class establishes a mapping from subcel...
Header function for Intrepid2::Util class and other utility functions.
Implementation of an assert that can safely be called from device code.
unsigned getCompositeSubcellOrdinal(unsigned subcell1Dim, unsigned subcell1Ordinal, unsigned subcell2Dim, unsigned subcell2Ordinal)
Map from component subcell ordinals to the corresponding composite subcell ordinal.
EBasis basisType_
Type of the basis.
Kokkos::DynRankView< OutputValueType, Kokkos::LayoutStride, ExecSpaceType > OutputViewType
View type for basis value output.
KOKKOS_INLINE_FUNCTION void set(ScalarType value)
KOKKOS_INLINE_FUNCTION int increment()
KOKKOS_INLINE_FUNCTION void setLocation(const Kokkos::Array< int, 7 > location)
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.
OrdinalTypeArray2DHost fieldOrdinalPolynomialDegree_
Polynomial degree for each degree of freedom. Only defined for hierarchical bases right now...
KOKKOS_INLINE_FUNCTION ScalarType getView2Entry()
void getComponentPoints(const PointViewType inputPoints, const bool attemptTensorDecomposition, PointViewType &inputPoints1, PointViewType &inputPoints2, bool &tensorDecompositionSucceeded) const
Method to extract component points from composite points.
void setOrdinalTagData(OrdinalTypeView3D &tagToOrdinal, OrdinalTypeView2D &ordinalToTag, const OrdinalTypeView1D tags, const ordinal_type basisCard, const ordinal_type tagSize, const ordinal_type posScDim, const ordinal_type posScOrd, const ordinal_type posDfOrd)
Fills ordinalToTag_ and tagToOrdinal_ by basis-specific tag data.
Kokkos::DynRankView< PointValueType, Kokkos::LayoutStride, ExecSpaceType > PointViewType
View type for input points.
Implementation of support for traversing component views alongside a view that represents a combinati...
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.
KOKKOS_INLINE_FUNCTION int nextIncrementRank()
outputValueType OutputValueType
Output value type for basis; default is double.
Kokkos::DynRankView< scalarType, Kokkos::LayoutStride, ExecSpaceType > ScalarViewType
View type for scalars.
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.
Class that defines mappings from component cell topologies to their tensor product topologies...
ExecSpaceType ExecutionSpace
(Kokkos) Execution space for basis.
A helper class that allows iteration over three Kokkos Views simultaneously, according to tensor comb...
EBasis getBasisType() const
Returns the basis type.
Basis defined as the tensor product of two component bases.
Functor for computing values for the TensorBasis3 class.
Header file for the abstract base class Intrepid2::Basis.
OrdinalTypeArray2DHost ordinalToTag_
"true" if tagToOrdinal_ and ordinalToTag_ have been initialized
shards::CellTopology basisCellTopology_
Base topology of the cells for which the basis is defined. See the Shards package for definition of b...