15 #ifndef Intrepid2_HierarchicalBasis_HCURL_TRI_h
16 #define Intrepid2_HierarchicalBasis_HCURL_TRI_h
18 #include <Kokkos_DynRankView.hpp>
20 #include <Intrepid2_config.h>
34 template<
class DeviceType,
class OutputScalar,
class PointScalar,
35 class OutputFieldType,
class InputPointsType>
38 using ExecutionSpace =
typename DeviceType::execution_space;
39 using ScratchSpace =
typename ExecutionSpace::scratch_memory_space;
40 using OutputScratchView = Kokkos::View<OutputScalar*,ScratchSpace,Kokkos::MemoryTraits<Kokkos::Unmanaged>>;
41 using PointScratchView = Kokkos::View<PointScalar*, ScratchSpace,Kokkos::MemoryTraits<Kokkos::Unmanaged>>;
43 using TeamPolicy = Kokkos::TeamPolicy<ExecutionSpace>;
44 using TeamMember =
typename TeamPolicy::member_type;
48 OutputFieldType output_;
49 InputPointsType inputPoints_;
52 int numFields_, numPoints_;
54 size_t fad_size_output_;
56 static const int numVertices = 3;
57 static const int numEdges = 3;
58 static const int numFaceFamilies = 2;
59 const int edge_start_[numEdges] = {0,1,0};
60 const int edge_end_[numEdges] = {1,2,2};
61 const int face_family_start_[numFaceFamilies] = {0,1};
62 const int face_family_middle_[numFaceFamilies] = {1,2};
63 const int face_family_end_ [numFaceFamilies] = {2,0};
66 : opType_(opType), output_(output), inputPoints_(inputPoints),
67 polyOrder_(polyOrder),
68 fad_size_output_(getScalarDimensionForView(output))
70 numFields_ = output.extent_int(0);
71 numPoints_ = output.extent_int(1);
72 const int expectedCardinality = 3 * polyOrder_ + polyOrder_ * (polyOrder-1);
74 INTREPID2_TEST_FOR_EXCEPTION(numPoints_ != inputPoints.extent_int(0), std::invalid_argument,
"point counts need to match!");
75 INTREPID2_TEST_FOR_EXCEPTION(numFields_ != expectedCardinality, std::invalid_argument,
"output field size does not match basis cardinality");
78 KOKKOS_INLINE_FUNCTION
79 void operator()(
const TeamMember & teamMember )
const
81 auto pointOrdinal = teamMember.league_rank();
82 OutputScratchView edge_field_values_at_point, jacobi_values_at_point, other_values_at_point, other_values2_at_point;
83 if (fad_size_output_ > 0) {
84 edge_field_values_at_point = OutputScratchView(teamMember.team_shmem(), polyOrder_, fad_size_output_);
85 jacobi_values_at_point = OutputScratchView(teamMember.team_shmem(), polyOrder_, fad_size_output_);
86 other_values_at_point = OutputScratchView(teamMember.team_shmem(), polyOrder_, fad_size_output_);
87 other_values2_at_point = OutputScratchView(teamMember.team_shmem(), polyOrder_, fad_size_output_);
90 edge_field_values_at_point = OutputScratchView(teamMember.team_shmem(), polyOrder_);
91 jacobi_values_at_point = OutputScratchView(teamMember.team_shmem(), polyOrder_);
92 other_values_at_point = OutputScratchView(teamMember.team_shmem(), polyOrder_);
93 other_values2_at_point = OutputScratchView(teamMember.team_shmem(), polyOrder_);
96 const auto & x = inputPoints_(pointOrdinal,0);
97 const auto & y = inputPoints_(pointOrdinal,1);
100 const PointScalar lambda[3] = {1. - x - y, x, y};
101 const PointScalar lambda_dx[3] = {-1., 1., 0.};
102 const PointScalar lambda_dy[3] = {-1., 0., 1.};
104 const int num1DEdgeFunctions = polyOrder_;
111 int fieldOrdinalOffset = 0;
112 for (
int edgeOrdinal=0; edgeOrdinal<numEdges; edgeOrdinal++)
114 const auto & s0 = lambda [edge_start_[edgeOrdinal]];
115 const auto & s0_dx = lambda_dx[edge_start_[edgeOrdinal]];
116 const auto & s0_dy = lambda_dy[edge_start_[edgeOrdinal]];
118 const auto & s1 = lambda [ edge_end_[edgeOrdinal]];
119 const auto & s1_dx = lambda_dx[ edge_end_[edgeOrdinal]];
120 const auto & s1_dy = lambda_dy[ edge_end_[edgeOrdinal]];
122 Polynomials::shiftedScaledLegendreValues(edge_field_values_at_point, polyOrder_-1, PointScalar(s1), PointScalar(s0+s1));
123 for (
int edgeFunctionOrdinal=0; edgeFunctionOrdinal<num1DEdgeFunctions; edgeFunctionOrdinal++)
125 const auto & legendreValue = edge_field_values_at_point(edgeFunctionOrdinal);
126 const PointScalar xWeight = s0 * s1_dx - s1 * s0_dx;
127 const PointScalar yWeight = s0 * s1_dy - s1 * s0_dy;
128 output_(edgeFunctionOrdinal+fieldOrdinalOffset,pointOrdinal,0) = legendreValue * xWeight;
129 output_(edgeFunctionOrdinal+fieldOrdinalOffset,pointOrdinal,1) = legendreValue * yWeight;
131 fieldOrdinalOffset += num1DEdgeFunctions;
137 const double jacobiScaling = 1.0;
139 const int max_ij_sum = polyOrder_ - 1;
142 const int faceFieldOrdinalOffset = fieldOrdinalOffset;
143 for (
int familyOrdinal=1; familyOrdinal<=2; familyOrdinal++)
145 int fieldOrdinal = faceFieldOrdinalOffset + familyOrdinal - 1;
146 const auto &s2 = lambda[ face_family_end_[familyOrdinal-1]];
147 for (
int ij_sum=1; ij_sum <= max_ij_sum; ij_sum++)
149 for (
int i=0; i<ij_sum; i++)
151 const int j = ij_sum - i;
153 const int edgeBasisOrdinal = i + (familyOrdinal-1)*num1DEdgeFunctions;
154 const auto & edgeValue_x = output_(edgeBasisOrdinal,pointOrdinal,0);
155 const auto & edgeValue_y = output_(edgeBasisOrdinal,pointOrdinal,1);
156 const double alpha = i*2.0 + 1;
158 Polynomials::shiftedScaledIntegratedJacobiValues(jacobi_values_at_point, alpha, polyOrder_-1, s2, jacobiScaling);
159 const auto & jacobiValue = jacobi_values_at_point(j);
160 output_(fieldOrdinal,pointOrdinal,0) = edgeValue_x * jacobiValue;
161 output_(fieldOrdinal,pointOrdinal,1) = edgeValue_y * jacobiValue;
173 int fieldOrdinalOffset = 0;
180 auto & P_i = edge_field_values_at_point;
181 auto & L_2ip1_j = jacobi_values_at_point;
182 for (
int edgeOrdinal=0; edgeOrdinal<numEdges; edgeOrdinal++)
184 const auto & s0 = lambda[edge_start_[edgeOrdinal]];
185 const auto & s1 = lambda[ edge_end_[edgeOrdinal]];
187 const auto & s0_dx = lambda_dx[edge_start_[edgeOrdinal]];
188 const auto & s0_dy = lambda_dy[edge_start_[edgeOrdinal]];
189 const auto & s1_dx = lambda_dx[ edge_end_[edgeOrdinal]];
190 const auto & s1_dy = lambda_dy[ edge_end_[edgeOrdinal]];
192 const OutputScalar grad_s0_cross_grad_s1 = s0_dx * s1_dy - s1_dx * s0_dy;
194 Polynomials::shiftedScaledLegendreValues(P_i, polyOrder_-1, PointScalar(s1), PointScalar(s0+s1));
195 for (
int i=0; i<num1DEdgeFunctions; i++)
197 output_(i+fieldOrdinalOffset,pointOrdinal) = (i+2) * P_i(i) * grad_s0_cross_grad_s1;
199 fieldOrdinalOffset += num1DEdgeFunctions;
220 auto & P_2ip1_j = other_values_at_point;
223 const int faceFieldOrdinalOffset = fieldOrdinalOffset;
224 for (
int familyOrdinal=1; familyOrdinal<=2; familyOrdinal++)
226 int fieldOrdinal = faceFieldOrdinalOffset + familyOrdinal - 1;
228 const auto &s0_index = face_family_start_ [familyOrdinal-1];
229 const auto &s1_index = face_family_middle_[familyOrdinal-1];
230 const auto &s2_index = face_family_end_ [familyOrdinal-1];
231 const auto &s0 = lambda[s0_index];
232 const auto &s1 = lambda[s1_index];
233 const auto &s2 = lambda[s2_index];
234 const double jacobiScaling = 1.0;
236 const auto & s0_dx = lambda_dx[s0_index];
237 const auto & s0_dy = lambda_dy[s0_index];
238 const auto & s1_dx = lambda_dx[s1_index];
239 const auto & s1_dy = lambda_dy[s1_index];
240 const auto & s2_dx = lambda_dx[s2_index];
241 const auto & s2_dy = lambda_dy[s2_index];
243 const OutputScalar grad_s0_cross_grad_s1 = s0_dx * s1_dy - s1_dx * s0_dy;
245 Polynomials::shiftedScaledLegendreValues (P_i, polyOrder_-1, PointScalar(s1), PointScalar(s0+s1));
249 const PointScalar xEdgeWeight = s0 * s1_dx - s1 * s0_dx;
250 const PointScalar yEdgeWeight = s0 * s1_dy - s1 * s0_dy;
251 OutputScalar grad_s2_cross_xy_edgeWeight = s2_dx * yEdgeWeight - xEdgeWeight * s2_dy;
253 const int max_ij_sum = polyOrder_ - 1;
254 for (
int ij_sum=1; ij_sum <= max_ij_sum; ij_sum++)
256 for (
int i=0; i<ij_sum; i++)
258 const int j = ij_sum - i;
259 const OutputScalar edgeCurl = (i+2.) * P_i(i) * grad_s0_cross_grad_s1;
261 const double alpha = i*2.0 + 1;
263 Polynomials::shiftedScaledJacobiValues(P_2ip1_j, alpha, polyOrder_-1, PointScalar(s2), jacobiScaling);
264 Polynomials::shiftedScaledIntegratedJacobiValues(L_2ip1_j, alpha, polyOrder_-1, s2, jacobiScaling);
266 const PointScalar & edgeValue = P_i(i);
267 output_(fieldOrdinal,pointOrdinal) = L_2ip1_j(j) * edgeCurl + P_2ip1_j(j-1) * edgeValue * grad_s2_cross_xy_edgeWeight;
286 INTREPID2_TEST_FOR_ABORT(
true,
287 ">>> ERROR: (Intrepid2::Hierarchical_HCURL_TRI_Functor) Unsupported differential operator");
290 device_assert(
false);
297 size_t team_shmem_size (
int team_size)
const
300 size_t shmem_size = 0;
301 if (fad_size_output_ > 0)
302 shmem_size += 4 * OutputScratchView::shmem_size(polyOrder_ + 1, fad_size_output_);
304 shmem_size += 4 * OutputScratchView::shmem_size(polyOrder_ + 1);
324 template<
typename DeviceType,
325 typename OutputScalar = double,
326 typename PointScalar = double,
327 bool useCGBasis =
true>
329 :
public Basis<DeviceType,OutputScalar,PointScalar>
354 polyOrder_(polyOrder)
356 const int numEdgeFunctions = polyOrder * 3;
357 const int numFaceFunctions = polyOrder * (polyOrder-1);
365 const int degreeLength = 1;
369 int fieldOrdinalOffset = 0;
374 const shards::CellTopology cellTopo(shards::getCellTopologyData<shards::Triangle<> >());
375 const int numFunctionsPerEdge = polyOrder;
376 const int numEdges = cellTopo.getEdgeCount();
377 for (
int edgeOrdinal=0; edgeOrdinal<numEdges; edgeOrdinal++)
379 for (
int i=0; i<numFunctionsPerEdge; i++)
384 fieldOrdinalOffset += numFunctionsPerEdge;
386 INTREPID2_TEST_FOR_EXCEPTION(fieldOrdinalOffset != numEdgeFunctions, std::invalid_argument,
"Internal error: basis enumeration is incorrect");
389 const int max_ij_sum = polyOrder-1;
390 const int faceFieldOrdinalOffset = fieldOrdinalOffset;
391 for (
int faceFamilyOrdinal=1; faceFamilyOrdinal<=2; faceFamilyOrdinal++)
394 int fieldOrdinal = faceFieldOrdinalOffset + faceFamilyOrdinal - 1;
395 for (
int ij_sum=1; ij_sum <= max_ij_sum; ij_sum++)
397 for (
int i=0; i<ij_sum; i++)
404 fieldOrdinalOffset = fieldOrdinal - 1;
407 INTREPID2_TEST_FOR_EXCEPTION(fieldOrdinalOffset != this->basisCardinality_, std::invalid_argument,
"Internal error: basis enumeration is incorrect");
414 const ordinal_type tagSize = 4;
415 const ordinal_type posScDim = 0;
416 const ordinal_type posScOrd = 1;
417 const ordinal_type posDfOrd = 2;
420 const ordinal_type edgeDim = 1, faceDim = 2;
425 for (
int edgeOrdinal=0; edgeOrdinal<numEdges; edgeOrdinal++)
427 for (
int functionOrdinal=0; functionOrdinal<numFunctionsPerEdge; functionOrdinal++)
429 tagView(tagNumber*tagSize+0) = edgeDim;
430 tagView(tagNumber*tagSize+1) = edgeOrdinal;
431 tagView(tagNumber*tagSize+2) = functionOrdinal;
432 tagView(tagNumber*tagSize+3) = numFunctionsPerEdge;
436 const int numFunctionsPerFace = numFaceFunctions;
437 const int numFaces = 1;
438 for (
int faceOrdinal=0; faceOrdinal<numFaces; faceOrdinal++)
440 for (
int functionOrdinal=0; functionOrdinal<numFunctionsPerFace; functionOrdinal++)
442 tagView(tagNumber*tagSize+0) = faceDim;
443 tagView(tagNumber*tagSize+1) = faceOrdinal;
444 tagView(tagNumber*tagSize+2) = functionOrdinal;
445 tagView(tagNumber*tagSize+3) = numFunctionsPerFace;
454 for (ordinal_type i=0;i<cardinality;++i) {
455 tagView(i*tagSize+0) = faceDim;
456 tagView(i*tagSize+1) = 0;
457 tagView(i*tagSize+2) = i;
458 tagView(i*tagSize+3) = cardinality;
467 this->basisCardinality_,
480 return "Intrepid2_HierarchicalBasis_HCURL_TRI";
513 const EOperator operatorType = OPERATOR_VALUE )
const override
515 auto numPoints = inputPoints.extent_int(0);
519 FunctorType functor(operatorType, outputValues, inputPoints, polyOrder_);
521 const int outputVectorSize = getVectorSizeForHierarchicalParallelism<OutputScalar>();
522 const int pointVectorSize = getVectorSizeForHierarchicalParallelism<PointScalar>();
523 const int vectorSize = std::max(outputVectorSize,pointVectorSize);
524 const int teamSize = 1;
526 auto policy = Kokkos::TeamPolicy<ExecutionSpace>(numPoints,teamSize,vectorSize);
527 Kokkos::parallel_for(
"Hierarchical_HCURL_TRI_Functor", policy, functor);
538 BasisPtr<DeviceType,OutputScalar,PointScalar>
540 if(subCellDim == 1) {
541 return Teuchos::rcp(
new
545 INTREPID2_TEST_FOR_EXCEPTION(
true,std::invalid_argument,
"Input parameters out of bounds");
552 virtual BasisPtr<typename Kokkos::HostSpace::device_type, OutputScalar, PointScalar>
554 using HostDeviceType =
typename Kokkos::HostSpace::device_type;
556 return Teuchos::rcp(
new HostBasisType(polyOrder_) );
H(grad) basis on the line based on integrated Legendre polynomials.
Kokkos::View< ordinal_type *, typename ExecutionSpace::array_layout, Kokkos::HostSpace > OrdinalTypeArray1DHost
View type for 1d host array.
const char * getName() const override
Returns basis name.
unsigned basisCellTopologyKey_
Identifier of the base topology of the cells for which the basis is defined. See the Shards package f...
EBasis basisType_
Type of the basis.
Functor for computing values for the HierarchicalBasis_HCURL_TRI class.
An abstract base class that defines interface for concrete basis implementations for Finite Element (...
Kokkos::DynRankView< scalarType, Kokkos::LayoutStride, DeviceType > ScalarViewType
View type for scalars.
HierarchicalBasis_HCURL_TRI(int polyOrder, const EPointType pointType=POINTTYPE_DEFAULT)
Constructor.
virtual bool requireOrientation() const override
True if orientation is required.
Free functions, callable from device code, that implement various polynomials useful in basis definit...
Kokkos::View< ordinal_type *, typename ExecutionSpace::array_layout, Kokkos::HostSpace > OrdinalTypeArray1DHost
View type for 1d host array.
EFunctionSpace functionSpace_
The function space in which the basis is defined.
ordinal_type basisDegree_
Degree of the largest complete polynomial space that can be represented by the basis.
virtual KOKKOS_INLINE_FUNCTION void getValues(OutputViewType, const PointViewType, const EOperator, const typename Kokkos::TeamPolicy< ExecutionSpace >::member_type &teamMember, const typename ExecutionSpace::scratch_memory_space &scratchStorage, const ordinal_type subcellDim=-1, const ordinal_type subcellOrdinal=-1) const
Team-level evaluation of basis functions on a reference cell.
Header function for Intrepid2::Util class and other utility functions.
For mathematical details of the construction, see:
Kokkos::View< ordinal_type **, typename ExecutionSpace::array_layout, Kokkos::HostSpace > OrdinalTypeArray2DHost
View type for 2d host array.
Basis defining Legendre basis on the line, a polynomial subspace of L^2 (a.k.a. H(vol)) on the line...
Kokkos::DynRankView< PointValueType, Kokkos::LayoutStride, DeviceType > PointViewType
View type for input points.
virtual void getValues(OutputViewType outputValues, const PointViewType inputPoints, const EOperator operatorType=OPERATOR_VALUE) const override
Evaluation of a FEM basis on a reference cell.
Kokkos::DynRankView< OutputValueType, Kokkos::LayoutStride, DeviceType > OutputViewType
View type for basis value output.
ordinal_type basisCardinality_
Cardinality of the basis, i.e., the number of basis functions/degrees-of-freedom. ...
OrdinalTypeArray3DHost tagToOrdinal_
DoF tag to ordinal lookup table.
BasisPtr< DeviceType, OutputScalar, PointScalar > getSubCellRefBasis(const ordinal_type subCellDim, const ordinal_type subCellOrd) const override
returns the basis associated to a subCell.
virtual BasisPtr< typename Kokkos::HostSpace::device_type, OutputScalar, PointScalar > getHostBasis() const override
Creates and returns a Basis object whose DeviceType template argument is Kokkos::HostSpace::device_ty...
OrdinalTypeArray2DHost ordinalToTag_
"true" if tagToOrdinal_ and ordinalToTag_ have been initialized
ordinal_type getDegree() const
Returns the degree of the basis.
ECoordinates basisCoordinates_
The coordinate system for which the basis is defined.
Kokkos::DynRankView< OutputValueType, Kokkos::LayoutStride, DeviceType > OutputViewType
View type for basis value output.
OrdinalTypeArray2DHost fieldOrdinalH1PolynomialDegree_
H^1 polynomial degree for each degree of freedom. Only defined for hierarchical bases right now...
OrdinalTypeArray2DHost fieldOrdinalPolynomialDegree_
Polynomial degree for each degree of freedom. Only defined for hierarchical bases right now...
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, DeviceType > PointViewType
View type for input points.
Header file for the abstract base class Intrepid2::Basis.
typename DeviceType::execution_space ExecutionSpace
(Kokkos) Execution space for basis.