Intrepid2
Intrepid2_HierarchicalBasis_HCURL_TRI.hpp
Go to the documentation of this file.
1// @HEADER
2// *****************************************************************************
3// Intrepid2 Package
4//
5// Copyright 2007 NTESS and the Intrepid2 contributors.
6// SPDX-License-Identifier: BSD-3-Clause
7// *****************************************************************************
8// @HEADER
9
15#ifndef Intrepid2_HierarchicalBasis_HCURL_TRI_h
16#define Intrepid2_HierarchicalBasis_HCURL_TRI_h
17
18#include <Kokkos_DynRankView.hpp>
19
20#include <Intrepid2_config.h>
21
22#include "Intrepid2_Basis.hpp"
25#include "Intrepid2_Utils.hpp"
26
27namespace Intrepid2
28{
34 template<class DeviceType, class OutputScalar, class PointScalar,
35 class OutputFieldType, class InputPointsType>
37 {
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>>;
42
43 using TeamPolicy = Kokkos::TeamPolicy<ExecutionSpace>;
44 using TeamMember = typename TeamPolicy::member_type;
45
46 EOperator opType_;
47
48 OutputFieldType output_; // F,P
49 InputPointsType inputPoints_; // P,D
50
51 int polyOrder_;
52 int numFields_, numPoints_;
53
54 size_t fad_size_output_;
55
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}; // edge i is from edge_start_[i] to edge_end_[i]
60 const int edge_end_[numEdges] = {1,2,2}; // edge i is from edge_start_[i] to edge_end_[i]
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};
64
65 Hierarchical_HCURL_TRI_Functor(EOperator opType, OutputFieldType output, InputPointsType inputPoints, int polyOrder)
66 : opType_(opType), output_(output), inputPoints_(inputPoints),
67 polyOrder_(polyOrder),
68 fad_size_output_(getScalarDimensionForView(output))
69 {
70 numFields_ = output.extent_int(0);
71 numPoints_ = output.extent_int(1);
72 const int expectedCardinality = 3 * polyOrder_ + polyOrder_ * (polyOrder-1);
73
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");
76 }
77
78 KOKKOS_INLINE_FUNCTION
79 void operator()( const TeamMember & teamMember ) const
80 {
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_);
88 }
89 else {
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_);
94 }
95
96 const auto & x = inputPoints_(pointOrdinal,0);
97 const auto & y = inputPoints_(pointOrdinal,1);
98
99 // write as barycentric coordinates:
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.};
103
104 const int num1DEdgeFunctions = polyOrder_; // per edge
105
106 switch (opType_)
107 {
108 case OPERATOR_VALUE:
109 {
110 // edge functions
111 int fieldOrdinalOffset = 0;
112 for (int edgeOrdinal=0; edgeOrdinal<numEdges; edgeOrdinal++)
113 {
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]];
117
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]];
121
122 Polynomials::shiftedScaledLegendreValues(edge_field_values_at_point, polyOrder_-1, PointScalar(s1), PointScalar(s0+s1));
123 for (int edgeFunctionOrdinal=0; edgeFunctionOrdinal<num1DEdgeFunctions; edgeFunctionOrdinal++)
124 {
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;
130 }
131 fieldOrdinalOffset += num1DEdgeFunctions;
132 }
133
134 // face functions
135 {
136 // these functions multiply the edge functions from the 01 edge by integrated Jacobi functions, appropriately scaled
137 const double jacobiScaling = 1.0; // s0 + s1 + s2
138
139 const int max_ij_sum = polyOrder_ - 1;
140
141 // following ESEAS, we interleave the face families. This groups all the face dofs of a given degree together.
142 const int faceFieldOrdinalOffset = fieldOrdinalOffset;
143 for (int familyOrdinal=1; familyOrdinal<=2; familyOrdinal++)
144 {
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++)
148 {
149 for (int i=0; i<ij_sum; i++)
150 {
151 const int j = ij_sum - i; // j >= 1
152 // family 1 involves edge functions from edge (0,1) (edgeOrdinal 0); family 2 involves functions from edge (1,2) (edgeOrdinal 1)
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;
157
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;
162
163 fieldOrdinal += 2; // 2 because there are two face families, and we interleave them.
164 }
165 }
166 }
167 }
168 } // end OPERATOR_VALUE
169 break;
170 case OPERATOR_CURL:
171 {
172 // edge functions
173 int fieldOrdinalOffset = 0;
174 /*
175 Per Fuentes et al. (see Appendix E.1, E.2), the curls of the edge functions, are
176 (i+2) * [P_i](s0,s1) * (grad s0 \times grad s1)
177 The P_i we have implemented in shiftedScaledLegendreValues.
178 */
179 // rename the scratch memory to match our usage here:
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++)
183 {
184 const auto & s0 = lambda[edge_start_[edgeOrdinal]];
185 const auto & s1 = lambda[ edge_end_[edgeOrdinal]];
186
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]];
191
192 const OutputScalar grad_s0_cross_grad_s1 = s0_dx * s1_dy - s1_dx * s0_dy;
193
194 Polynomials::shiftedScaledLegendreValues(P_i, polyOrder_-1, PointScalar(s1), PointScalar(s0+s1));
195 for (int i=0; i<num1DEdgeFunctions; i++)
196 {
197 output_(i+fieldOrdinalOffset,pointOrdinal) = (i+2) * P_i(i) * grad_s0_cross_grad_s1;
198 }
199 fieldOrdinalOffset += num1DEdgeFunctions;
200 }
201
202 /*
203 Fuentes et al give the face functions as E^f_{ij}, with curl:
204 [L^{2i+1}_j](s0+s1,s2) curl(E^E_i(s0,s1)) + grad[L^(2i+1)_j](s0+s1,s2) \times E^E_i(s0,s1)
205 where:
206 - E^E_i is the ith edge function on the edge s0 to s1
207 - L^{2i+1}_j is an shifted, scaled integrated Jacobi polynomial.
208 - For family 1, s0s1s2 = 012
209 - For family 2, s0s1s2 = 120
210 - Note that grad[L^(2i+1)_j](s0+s1,s2) is computed as [P^{2i+1}_{j-1}](s0+s1,s2) (grad s2) + [R^{2i+1}_{j-1}] grad (s0+s1+s2),
211 but for triangles (s0+s1+s2) is always 1, so that the grad (s0+s1+s2) is 0.
212 - Here,
213 [P^{2i+1}_{j-1}](s0,s1) = P^{2i+1}_{j-1}(s1,s0+s1)
214 and
215 [R^{2i+1}_{j-1}(s0,s1)] = d/dt L^{2i+1}_j(s1,s0+s1)
216 We have implemented P^{alpha}_{j} as shiftedScaledJacobiValues,
217 and d/dt L^{alpha}_{j} as shiftedScaledIntegratedJacobiValues_dt.
218 */
219 // rename the scratch memory to match our usage here:
220 auto & P_2ip1_j = other_values_at_point;
221
222 // following ESEAS, we interleave the face families. This groups all the face dofs of a given degree together.
223 const int faceFieldOrdinalOffset = fieldOrdinalOffset;
224 for (int familyOrdinal=1; familyOrdinal<=2; familyOrdinal++)
225 {
226 int fieldOrdinal = faceFieldOrdinalOffset + familyOrdinal - 1;
227
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; // s0 + s1 + s2
235
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];
242
243 const OutputScalar grad_s0_cross_grad_s1 = s0_dx * s1_dy - s1_dx * s0_dy;
244
245 Polynomials::shiftedScaledLegendreValues (P_i, polyOrder_-1, PointScalar(s1), PointScalar(s0+s1));
246 // [L^{2i+1}_j](s0+s1,s2) curl(E^E_i(s0,s1)) + grad[L^(2i+1)_j](s0+s1,s2) \times E^E_i(s0,s1)
247 // grad[L^(2i+1)_j](s0+s1,s2) \times E^E_i(s0,s1)
248// - Note that grad[L^(2i+1)_j](s0+s1,s2) is computed as [P^{2i+1}_{j-1}](s0+s1,s2) (grad s2) + [R^{2i+1}_{j-1}] grad (s0+s1+s2),
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;
252
253 const int max_ij_sum = polyOrder_ - 1;
254 for (int ij_sum=1; ij_sum <= max_ij_sum; ij_sum++)
255 {
256 for (int i=0; i<ij_sum; i++)
257 {
258 const int j = ij_sum - i; // j >= 1
259 const OutputScalar edgeCurl = (i+2.) * P_i(i) * grad_s0_cross_grad_s1;
260
261 const double alpha = i*2.0 + 1;
262
263 Polynomials::shiftedScaledJacobiValues(P_2ip1_j, alpha, polyOrder_-1, PointScalar(s2), jacobiScaling);
264 Polynomials::shiftedScaledIntegratedJacobiValues(L_2ip1_j, alpha, polyOrder_-1, s2, jacobiScaling);
265
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;
268
269 fieldOrdinal += 2; // 2 because there are two face families, and we interleave them.
270 }
271 }
272 }
273 }
274 break;
275 case OPERATOR_GRAD:
276 case OPERATOR_D1:
277 case OPERATOR_D2:
278 case OPERATOR_D3:
279 case OPERATOR_D4:
280 case OPERATOR_D5:
281 case OPERATOR_D6:
282 case OPERATOR_D7:
283 case OPERATOR_D8:
284 case OPERATOR_D9:
285 case OPERATOR_D10:
286 INTREPID2_TEST_FOR_ABORT( true,
287 ">>> ERROR: (Intrepid2::Hierarchical_HCURL_TRI_Functor) Unsupported differential operator");
288 default:
289 // unsupported operator type
290 device_assert(false);
291 }
292 }
293
294 // Provide the shared memory capacity.
295 // This function takes the team_size as an argument,
296 // which allows team_size-dependent allocations.
297 size_t team_shmem_size (int team_size) const
298 {
299 // we will use shared memory to create a fast buffer for basis computations
300 size_t shmem_size = 0;
301 if (fad_size_output_ > 0)
302 shmem_size += 4 * OutputScratchView::shmem_size(polyOrder_ + 1, fad_size_output_);
303 else
304 shmem_size += 4 * OutputScratchView::shmem_size(polyOrder_ + 1);
305
306 return shmem_size;
307 }
308 };
309
324 template<typename DeviceType,
325 typename OutputScalar = double,
326 typename PointScalar = double,
327 bool useCGBasis = true> // if useCGBasis is false, all basis functions will be associated with the interior
329 : public Basis<DeviceType,OutputScalar,PointScalar>
330 {
331 public:
333
335
338
339 using typename BasisBase::OutputViewType;
340 using typename BasisBase::PointViewType;
341 using typename BasisBase::ScalarViewType;
342
343 using typename BasisBase::ExecutionSpace;
344
345 protected:
346 int polyOrder_; // the maximum order of the polynomial
347 public:
352 HierarchicalBasis_HCURL_TRI(int polyOrder, const EPointType pointType=POINTTYPE_DEFAULT)
353 :
354 polyOrder_(polyOrder)
355 {
356 const int numEdgeFunctions = polyOrder * 3;
357 const int numFaceFunctions = polyOrder * (polyOrder-1); // two families, each with p*(p-1)/2 functions
358 this->basisCardinality_ = numEdgeFunctions + numFaceFunctions;
359 this->basisDegree_ = polyOrder;
360 this->basisCellTopologyKey_ = shards::Triangle<>::key;
361 this->basisType_ = BASIS_FEM_HIERARCHICAL;
362 this->basisCoordinates_ = COORDINATES_CARTESIAN;
363 this->functionSpace_ = FUNCTION_SPACE_HCURL;
364
365 const int degreeLength = 1;
366 this->fieldOrdinalPolynomialDegree_ = OrdinalTypeArray2DHost("Hierarchical H(curl) triangle polynomial degree lookup", this->basisCardinality_, degreeLength);
367 this->fieldOrdinalH1PolynomialDegree_ = OrdinalTypeArray2DHost("Hierarchical H(curl) triangle polynomial H^1 degree lookup", this->basisCardinality_, degreeLength);
368
369 int fieldOrdinalOffset = 0;
370 // **** vertex functions **** //
371 // no vertex functions in H(curl)
372
373 // **** edge functions **** //
374 const shards::CellTopology cellTopo(shards::getCellTopologyData<shards::Triangle<> >());
375 const int numFunctionsPerEdge = polyOrder; // p functions associated with each edge
376 const int numEdges = cellTopo.getEdgeCount();
377 for (int edgeOrdinal=0; edgeOrdinal<numEdges; edgeOrdinal++)
378 {
379 for (int i=0; i<numFunctionsPerEdge; i++)
380 {
381 this->fieldOrdinalPolynomialDegree_(i+fieldOrdinalOffset,0) = i+1; // the multiplicands involving the gradients of the vertex functions are first degree polynomials; hence the +1 (the remaining multiplicands are order i = 0,…,p-1).
382 this->fieldOrdinalH1PolynomialDegree_(i+fieldOrdinalOffset,0) = i+2;
383 }
384 fieldOrdinalOffset += numFunctionsPerEdge;
385 }
386 INTREPID2_TEST_FOR_EXCEPTION(fieldOrdinalOffset != numEdgeFunctions, std::invalid_argument, "Internal error: basis enumeration is incorrect");
387
388 // **** face functions **** //
389 const int max_ij_sum = polyOrder-1;
390 const int faceFieldOrdinalOffset = fieldOrdinalOffset;
391 for (int faceFamilyOrdinal=1; faceFamilyOrdinal<=2; faceFamilyOrdinal++)
392 {
393 // following ESEAS, we interleave the face families. This groups all the face dofs of a given degree together.
394 int fieldOrdinal = faceFieldOrdinalOffset + faceFamilyOrdinal - 1;
395 for (int ij_sum=1; ij_sum <= max_ij_sum; ij_sum++)
396 {
397 for (int i=0; i<ij_sum; i++)
398 {
399 this->fieldOrdinalPolynomialDegree_(fieldOrdinal,0) = ij_sum+1;
400 this->fieldOrdinalH1PolynomialDegree_(fieldOrdinal,0) = ij_sum+2;
401 fieldOrdinal += 2; // 2 because there are two face families, and we interleave them.
402 }
403 }
404 fieldOrdinalOffset = fieldOrdinal - 1; // due to the interleaving increment, we've gone two past the last face ordinal. Set offset to be one past.
405 }
406
407 INTREPID2_TEST_FOR_EXCEPTION(fieldOrdinalOffset != this->basisCardinality_, std::invalid_argument, "Internal error: basis enumeration is incorrect");
408
409 // initialize tags
410 {
411 const auto & cardinality = this->basisCardinality_;
412
413 // Basis-dependent initializations
414 const ordinal_type tagSize = 4; // size of DoF tag, i.e., number of fields in the tag
415 const ordinal_type posScDim = 0; // position in the tag, counting from 0, of the subcell dim
416 const ordinal_type posScOrd = 1; // position in the tag, counting from 0, of the subcell ordinal
417 const ordinal_type posDfOrd = 2; // position in the tag, counting from 0, of DoF ordinal relative to the subcell
418
419 OrdinalTypeArray1DHost tagView("tag view", cardinality*tagSize);
420 const ordinal_type edgeDim = 1, faceDim = 2;
421
422 if (useCGBasis) {
423 {
424 int tagNumber = 0;
425 for (int edgeOrdinal=0; edgeOrdinal<numEdges; edgeOrdinal++)
426 {
427 for (int functionOrdinal=0; functionOrdinal<numFunctionsPerEdge; functionOrdinal++)
428 {
429 tagView(tagNumber*tagSize+0) = edgeDim; // edge dimension
430 tagView(tagNumber*tagSize+1) = edgeOrdinal; // edge id
431 tagView(tagNumber*tagSize+2) = functionOrdinal; // local dof id
432 tagView(tagNumber*tagSize+3) = numFunctionsPerEdge; // total number of dofs on this edge
433 tagNumber++;
434 }
435 }
436 const int numFunctionsPerFace = numFaceFunctions; // just one face in the triangle
437 const int numFaces = 1;
438 for (int faceOrdinal=0; faceOrdinal<numFaces; faceOrdinal++)
439 {
440 for (int functionOrdinal=0; functionOrdinal<numFunctionsPerFace; functionOrdinal++)
441 {
442 tagView(tagNumber*tagSize+0) = faceDim; // face dimension
443 tagView(tagNumber*tagSize+1) = faceOrdinal; // face id
444 tagView(tagNumber*tagSize+2) = functionOrdinal; // local dof id
445 tagView(tagNumber*tagSize+3) = numFunctionsPerFace; // total number of dofs on this face
446 tagNumber++;
447 }
448 }
449 }
450 }
451 else
452 {
453 // DG basis: all functions are associated with interior
454 for (ordinal_type i=0;i<cardinality;++i) {
455 tagView(i*tagSize+0) = faceDim; // face dimension
456 tagView(i*tagSize+1) = 0; // face id
457 tagView(i*tagSize+2) = i; // local dof id
458 tagView(i*tagSize+3) = cardinality; // total number of dofs on this face
459 }
460 }
461
462 // Basis-independent function sets tag and enum data in tagToOrdinal_ and ordinalToTag_ arrays:
463 // tags are constructed on host
465 this->ordinalToTag_,
466 tagView,
467 this->basisCardinality_,
468 tagSize,
469 posScDim,
470 posScOrd,
471 posDfOrd);
472 }
473 }
474
479 const char* getName() const override {
480 return "Intrepid2_HierarchicalBasis_HCURL_TRI";
481 }
482
485 virtual bool requireOrientation() const override {
486 return (this->getDegree() > 2);
487 }
488
489 // since the getValues() below only overrides the FEM variant, we specify that
490 // we use the base class's getValues(), which implements the FVD variant by throwing an exception.
491 // (It's an error to use the FVD variant on this basis.)
493
512 virtual void getValues( OutputViewType outputValues, const PointViewType inputPoints,
513 const EOperator operatorType = OPERATOR_VALUE ) const override
514 {
515 auto numPoints = inputPoints.extent_int(0);
516
518
519 FunctorType functor(operatorType, outputValues, inputPoints, polyOrder_);
520
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; // because of the way the basis functions are computed, we don't have a second level of parallelism...
525
526 auto policy = Kokkos::TeamPolicy<ExecutionSpace>(numPoints,teamSize,vectorSize);
527 Kokkos::parallel_for("Hierarchical_HCURL_TRI_Functor", policy, functor);
528 }
529
539 getSubCellRefBasis(const ordinal_type subCellDim, const ordinal_type subCellOrd) const override{
540 if(subCellDim == 1) {
541 return Teuchos::rcp(new
543 (this->basisDegree_-1));
544 }
545 INTREPID2_TEST_FOR_EXCEPTION(true,std::invalid_argument,"Input parameters out of bounds");
546 }
547
553 getHostBasis() const override {
554 using HostDeviceType = typename Kokkos::HostSpace::device_type;
556 return Teuchos::rcp( new HostBasisType(polyOrder_) );
557 }
558 };
559} // end namespace Intrepid2
560
561#endif /* Intrepid2_HierarchicalBasis_HCURL_TRI_h */
Header file for the abstract base class Intrepid2::Basis.
Teuchos::RCP< Basis< DeviceType, OutputType, PointType > > BasisPtr
Basis Pointer.
KOKKOS_INLINE_FUNCTION void device_assert(bool val)
H(grad) basis on the line based on integrated Legendre polynomials.
Free functions, callable from device code, that implement various polynomials useful in basis definit...
Header function for Intrepid2::Util class and other utility functions.
KOKKOS_INLINE_FUNCTION constexpr unsigned getScalarDimensionForView(const ViewType &view)
Returns the size of the Scalar dimension for the View. This is 0 for non-AD types....
An abstract base class that defines interface for concrete basis implementations for Finite Element (...
ECoordinates basisCoordinates_
The coordinate system for which the basis is defined.
Kokkos::DynRankView< PointValueType, Kokkos::LayoutStride, DeviceType > PointViewType
View type for input points.
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.
Kokkos::DynRankView< OutputValueType, Kokkos::LayoutStride, DeviceType > OutputViewType
View type for basis value output.
EBasis basisType_
Type of the basis.
ordinal_type basisDegree_
Degree of the largest complete polynomial space that can be represented by the basis.
ordinal_type getDegree() const
Returns the degree of the basis.
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< scalarType, Kokkos::LayoutStride, DeviceType > ScalarViewType
View type for scalars.
OrdinalTypeArray2DHost ordinalToTag_
"true" if tagToOrdinal_ and ordinalToTag_ have been initialized
OrdinalTypeArray2DHost fieldOrdinalH1PolynomialDegree_
H^1 polynomial degree for each degree of freedom. Only defined for hierarchical bases right now....
Kokkos::View< ordinal_type **, typename ExecutionSpace::array_layout, Kokkos::HostSpace > OrdinalTypeArray2DHost
View type for 2d host array.
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.
Kokkos::View< ordinal_type *, typename ExecutionSpace::array_layout, Kokkos::HostSpace > OrdinalTypeArray1DHost
View type for 1d host array.
unsigned basisCellTopologyKey_
Identifier of the base topology of the cells for which the basis is defined. See the Shards package f...
typename DeviceType::execution_space ExecutionSpace
(Kokkos) Execution space for basis.
OrdinalTypeArray2DHost fieldOrdinalPolynomialDegree_
Polynomial degree for each degree of freedom. Only defined for hierarchical bases right now....
EFunctionSpace functionSpace_
The function space in which the basis is defined.
For mathematical details of the construction, see:
Kokkos::DynRankView< PointValueType, Kokkos::LayoutStride, DeviceType > PointViewType
View type for input points.
Kokkos::DynRankView< OutputValueType, Kokkos::LayoutStride, DeviceType > OutputViewType
View type for basis value output.
virtual void getValues(OutputViewType outputValues, const PointViewType inputPoints, const EOperator operatorType=OPERATOR_VALUE) const override
Evaluation of a FEM basis on a reference cell.
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...
const char * getName() const override
Returns basis name.
Kokkos::View< ordinal_type **, typename ExecutionSpace::array_layout, Kokkos::HostSpace > OrdinalTypeArray2DHost
View type for 2d host array.
HierarchicalBasis_HCURL_TRI(int polyOrder, const EPointType pointType=POINTTYPE_DEFAULT)
Constructor.
virtual bool requireOrientation() const override
True if orientation is required.
Kokkos::View< ordinal_type *, typename ExecutionSpace::array_layout, Kokkos::HostSpace > OrdinalTypeArray1DHost
View type for 1d host array.
Basis defining Legendre basis on the line, a polynomial subspace of L^2 (a.k.a. H(vol)) on the line.
Functor for computing values for the HierarchicalBasis_HCURL_TRI class.