15 #ifndef Intrepid2_HierarchicalBasis_HCURL_TET_h
16 #define Intrepid2_HierarchicalBasis_HCURL_TET_h
18 #include <Intrepid2_config.h>
20 #include <Kokkos_DynRankView.hpp>
35 template<
class DeviceType,
class OutputScalar,
class PointScalar,
36 class OutputFieldType,
class InputPointsType>
39 using ExecutionSpace =
typename DeviceType::execution_space;
40 using ScratchSpace =
typename ExecutionSpace::scratch_memory_space;
41 using OutputScratchView = Kokkos::View<OutputScalar*,ScratchSpace,Kokkos::MemoryTraits<Kokkos::Unmanaged>>;
42 using PointScratchView = Kokkos::View<PointScalar*, ScratchSpace,Kokkos::MemoryTraits<Kokkos::Unmanaged>>;
44 using TeamPolicy = Kokkos::TeamPolicy<ExecutionSpace>;
45 using TeamMember =
typename TeamPolicy::member_type;
49 OutputFieldType output_;
50 InputPointsType inputPoints_;
52 ordinal_type polyOrder_;
53 ordinal_type numFields_, numPoints_;
55 size_t fad_size_output_;
57 static constexpr ordinal_type numVertices = 4;
58 static constexpr ordinal_type numEdges = 6;
59 static constexpr ordinal_type numEdgesPerFace = 3;
60 static constexpr ordinal_type numFaceFamilies = 2;
61 static constexpr ordinal_type numFaces = 4;
62 static constexpr ordinal_type numVerticesPerFace = 3;
63 static constexpr ordinal_type numInteriorFamilies = 3;
66 const ordinal_type face_vertices[numFaces*numVerticesPerFace] = {0,1,2,
75 const ordinal_type face_edges[numFaces * numEdgesPerFace] = {0,1,2,
81 const ordinal_type edge_start_[numEdges] = {0,1,0,0,1,2};
82 const ordinal_type edge_end_[numEdges] = {1,2,2,3,3,3};
83 const ordinal_type face_family_start_ [numFaceFamilies] = {0,1};
84 const ordinal_type face_family_middle_[numFaceFamilies] = {1,2};
85 const ordinal_type face_family_end_ [numFaceFamilies] = {2,0};
87 const ordinal_type numEdgeFunctions_;
88 const ordinal_type numFaceFunctionsPerFace_;
89 const ordinal_type numFaceFunctions_;
90 const ordinal_type numInteriorFunctionsPerFamily_;
91 const ordinal_type numInteriorFunctions_;
94 const ordinal_type faceOrdinalForInterior_[numInteriorFamilies] = {0,2,3};
95 const ordinal_type faceFamilyForInterior_[numInteriorFamilies] = {0,0,1};
96 const ordinal_type interiorCoordinateOrdinal_[numInteriorFamilies] = {3,0,1};
98 KOKKOS_INLINE_FUNCTION
99 ordinal_type dofOrdinalForFace(
const ordinal_type &faceOrdinal,
100 const ordinal_type &zeroBasedFaceFamily,
101 const ordinal_type &i,
102 const ordinal_type &j)
const
105 const ordinal_type faceDofOffset = numEdgeFunctions_ + faceOrdinal * numFaceFunctionsPerFace_;
111 const ordinal_type max_ij_sum = polyOrder_ - 1;
113 ordinal_type fieldOrdinal = faceDofOffset + zeroBasedFaceFamily;
115 for (ordinal_type ij_sum=1; ij_sum <= max_ij_sum; ij_sum++)
117 for (ordinal_type ii=0; ii<ij_sum; ii++)
120 const ordinal_type jj = ij_sum - ii;
121 if ( (ii == i) && (jj == j))
126 fieldOrdinal += numFaceFamilies;
133 : opType_(opType), output_(output), inputPoints_(inputPoints),
134 polyOrder_(polyOrder),
135 fad_size_output_(getScalarDimensionForView(output)),
136 numEdgeFunctions_(polyOrder * numEdges),
137 numFaceFunctionsPerFace_(polyOrder * (polyOrder-1)),
138 numFaceFunctions_(numFaceFunctionsPerFace_*numFaces),
139 numInteriorFunctionsPerFamily_((polyOrder > 2) ? (polyOrder-2)*(polyOrder-1)*polyOrder/6 : 0),
140 numInteriorFunctions_(numInteriorFunctionsPerFamily_ * numInteriorFamilies)
142 numFields_ = output.extent_int(0);
143 numPoints_ = output.extent_int(1);
145 const ordinal_type expectedCardinality = numEdgeFunctions_ + numFaceFunctions_ + numInteriorFunctions_;
151 INTREPID2_TEST_FOR_EXCEPTION(numPoints_ != inputPoints.extent_int(0), std::invalid_argument,
"point counts need to match!");
152 INTREPID2_TEST_FOR_EXCEPTION(numFields_ != expectedCardinality, std::invalid_argument,
"output field size does not match basis cardinality");
155 KOKKOS_INLINE_FUNCTION
156 void computeEdgeLegendre(OutputScratchView &P,
157 const ordinal_type &edgeOrdinal,
158 const PointScalar* lambda)
const
160 const auto & s0 = lambda[edge_start_[edgeOrdinal]];
161 const auto & s1 = lambda[ edge_end_[edgeOrdinal]];
163 Polynomials::shiftedScaledLegendreValues(P, polyOrder_-1, PointScalar(s1), PointScalar(s0+s1));
166 KOKKOS_INLINE_FUNCTION
167 void edgeFunctionValue(OutputScalar &edgeValue_x,
168 OutputScalar &edgeValue_y,
169 OutputScalar &edgeValue_z,
170 const ordinal_type &edgeOrdinal,
171 OutputScratchView &P,
172 const ordinal_type &i,
173 const PointScalar* lambda,
174 const PointScalar* lambda_dx,
175 const PointScalar* lambda_dy,
176 const PointScalar* lambda_dz
179 const auto & s0 = lambda [edge_start_[edgeOrdinal]];
180 const auto & s0_dx = lambda_dx[edge_start_[edgeOrdinal]];
181 const auto & s0_dy = lambda_dy[edge_start_[edgeOrdinal]];
182 const auto & s0_dz = lambda_dz[edge_start_[edgeOrdinal]];
184 const auto & s1 = lambda [ edge_end_[edgeOrdinal]];
185 const auto & s1_dx = lambda_dx[ edge_end_[edgeOrdinal]];
186 const auto & s1_dy = lambda_dy[ edge_end_[edgeOrdinal]];
187 const auto & s1_dz = lambda_dz[ edge_end_[edgeOrdinal]];
189 const auto & P_i = P(i);
190 const PointScalar xWeight = s0 * s1_dx - s1 * s0_dx;
191 const PointScalar yWeight = s0 * s1_dy - s1 * s0_dy;
192 const PointScalar zWeight = s0 * s1_dz - s1 * s0_dz;
193 edgeValue_x = P_i * xWeight;
194 edgeValue_y = P_i * yWeight;
195 edgeValue_z = P_i * zWeight;
198 KOKKOS_INLINE_FUNCTION
199 void computeFaceIntegratedJacobi(OutputScratchView &L_2ip1,
200 const ordinal_type &zeroBasedFaceOrdinal,
201 const ordinal_type &zeroBasedFamilyOrdinal,
202 const ordinal_type &i,
203 const PointScalar* lambda)
const
205 const auto &s0_vertex_number = face_family_start_ [zeroBasedFamilyOrdinal];
206 const auto &s1_vertex_number = face_family_middle_[zeroBasedFamilyOrdinal];
207 const auto &s2_vertex_number = face_family_end_ [zeroBasedFamilyOrdinal];
210 const auto &s0_index = face_vertices[zeroBasedFaceOrdinal * numVerticesPerFace + s0_vertex_number];
211 const auto &s1_index = face_vertices[zeroBasedFaceOrdinal * numVerticesPerFace + s1_vertex_number];
212 const auto &s2_index = face_vertices[zeroBasedFaceOrdinal * numVerticesPerFace + s2_vertex_number];
214 const auto & s0 = lambda[s0_index];
215 const auto & s1 = lambda[s1_index];
216 const auto & s2 = lambda[s2_index];
217 const PointScalar jacobiScaling = s0 + s1 + s2;
219 const double alpha = i*2.0 + 1;
220 Polynomials::shiftedScaledIntegratedJacobiValues(L_2ip1, alpha, polyOrder_-1, s2, jacobiScaling);
223 KOKKOS_INLINE_FUNCTION
224 void faceFunctionValue(OutputScalar &value_x,
225 OutputScalar &value_y,
226 OutputScalar &value_z,
227 const ordinal_type &j,
228 const OutputScratchView &L_2ip1,
229 const OutputScalar &edgeValue_x,
230 const OutputScalar &edgeValue_y,
231 const OutputScalar &edgeValue_z,
232 const PointScalar* lambda)
const
234 const auto & L_2ip1_j = L_2ip1(j);
235 value_x = edgeValue_x * L_2ip1_j;
236 value_y = edgeValue_y * L_2ip1_j;
237 value_z = edgeValue_z * L_2ip1_j;
240 KOKKOS_INLINE_FUNCTION
241 void operator()(
const TeamMember & teamMember )
const
243 const ordinal_type numFunctionsPerFace = polyOrder_ * (polyOrder_ - 1);
244 auto pointOrdinal = teamMember.league_rank();
245 OutputScratchView edge_field_values_at_point, jacobi_values_at_point, other_values_at_point, other_values2_at_point;
246 if (fad_size_output_ > 0) {
247 edge_field_values_at_point = OutputScratchView(teamMember.team_shmem(), polyOrder_, fad_size_output_);
248 jacobi_values_at_point = OutputScratchView(teamMember.team_shmem(), polyOrder_, fad_size_output_);
249 other_values_at_point = OutputScratchView(teamMember.team_shmem(), polyOrder_, fad_size_output_);
250 other_values2_at_point = OutputScratchView(teamMember.team_shmem(), polyOrder_, fad_size_output_);
253 edge_field_values_at_point = OutputScratchView(teamMember.team_shmem(), polyOrder_);
254 jacobi_values_at_point = OutputScratchView(teamMember.team_shmem(), polyOrder_);
255 other_values_at_point = OutputScratchView(teamMember.team_shmem(), polyOrder_);
256 other_values2_at_point = OutputScratchView(teamMember.team_shmem(), polyOrder_);
259 const auto & x = inputPoints_(pointOrdinal,0);
260 const auto & y = inputPoints_(pointOrdinal,1);
261 const auto & z = inputPoints_(pointOrdinal,2);
264 const PointScalar lambda[4] = {1. - x - y - z, x, y, z};
265 const PointScalar lambda_dx[4] = {-1., 1., 0., 0.};
266 const PointScalar lambda_dy[4] = {-1., 0., 1., 0.};
267 const PointScalar lambda_dz[4] = {-1., 0., 0., 1.};
269 const int num1DEdgeFunctions = polyOrder_;
278 auto & P = edge_field_values_at_point;
280 int fieldOrdinalOffset = 0;
281 for (
int edgeOrdinal=0; edgeOrdinal<numEdges; edgeOrdinal++)
283 computeEdgeLegendre(P, edgeOrdinal, lambda);
285 for (
int i=0; i<num1DEdgeFunctions; i++)
287 auto &output_x = output_(i+fieldOrdinalOffset,pointOrdinal,0);
288 auto &output_y = output_(i+fieldOrdinalOffset,pointOrdinal,1);
289 auto &output_z = output_(i+fieldOrdinalOffset,pointOrdinal,2);
291 edgeFunctionValue(output_x, output_y, output_z,
293 lambda, lambda_dx, lambda_dy, lambda_dz);
295 fieldOrdinalOffset += num1DEdgeFunctions;
301 auto & L_2ip1 = jacobi_values_at_point;
304 const int max_ij_sum = polyOrder_ - 1;
307 int faceFieldOrdinalOffset = fieldOrdinalOffset;
308 for (
int faceOrdinal = 0; faceOrdinal < numFaces; faceOrdinal++) {
309 for (
int familyOrdinal=1; familyOrdinal<=numFaceFamilies; familyOrdinal++)
311 int fieldOrdinal = faceFieldOrdinalOffset + familyOrdinal - 1;
313 for (
int ij_sum=1; ij_sum <= max_ij_sum; ij_sum++)
315 for (
int i=0; i<ij_sum; i++)
317 computeFaceIntegratedJacobi(L_2ip1, faceOrdinal, familyOrdinal-1, i, lambda);
319 const int j = ij_sum - i;
321 const int faceEdgeOrdinal = familyOrdinal-1;
322 const int volumeEdgeOrdinal = face_edges[faceOrdinal * numEdgesPerFace + faceEdgeOrdinal];
323 const int edgeBasisOrdinal = i + volumeEdgeOrdinal*num1DEdgeFunctions;
324 const auto & edgeValue_x = output_(edgeBasisOrdinal,pointOrdinal,0);
325 const auto & edgeValue_y = output_(edgeBasisOrdinal,pointOrdinal,1);
326 const auto & edgeValue_z = output_(edgeBasisOrdinal,pointOrdinal,2);
328 auto & output_x = output_(fieldOrdinal,pointOrdinal,0);
329 auto & output_y = output_(fieldOrdinal,pointOrdinal,1);
330 auto & output_z = output_(fieldOrdinal,pointOrdinal,2);
332 faceFunctionValue(output_x, output_y, output_z, j, L_2ip1, edgeValue_x, edgeValue_y, edgeValue_z, lambda);
334 fieldOrdinal += numFaceFamilies;
337 fieldOrdinalOffset = fieldOrdinal - numFaceFamilies + 1;
339 faceFieldOrdinalOffset += numFunctionsPerFace;
345 const int interiorFieldOrdinalOffset = fieldOrdinalOffset;
346 const int min_ijk_sum = 2;
347 const int max_ijk_sum = polyOrder_-1;
350 const auto & L_2ipj = jacobi_values_at_point;
351 for (
int interiorFamilyOrdinal=1; interiorFamilyOrdinal<=numInteriorFamilies; interiorFamilyOrdinal++)
356 const auto & lambda_m = lambda[interiorCoordinateOrdinal_[interiorFamilyOrdinal-1]];
357 const PointScalar jacobiScaling = 1.0;
359 ordinal_type fieldOrdinal = interiorFieldOrdinalOffset + interiorFamilyOrdinal - 1;
361 const ordinal_type relatedFaceOrdinal = faceOrdinalForInterior_[interiorFamilyOrdinal-1];
362 const ordinal_type relatedFaceFamily = faceFamilyForInterior_ [interiorFamilyOrdinal-1];
364 for (
int ijk_sum=min_ijk_sum; ijk_sum <= max_ijk_sum; ijk_sum++)
366 for (
int i=0; i<ijk_sum-1; i++)
368 for (
int j=1; j<ijk_sum-i; j++)
371 const ordinal_type faceDofOrdinal = dofOrdinalForFace(relatedFaceOrdinal, relatedFaceFamily, i, j);
373 const double alpha = 2 * (i + j);
375 Polynomials::shiftedScaledIntegratedJacobiValues(L_2ipj, alpha, polyOrder_-1, lambda_m, jacobiScaling);
377 const int k = ijk_sum - i - j;
378 const auto & L_k = L_2ipj(k);
379 for (
int d=0; d<3; d++)
381 const auto & E_face_d = output_(faceDofOrdinal,pointOrdinal,d);
382 output_(fieldOrdinal,pointOrdinal,d) = L_k * E_face_d;
384 fieldOrdinal += numInteriorFamilies;
388 fieldOrdinalOffset = fieldOrdinal - numInteriorFamilies + 1;
397 int fieldOrdinalOffset = 0;
404 auto & P_i = edge_field_values_at_point;
405 auto & L_2ip1_j = jacobi_values_at_point;
406 for (
int edgeOrdinal=0; edgeOrdinal<numEdges; edgeOrdinal++)
408 const auto & s0 = lambda[edge_start_[edgeOrdinal]];
409 const auto & s1 = lambda[ edge_end_[edgeOrdinal]];
411 const auto & s0_dx = lambda_dx[edge_start_[edgeOrdinal]];
412 const auto & s0_dy = lambda_dy[edge_start_[edgeOrdinal]];
413 const auto & s0_dz = lambda_dz[edge_start_[edgeOrdinal]];
414 const auto & s1_dx = lambda_dx[ edge_end_[edgeOrdinal]];
415 const auto & s1_dy = lambda_dy[ edge_end_[edgeOrdinal]];
416 const auto & s1_dz = lambda_dz[ edge_end_[edgeOrdinal]];
418 const OutputScalar grad_s0_cross_grad_s1[3] = {s0_dy * s1_dz - s0_dz * s1_dy,
419 s0_dz * s1_dx - s0_dx * s1_dz,
420 s0_dx * s1_dy - s0_dy * s1_dx};
422 Polynomials::shiftedScaledLegendreValues(P_i, polyOrder_-1, PointScalar(s1), PointScalar(s0+s1));
423 for (
int i=0; i<num1DEdgeFunctions; i++)
425 for (
int d=0; d<3; d++)
427 output_(i+fieldOrdinalOffset,pointOrdinal,d) = (i+2) * P_i(i) * grad_s0_cross_grad_s1[d];
430 fieldOrdinalOffset += num1DEdgeFunctions;
451 auto & P_2ip1_j = other_values_at_point;
452 auto & L_2ip1_j_dt = other_values2_at_point;
455 int faceFieldOrdinalOffset = fieldOrdinalOffset;
456 for (
int faceOrdinal=0; faceOrdinal<numFaces; faceOrdinal++)
458 for (
int familyOrdinal=1; familyOrdinal<=numFaceFamilies; familyOrdinal++)
460 int fieldOrdinal = faceFieldOrdinalOffset + familyOrdinal - 1;
462 const auto &s0_vertex_number = face_family_start_ [familyOrdinal-1];
463 const auto &s1_vertex_number = face_family_middle_[familyOrdinal-1];
464 const auto &s2_vertex_number = face_family_end_ [familyOrdinal-1];
467 const auto &s0_index = face_vertices[faceOrdinal * numVerticesPerFace + s0_vertex_number];
468 const auto &s1_index = face_vertices[faceOrdinal * numVerticesPerFace + s1_vertex_number];
469 const auto &s2_index = face_vertices[faceOrdinal * numVerticesPerFace + s2_vertex_number];
471 const auto & s0 = lambda[s0_index];
472 const auto & s1 = lambda[s1_index];
473 const auto & s2 = lambda[s2_index];
474 const PointScalar jacobiScaling = s0 + s1 + s2;
476 const auto & s0_dx = lambda_dx[s0_index];
477 const auto & s0_dy = lambda_dy[s0_index];
478 const auto & s0_dz = lambda_dz[s0_index];
479 const auto & s1_dx = lambda_dx[s1_index];
480 const auto & s1_dy = lambda_dy[s1_index];
481 const auto & s1_dz = lambda_dz[s1_index];
482 const auto & s2_dx = lambda_dx[s2_index];
483 const auto & s2_dy = lambda_dy[s2_index];
484 const auto & s2_dz = lambda_dz[s2_index];
486 const PointScalar grad_s2[3] = {s2_dx, s2_dy, s2_dz};
487 const PointScalar gradJacobiScaling[3] = {s0_dx + s1_dx + s2_dx,
488 s0_dy + s1_dy + s2_dy,
489 s0_dz + s1_dz + s2_dz};
491 const PointScalar grad_s0_cross_grad_s1[3] = {s0_dy * s1_dz - s0_dz * s1_dy,
492 s0_dz * s1_dx - s0_dx * s1_dz,
493 s0_dx * s1_dy - s0_dy * s1_dx};
495 const PointScalar s0_grad_s1_minus_s1_grad_s0[3] = {s0 * s1_dx - s1 * s0_dx,
496 s0 * s1_dy - s1 * s0_dy,
497 s0 * s1_dz - s1 * s0_dz};
499 Polynomials::shiftedScaledLegendreValues (P_i, polyOrder_-1, PointScalar(s1), PointScalar(s0+s1));
506 const int max_ij_sum = polyOrder_ - 1;
507 for (
int ij_sum=1; ij_sum <= max_ij_sum; ij_sum++)
509 for (
int i=0; i<ij_sum; i++)
511 const int j = ij_sum - i;
513 const double alpha = i*2.0 + 1;
515 Polynomials::shiftedScaledJacobiValues (P_2ip1_j, alpha, polyOrder_-1, PointScalar(s2), jacobiScaling);
516 Polynomials::shiftedScaledIntegratedJacobiValues (L_2ip1_j, alpha, polyOrder_-1, PointScalar(s2), jacobiScaling);
517 Polynomials::shiftedScaledIntegratedJacobiValues_dt(L_2ip1_j_dt, alpha, polyOrder_-1, PointScalar(s2), jacobiScaling);
519 const PointScalar & edgeValue = P_i(i);
521 PointScalar grad_L_2ip1_j[3];
522 for (
int d=0; d<3; d++)
524 grad_L_2ip1_j[d] = P_2ip1_j(j-1) * grad_s2[d]
525 + L_2ip1_j_dt(j) * gradJacobiScaling[d];
528 const PointScalar grad_L_2ip1_j_cross_E_i[3] = { grad_L_2ip1_j[1] * edgeValue * s0_grad_s1_minus_s1_grad_s0[2] - grad_L_2ip1_j[2] * edgeValue * s0_grad_s1_minus_s1_grad_s0[1],
529 grad_L_2ip1_j[2] * edgeValue * s0_grad_s1_minus_s1_grad_s0[0] - grad_L_2ip1_j[0] * edgeValue * s0_grad_s1_minus_s1_grad_s0[2],
530 grad_L_2ip1_j[0] * edgeValue * s0_grad_s1_minus_s1_grad_s0[1] - grad_L_2ip1_j[1] * edgeValue * s0_grad_s1_minus_s1_grad_s0[0] };
532 for (
int d=0; d<3; d++)
534 const OutputScalar edgeCurl_d = (i+2.) * P_i(i) * grad_s0_cross_grad_s1[d];
535 output_(fieldOrdinal,pointOrdinal,d) = L_2ip1_j(j) * edgeCurl_d
536 + grad_L_2ip1_j_cross_E_i[d];
539 fieldOrdinal += numFaceFamilies;
542 fieldOrdinalOffset = fieldOrdinal - numFaceFamilies + 1;
544 faceFieldOrdinalOffset += numFunctionsPerFace;
550 auto & L_2ipj = jacobi_values_at_point;
551 auto & P_2ipj = other_values_at_point;
552 auto & L_2ip1 = edge_field_values_at_point;
553 auto & P = other_values2_at_point;
555 const int interiorFieldOrdinalOffset = fieldOrdinalOffset;
556 const int min_ijk_sum = 2;
557 const int max_ijk_sum = polyOrder_-1;
558 for (
int interiorFamilyOrdinal=1; interiorFamilyOrdinal<=numInteriorFamilies; interiorFamilyOrdinal++)
562 const ordinal_type relatedFaceOrdinal = faceOrdinalForInterior_[interiorFamilyOrdinal-1];
563 const ordinal_type relatedFaceFamily = faceFamilyForInterior_ [interiorFamilyOrdinal-1];
566 const auto & m = interiorCoordinateOrdinal_[interiorFamilyOrdinal-1];
567 const auto & lambda_m = lambda[m];
568 const PointScalar jacobiScaling = 1.0;
570 ordinal_type fieldOrdinal = interiorFieldOrdinalOffset + interiorFamilyOrdinal - 1;
572 for (
int ijk_sum=min_ijk_sum; ijk_sum <= max_ijk_sum; ijk_sum++)
574 for (
int i=0; i<ijk_sum-1; i++)
576 computeFaceIntegratedJacobi(L_2ip1, relatedFaceOrdinal, relatedFaceFamily, i, lambda);
578 const ordinal_type faceEdgeOrdinal = relatedFaceFamily;
579 const int volumeEdgeOrdinal = face_edges[relatedFaceOrdinal * numEdgesPerFace + faceEdgeOrdinal];
580 computeEdgeLegendre(P, volumeEdgeOrdinal, lambda);
582 OutputScalar edgeValue[3];
583 edgeFunctionValue(edgeValue[0], edgeValue[1], edgeValue[2], volumeEdgeOrdinal, P, i, lambda, lambda_dx, lambda_dy, lambda_dz);
585 for (
int j=1; j<ijk_sum-i; j++)
588 const ordinal_type faceDofOrdinal = dofOrdinalForFace(relatedFaceOrdinal, relatedFaceFamily, i, j);
590 const double alpha = 2 * (i + j);
592 Polynomials::shiftedScaledIntegratedJacobiValues(L_2ipj, alpha, polyOrder_-1, lambda_m, jacobiScaling);
593 Polynomials::shiftedScaledJacobiValues (P_2ipj, alpha, polyOrder_-1, lambda_m, jacobiScaling);
598 const int k = ijk_sum - i - j;
599 const auto & L_k = L_2ipj(k);
600 const auto & P_km1 = P_2ipj(k-1);
602 const PointScalar grad_L_k[3] = {P_km1 * lambda_dx[m],
603 P_km1 * lambda_dy[m],
604 P_km1 * lambda_dz[m]};
607 OutputScalar E_face[3];
608 faceFunctionValue(E_face[0], E_face[1], E_face[2], j, L_2ip1, edgeValue[0], edgeValue[1], edgeValue[2], lambda);
610 PointScalar grad_L_k_cross_E_face[3] = {grad_L_k[1] * E_face[2] - grad_L_k[2] * E_face[1],
611 grad_L_k[2] * E_face[0] - grad_L_k[0] * E_face[2],
612 grad_L_k[0] * E_face[1] - grad_L_k[1] * E_face[0]};
613 for (
int d=0; d<3; d++)
615 const auto & curl_E_face_d = output_(faceDofOrdinal,pointOrdinal,d);
616 output_(fieldOrdinal,pointOrdinal,d) = L_k * curl_E_face_d + grad_L_k_cross_E_face[d];
619 fieldOrdinal += numInteriorFamilies;
623 fieldOrdinalOffset = fieldOrdinal - numInteriorFamilies + 1;
639 INTREPID2_TEST_FOR_ABORT(
true,
640 ">>> ERROR: (Intrepid2::Hierarchical_HCURL_TET_Functor) Unsupported differential operator");
643 device_assert(
false);
650 size_t team_shmem_size (
int team_size)
const
653 size_t shmem_size = 0;
654 if (fad_size_output_ > 0)
655 shmem_size += 4 * OutputScratchView::shmem_size(polyOrder_ + 1, fad_size_output_);
657 shmem_size += 4 * OutputScratchView::shmem_size(polyOrder_ + 1);
677 template<
typename DeviceType,
678 typename OutputScalar = double,
679 typename PointScalar = double,
680 bool useCGBasis =
true>
682 :
public Basis<DeviceType,OutputScalar,PointScalar>
705 polyOrder_(polyOrder)
708 const shards::CellTopology cellTopo(shards::getCellTopologyData<shards::Tetrahedron<>>());
709 const int numEdges = cellTopo.getEdgeCount();
710 const int numFaces = cellTopo.getFaceCount();
712 const int numEdgeFunctions = polyOrder * numEdges;
713 const int numFaceFunctions = polyOrder * (polyOrder-1) * numFaces;
714 const int numInteriorFunctionsPerFamily = (polyOrder > 2) ? (polyOrder-2)*(polyOrder-1)*polyOrder/6 : 0;
715 const int numInteriorFunctions = numInteriorFunctionsPerFamily * 3;
716 this->
basisCardinality_ = numEdgeFunctions + numFaceFunctions + numInteriorFunctions;
723 const int degreeLength = 1;
726 int fieldOrdinalOffset = 0;
731 const int numFunctionsPerEdge = polyOrder;
732 for (
int edgeOrdinal=0; edgeOrdinal<numEdges; edgeOrdinal++)
734 for (
int i=0; i<numFunctionsPerEdge; i++)
738 fieldOrdinalOffset += numFunctionsPerEdge;
740 INTREPID2_TEST_FOR_EXCEPTION(fieldOrdinalOffset != numEdgeFunctions, std::invalid_argument,
"Internal error: basis enumeration is incorrect");
743 const int max_ij_sum = polyOrder-1;
744 int faceFieldOrdinalOffset = fieldOrdinalOffset;
745 const int numFaceFamilies = 2;
746 for (
int faceOrdinal=0; faceOrdinal<numFaces; faceOrdinal++)
748 for (
int faceFamilyOrdinal=1; faceFamilyOrdinal<=numFaceFamilies; faceFamilyOrdinal++)
751 int fieldOrdinal = faceFieldOrdinalOffset + faceFamilyOrdinal - 1;
752 for (
int ij_sum=1; ij_sum <= max_ij_sum; ij_sum++)
754 for (
int i=0; i<ij_sum; i++)
757 fieldOrdinal += numFaceFamilies;
760 fieldOrdinalOffset = fieldOrdinal - numFaceFamilies + 1;
762 faceFieldOrdinalOffset += numFaceFunctions / numFaces;
764 INTREPID2_TEST_FOR_EXCEPTION(fieldOrdinalOffset != numEdgeFunctions + numFaceFunctions, std::invalid_argument,
"Internal error: basis enumeration is incorrect");
766 const int numInteriorFamilies = 3;
767 const int interiorFieldOrdinalOffset = fieldOrdinalOffset;
768 const int min_ijk_sum = 2;
769 const int max_ijk_sum = polyOrder-1;
770 for (
int interiorFamilyOrdinal=1; interiorFamilyOrdinal<=numInteriorFamilies; interiorFamilyOrdinal++)
773 int fieldOrdinal = interiorFieldOrdinalOffset + interiorFamilyOrdinal - 1;
774 for (
int ijk_sum=min_ijk_sum; ijk_sum <= max_ijk_sum; ijk_sum++)
776 for (
int i=0; i<ijk_sum-1; i++)
778 for (
int j=1; j<ijk_sum-i; j++)
781 fieldOrdinal += numInteriorFamilies;
785 fieldOrdinalOffset = fieldOrdinal - numInteriorFamilies + 1;
788 INTREPID2_TEST_FOR_EXCEPTION(fieldOrdinalOffset != this->
basisCardinality_, std::invalid_argument,
"Internal error: basis enumeration is incorrect");
795 const int intrepid2FaceOrdinals[4] {3,0,1,2};
800 const ordinal_type tagSize = 4;
801 const ordinal_type posScDim = 0;
802 const ordinal_type posScOrd = 1;
803 const ordinal_type posDfOrd = 2;
806 const ordinal_type edgeDim = 1, faceDim = 2, volumeDim = 3;
811 for (
int edgeOrdinal=0; edgeOrdinal<numEdges; edgeOrdinal++)
813 for (
int functionOrdinal=0; functionOrdinal<numFunctionsPerEdge; functionOrdinal++)
815 tagView(tagNumber*tagSize+0) = edgeDim;
816 tagView(tagNumber*tagSize+1) = edgeOrdinal;
817 tagView(tagNumber*tagSize+2) = functionOrdinal;
818 tagView(tagNumber*tagSize+3) = numFunctionsPerEdge;
822 const int numFunctionsPerFace = numFaceFunctions / numFaces;
823 for (
int faceOrdinalESEAS=0; faceOrdinalESEAS<numFaces; faceOrdinalESEAS++)
825 int faceOrdinalIntrepid2 = intrepid2FaceOrdinals[faceOrdinalESEAS];
826 for (
int functionOrdinal=0; functionOrdinal<numFunctionsPerFace; functionOrdinal++)
828 tagView(tagNumber*tagSize+0) = faceDim;
829 tagView(tagNumber*tagSize+1) = faceOrdinalIntrepid2;
830 tagView(tagNumber*tagSize+2) = functionOrdinal;
831 tagView(tagNumber*tagSize+3) = numFunctionsPerFace;
837 for (
int functionOrdinal=0; functionOrdinal<numInteriorFunctions; functionOrdinal++)
839 tagView(tagNumber*tagSize+0) = volumeDim;
840 tagView(tagNumber*tagSize+1) = 0;
841 tagView(tagNumber*tagSize+2) = functionOrdinal;
842 tagView(tagNumber*tagSize+3) = numInteriorFunctions;
850 for (ordinal_type i=0;i<cardinality;++i) {
851 tagView(i*tagSize+0) = volumeDim;
852 tagView(i*tagSize+1) = 0;
853 tagView(i*tagSize+2) = i;
854 tagView(i*tagSize+3) = cardinality;
876 return "Intrepid2_HierarchicalBasis_HCURL_TET";
909 const EOperator operatorType = OPERATOR_VALUE )
const override
911 auto numPoints = inputPoints.extent_int(0);
915 FunctorType functor(operatorType, outputValues, inputPoints, polyOrder_);
917 const int outputVectorSize = getVectorSizeForHierarchicalParallelism<OutputScalar>();
918 const int pointVectorSize = getVectorSizeForHierarchicalParallelism<PointScalar>();
919 const int vectorSize = std::max(outputVectorSize,pointVectorSize);
920 const int teamSize = 1;
922 auto policy = Kokkos::TeamPolicy<ExecutionSpace>(numPoints,teamSize,vectorSize);
923 Kokkos::parallel_for(
"Hierarchical_HCURL_TET_Functor", policy , functor);
934 BasisPtr<DeviceType,OutputScalar,PointScalar>
941 return Teuchos::rcp(
new HVOL_Line(this->
basisDegree_-1));
943 else if (subCellDim == 2)
947 INTREPID2_TEST_FOR_EXCEPTION(
true,std::invalid_argument,
"Input parameters out of bounds");
954 virtual BasisPtr<typename Kokkos::HostSpace::device_type, OutputScalar, PointScalar>
956 using HostDeviceType =
typename Kokkos::HostSpace::device_type;
958 return Teuchos::rcp(
new HostBasisType(polyOrder_) );
BasisPtr< DeviceType, OutputScalar, PointScalar > getSubCellRefBasis(const ordinal_type subCellDim, const ordinal_type subCellOrd) const override
returns the basis associated to a subCell.
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...
EBasis basisType_
Type of the basis.
const char * getName() const override
Returns basis name.
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.
Free functions, callable from device code, that implement various polynomials useful in basis definit...
virtual bool requireOrientation() const override
True if orientation is required.
H(curl) basis on the triangle using a construction involving Legendre and integrated Jacobi polynomia...
For mathematical details of the construction, see:
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...
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.
H(vol) basis on the line based on Legendre polynomials.
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.
OrdinalTypeArray2DHost ordinalToTag_
"true" if tagToOrdinal_ and ordinalToTag_ have been initialized
ordinal_type getDegree() const
Returns the degree of the basis.
Kokkos::DynRankView< OutputValueType, Kokkos::LayoutStride, DeviceType > OutputViewType
View type for basis value output.
ECoordinates basisCoordinates_
The coordinate system for which the basis is defined.
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 fieldOrdinalPolynomialDegree_
Polynomial degree for each degree of freedom. Only defined for hierarchical bases right now...
HierarchicalBasis_HCURL_TET(int polyOrder, const EPointType pointType=POINTTYPE_DEFAULT)
Constructor.
Kokkos::View< ordinal_type *, typename ExecutionSpace::array_layout, Kokkos::HostSpace > OrdinalTypeArray1DHost
View type for 1d host array.
Kokkos::DynRankView< PointValueType, Kokkos::LayoutStride, DeviceType > PointViewType
View type for input 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, DeviceType > PointViewType
View type for input points.
Functor for computing values for the HierarchicalBasis_HCURL_TET class.
Header file for the abstract base class Intrepid2::Basis.
typename DeviceType::execution_space ExecutionSpace
(Kokkos) Execution space for basis.