Intrepid2
Intrepid2_IntegratedLegendreBasis_HGRAD_PYR.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
21#ifndef Intrepid2_IntegratedLegendreBasis_HGRAD_PYR_h
22#define Intrepid2_IntegratedLegendreBasis_HGRAD_PYR_h
23
24#include <Kokkos_DynRankView.hpp>
25
26#include <Intrepid2_config.h>
27
28#include "Intrepid2_Basis.hpp"
34#include "Intrepid2_Utils.hpp"
35
36#include "Teuchos_RCP.hpp"
37
38namespace Intrepid2
39{
45 template<class DeviceType, class OutputScalar, class PointScalar,
46 class OutputFieldType, class InputPointsType>
48 {
49 using ExecutionSpace = typename DeviceType::execution_space;
50 using ScratchSpace = typename ExecutionSpace::scratch_memory_space;
51 using OutputScratchView = Kokkos::View<OutputScalar*,ScratchSpace,Kokkos::MemoryTraits<Kokkos::Unmanaged>>;
52 using OutputScratchView2D = Kokkos::View<OutputScalar**,ScratchSpace,Kokkos::MemoryTraits<Kokkos::Unmanaged>>;
53 using PointScratchView = Kokkos::View<PointScalar*, ScratchSpace,Kokkos::MemoryTraits<Kokkos::Unmanaged>>;
54
55 using TeamPolicy = Kokkos::TeamPolicy<ExecutionSpace>;
56 using TeamMember = typename TeamPolicy::member_type;
57
58 EOperator opType_;
59
60 OutputFieldType output_; // F,P
61 InputPointsType inputPoints_; // P,D
62
63 int polyOrder_;
64 bool defineVertexFunctions_;
65 int numFields_, numPoints_;
66
67 size_t fad_size_output_;
68
69 static const int numVertices = 5;
70 static const int numMixedEdges = 4;
71 static const int numTriEdges = 4;
72 static const int numEdges = 8;
73 // the following ordering of the edges matches that used by ESEAS
74 // (it *looks* like this is what ESEAS uses; the basis comparison tests will clarify whether I've read their code correctly)
75 // see also PyramidEdgeNodeMap in Shards_BasicTopologies.hpp
76 const int edge_start_[numEdges] = {0,1,2,3,0,1,2,3}; // edge i is from edge_start_[i] to edge_end_[i]
77 const int edge_end_[numEdges] = {1,2,3,0,4,4,4,4}; // edge i is from edge_start_[i] to edge_end_[i]
78
79 // quadrilateral face comes first
80 static const int numQuadFaces = 1;
81 static const int numTriFaces = 4;
82
83 // face ordering matches ESEAS. (See BlendProjectPyraTF in ESEAS.)
84 const int tri_face_vertex_0[numTriFaces] = {0,1,3,0}; // faces are abc where 0 ≤ a < b < c ≤ 3
85 const int tri_face_vertex_1[numTriFaces] = {1,2,2,3};
86 const int tri_face_vertex_2[numTriFaces] = {4,4,4,4};
87
88 Hierarchical_HGRAD_PYR_Functor(EOperator opType, OutputFieldType output, InputPointsType inputPoints,
89 int polyOrder, bool defineVertexFunctions)
90 : opType_(opType), output_(output), inputPoints_(inputPoints),
91 polyOrder_(polyOrder), defineVertexFunctions_(defineVertexFunctions),
92 fad_size_output_(getScalarDimensionForView(output))
93 {
94 numFields_ = output.extent_int(0);
95 numPoints_ = output.extent_int(1);
96 const auto & p = polyOrder;
97 const auto p3 = p * p * p;
98 INTREPID2_TEST_FOR_EXCEPTION(numPoints_ != inputPoints.extent_int(0), std::invalid_argument, "point counts need to match!");
99 INTREPID2_TEST_FOR_EXCEPTION(numFields_ != p3 + 3 * p + 1, std::invalid_argument, "output field size does not match basis cardinality");
100 }
101
102 KOKKOS_INLINE_FUNCTION
103 void operator()( const TeamMember & teamMember ) const
104 {
105 auto pointOrdinal = teamMember.league_rank();
106 OutputScratchView scratch1D_1, scratch1D_2, scratch1D_3;
107 OutputScratchView scratch1D_4, scratch1D_5, scratch1D_6;
108 OutputScratchView scratch1D_7, scratch1D_8, scratch1D_9;
109 OutputScratchView2D scratch2D_1, scratch2D_2, scratch2D_3;
110 const int numAlphaValues = (polyOrder_-1 > 1) ? (polyOrder_-1) : 1; // make numAlphaValues at least 1 so we can avoid zero-extent allocations…
111 if (fad_size_output_ > 0) {
112 scratch1D_1 = OutputScratchView(teamMember.team_shmem(), polyOrder_ + 1, fad_size_output_);
113 scratch1D_2 = OutputScratchView(teamMember.team_shmem(), polyOrder_ + 1, fad_size_output_);
114 scratch1D_3 = OutputScratchView(teamMember.team_shmem(), polyOrder_ + 1, fad_size_output_);
115 scratch1D_4 = OutputScratchView(teamMember.team_shmem(), polyOrder_ + 1, fad_size_output_);
116 scratch1D_5 = OutputScratchView(teamMember.team_shmem(), polyOrder_ + 1, fad_size_output_);
117 scratch1D_6 = OutputScratchView(teamMember.team_shmem(), polyOrder_ + 1, fad_size_output_);
118 scratch1D_7 = OutputScratchView(teamMember.team_shmem(), polyOrder_ + 1, fad_size_output_);
119 scratch1D_8 = OutputScratchView(teamMember.team_shmem(), polyOrder_ + 1, fad_size_output_);
120 scratch1D_9 = OutputScratchView(teamMember.team_shmem(), polyOrder_ + 1, fad_size_output_);
121 scratch2D_1 = OutputScratchView2D(teamMember.team_shmem(), numAlphaValues, polyOrder_ + 1, fad_size_output_);
122 scratch2D_2 = OutputScratchView2D(teamMember.team_shmem(), numAlphaValues, polyOrder_ + 1, fad_size_output_);
123 scratch2D_3 = OutputScratchView2D(teamMember.team_shmem(), numAlphaValues, polyOrder_ + 1, fad_size_output_);
124 }
125 else {
126 scratch1D_1 = OutputScratchView(teamMember.team_shmem(), polyOrder_ + 1);
127 scratch1D_2 = OutputScratchView(teamMember.team_shmem(), polyOrder_ + 1);
128 scratch1D_3 = OutputScratchView(teamMember.team_shmem(), polyOrder_ + 1);
129 scratch1D_4 = OutputScratchView(teamMember.team_shmem(), polyOrder_ + 1);
130 scratch1D_5 = OutputScratchView(teamMember.team_shmem(), polyOrder_ + 1);
131 scratch1D_6 = OutputScratchView(teamMember.team_shmem(), polyOrder_ + 1);
132 scratch1D_7 = OutputScratchView(teamMember.team_shmem(), polyOrder_ + 1);
133 scratch1D_8 = OutputScratchView(teamMember.team_shmem(), polyOrder_ + 1);
134 scratch1D_9 = OutputScratchView(teamMember.team_shmem(), polyOrder_ + 1);
135 scratch2D_1 = OutputScratchView2D(teamMember.team_shmem(), numAlphaValues, polyOrder_ + 1);
136 scratch2D_2 = OutputScratchView2D(teamMember.team_shmem(), numAlphaValues, polyOrder_ + 1);
137 scratch2D_3 = OutputScratchView2D(teamMember.team_shmem(), numAlphaValues, polyOrder_ + 1);
138 }
139
140 const auto & x = inputPoints_(pointOrdinal,0);
141 const auto & y = inputPoints_(pointOrdinal,1);
142 const auto & z = inputPoints_(pointOrdinal,2);
143
144 // Intrepid2 uses (-1,1)^2 for x,y
145 // ESEAS uses (0,1)^2
146 // (Can look at what we do on the HGRAD_LINE for reference; there's a similar difference for line topology.)
147
148 Kokkos::Array<PointScalar,3> coords;
149 transformToESEASPyramid<>(coords[0], coords[1], coords[2], x, y, z); // map x,y coordinates from (-z,z)^2 to (0,z)^2
150
151 // pyramid "affine" coordinates and gradients get stored in lambda, lambdaGrad:
152 using Kokkos::Array;
153 Array<PointScalar,5> lambda;
154 Array<Kokkos::Array<PointScalar,3>,5> lambdaGrad;
155
156 Array<Array<PointScalar,3>,2> mu;
157 Array<Array<Array<PointScalar,3>,3>,2> muGrad;
158
159 Array<Array<PointScalar,2>,3> nu;
160 Array<Array<Array<PointScalar,3>,2>,3> nuGrad;
161
162 affinePyramid(lambda, lambdaGrad, mu, muGrad, nu, nuGrad, coords);
163
164 switch (opType_)
165 {
166 case OPERATOR_VALUE:
167 {
168 // vertex functions come first, according to vertex ordering: (0,0,0), (1,0,0), (1,1,0), (0,1,0), (0,0,1)
169 for (int vertexOrdinal=0; vertexOrdinal<numVertices; vertexOrdinal++)
170 {
171 output_(vertexOrdinal,pointOrdinal) = lambda[vertexOrdinal];
172 }
173 if (!defineVertexFunctions_)
174 {
175 // "DG" basis case
176 // here, we overwrite the first vertex function with 1:
177 output_(0,pointOrdinal) = 1.0;
178 }
179
180 // rename scratch1, scratch2
181 auto & Li_a1 = scratch1D_1;
182 auto & Li_a2 = scratch1D_2;
183
184 Polynomials::shiftedScaledIntegratedLegendreValues(Li_a1, polyOrder_, nu[1][0], nu[0][0] + nu[1][0]);
185 Polynomials::shiftedScaledIntegratedLegendreValues(Li_a2, polyOrder_, nu[1][1], nu[0][1] + nu[1][1]);
186
187 // edge functions
188 // "mixed" edges (those shared between the quad and some tri face) first
189 int fieldOrdinalOffset = numVertices;
190 for (int edgeOrdinal=0; edgeOrdinal<numMixedEdges; edgeOrdinal++)
191 {
192 // edge 0,2 --> a=1, b=2
193 // edge 1,3 --> a=2, b=1
194 int a = (edgeOrdinal % 2 == 0) ? 1 : 2;
195 int b = 3 - a;
196 auto & Li = (a == 1) ? Li_a1 : Li_a2;
197 // edge 0,3 --> c=0
198 // edge 1,2 --> c=1
199 int c = ((edgeOrdinal == 0) || (edgeOrdinal == 3)) ? 0 : 1;
200 for (int i=2; i<=polyOrder_; i++)
201 {
202 output_(fieldOrdinalOffset,pointOrdinal) = mu[c][b-1] * Li(i);
203 fieldOrdinalOffset++;
204 }
205 }
206
207 // triangle edges next
208 // rename scratch1
209 auto & Li = scratch1D_1;
210 for (int edgeOrdinal=0; edgeOrdinal<numMixedEdges; edgeOrdinal++)
211 {
212 const auto & lambda_a = lambda[edgeOrdinal];
213 Polynomials::shiftedScaledIntegratedLegendreValues(Li, polyOrder_, lambda[4], lambda_a + lambda[4]);
214 for (int i=2; i<=polyOrder_; i++)
215 {
216 output_(fieldOrdinalOffset,pointOrdinal) = Li(i);
217 fieldOrdinalOffset++;
218 }
219 }
220
221 // quadrilateral face
222 // mu_0 * phi_i(mu_0^{xi_1},mu_1^{xi_1}) * phi_j(mu_0^{xi_2},mu_1^{xi_2})
223
224 // rename scratch
225 Li = scratch1D_1;
226 auto & Lj = scratch1D_2;
227 Polynomials::shiftedScaledIntegratedLegendreValues(Li, polyOrder_, mu[1][0], mu[0][0] + mu[1][0]);
228 Polynomials::shiftedScaledIntegratedLegendreValues(Lj, polyOrder_, mu[1][1], mu[0][1] + mu[1][1]);
229 // following the ESEAS ordering: j increments first
230 for (int j=2; j<=polyOrder_; j++)
231 {
232 for (int i=2; i<=polyOrder_; i++)
233 {
234 output_(fieldOrdinalOffset,pointOrdinal) = mu[0][2] * Li(i) * Lj(j);
235 fieldOrdinalOffset++;
236 }
237 }
238
239 /*
240 Face functions for triangular face (d,e,f) are the product of:
241 mu_c^{zeta,xi_b},
242 edge functions on their (d,e) edge,
243 and a Jacobi polynomial [L^2i_j](s0+s1,s2) = L^2i_j(s2;s0+s1+s2),
244
245 where s0, s1, s2 are nu[0][a-1],nu[1][a-1],nu[2][a-1],
246 and (a,b) = (1,2) for faces 0,2; (a,b) = (2,1) for others;
247 c = 0 for faces 0,3; c = 1 for others
248 */
249 for (int faceOrdinal=0; faceOrdinal<numTriFaces; faceOrdinal++)
250 {
251 // face 0,2 --> a=1, b=2
252 // face 1,3 --> a=2, b=1
253 int a = (faceOrdinal % 2 == 0) ? 1 : 2;
254 int b = 3 - a;
255 // face 0,3 --> c=0
256 // face 1,2 --> c=1
257 int c = ((faceOrdinal == 0) || (faceOrdinal == 3)) ? 0 : 1;
258
259 const auto & s0 = nu[0][a-1];
260 const auto & s1 = nu[1][a-1];
261 const auto & s2 = nu[2][a-1];
262 const PointScalar jacobiScaling = s0 + s1 + s2;
263
264 // compute integrated Jacobi values for each desired value of alpha
265 // relabel scratch2D_1
266 auto & jacobi = scratch2D_1;
267 for (int n=2; n<=polyOrder_; n++)
268 {
269 const double alpha = n*2;
270 const int alphaOrdinal = n-2;
271 using Kokkos::subview;
272 using Kokkos::ALL;
273 auto jacobi_alpha = subview(jacobi, alphaOrdinal, ALL);
274 Polynomials::shiftedScaledIntegratedJacobiValues(jacobi_alpha, alpha, polyOrder_-2, s2, jacobiScaling);
275 }
276 // relabel scratch1D_1
277 auto & edge_s0s1 = scratch1D_1;
278 Polynomials::shiftedScaledIntegratedLegendreValues(edge_s0s1, polyOrder_, s1, s0 + s1);
279
280 for (int totalPolyOrder=3; totalPolyOrder<=polyOrder_; totalPolyOrder++)
281 {
282 for (int i=2; i<totalPolyOrder; i++)
283 {
284 const auto & edgeValue = edge_s0s1(i);
285 const int alphaOrdinal = i-2;
286
287 const int j = totalPolyOrder - i;
288 const auto & jacobiValue = jacobi(alphaOrdinal,j);
289 output_(fieldOrdinalOffset,pointOrdinal) = mu[c][b-1] * edgeValue * jacobiValue;
290
291 fieldOrdinalOffset++;
292 }
293 }
294 }
295
296 // interior functions
297 // these are the product of the same quadrilateral function that we blended for the quadrilateral face and
298 // [L_k](mu_{0}^zeta, mu_1^zeta)
299
300 // rename scratch
301 Li = scratch1D_1;
302 Lj = scratch1D_2;
303 auto & Lk = scratch1D_3;
304 Polynomials::shiftedScaledIntegratedLegendreValues(Li, polyOrder_, mu[1][0], mu[0][0] + mu[1][0]);
305 Polynomials::shiftedScaledIntegratedLegendreValues(Lj, polyOrder_, mu[1][1], mu[0][1] + mu[1][1]);
306 Polynomials::shiftedScaledIntegratedLegendreValues(Lk, polyOrder_, mu[1][2], mu[0][2] + mu[1][2]);
307 // following the ESEAS ordering: k increments first
308 for (int k=2; k<=polyOrder_; k++)
309 {
310 for (int j=2; j<=polyOrder_; j++)
311 {
312 for (int i=2; i<=polyOrder_; i++)
313 {
314 output_(fieldOrdinalOffset,pointOrdinal) = Lk(k) * Li(i) * Lj(j);
315 fieldOrdinalOffset++;
316 }
317 }
318 }
319 } // end OPERATOR_VALUE
320 break;
321 case OPERATOR_GRAD:
322 case OPERATOR_D1:
323 {
324 // vertex functions
325
326 for (int vertexOrdinal=0; vertexOrdinal<numVertices; vertexOrdinal++)
327 {
328 for (int d=0; d<3; d++)
329 {
330 output_(vertexOrdinal,pointOrdinal,d) = lambdaGrad[vertexOrdinal][d];
331 }
332 }
333
334 if (!defineVertexFunctions_)
335 {
336 // "DG" basis case
337 // here, the first "vertex" function is 1, so the derivative is 0:
338 output_(0,pointOrdinal,0) = 0.0;
339 output_(0,pointOrdinal,1) = 0.0;
340 output_(0,pointOrdinal,2) = 0.0;
341 }
342
343 // edge functions
344 int fieldOrdinalOffset = numVertices;
345
346 // mixed edges first
347 auto & P_i_minus_1 = scratch1D_1;
348 auto & L_i_dt = scratch1D_2; // R_{i-1} = d/dt L_i
349 auto & L_i = scratch1D_3;
350
351 for (int edgeOrdinal=0; edgeOrdinal<numMixedEdges; edgeOrdinal++)
352 {
353 // edge 0,2 --> a=1, b=2
354 // edge 1,3 --> a=2, b=1
355 int a = (edgeOrdinal % 2 == 0) ? 1 : 2;
356 int b = 3 - a;
357
358 Polynomials::shiftedScaledLegendreValues (P_i_minus_1, polyOrder_-1, nu[1][a-1], nu[0][a-1] + nu[1][a-1]);
359 Polynomials::shiftedScaledIntegratedLegendreValues_dt(L_i_dt, polyOrder_, nu[1][a-1], nu[0][a-1] + nu[1][a-1]);
360 Polynomials::shiftedScaledIntegratedLegendreValues (L_i, polyOrder_, nu[1][a-1], nu[0][a-1] + nu[1][a-1]);
361
362 // edge 0,3 --> c=0
363 // edge 1,2 --> c=1
364 int c = ((edgeOrdinal == 0) || (edgeOrdinal == 3)) ? 0 : 1;
365 for (int i=2; i<=polyOrder_; i++)
366 {
367 // grad (mu[c][b-1] * Li(i)) = grad (mu[c][b-1]) * Li(i) + mu[c][b-1] * grad Li(i)
368 const auto & R_i_minus_1 = L_i_dt(i);
369
370 for (int d=0; d<3; d++)
371 {
372 // grad [L_i](nu_0,nu_1) = [P_{i-1}](nu_0,nu_1) * grad nu_1 + [R_{i-1}](nu_0,nu_1) * grad (nu_0 + nu_1)
373
374 OutputScalar grad_Li_d = P_i_minus_1(i-1) * nuGrad[1][a-1][d] + R_i_minus_1 * (nuGrad[0][a-1][d] + nuGrad[1][a-1][d]);
375 output_(fieldOrdinalOffset,pointOrdinal,d) = muGrad[c][b-1][d] * L_i(i) + mu[c][b-1] * grad_Li_d;
376 }
377 fieldOrdinalOffset++;
378 }
379 }
380
381 // triangle edges next
382 P_i_minus_1 = scratch1D_1;
383 L_i_dt = scratch1D_2; // R_{i-1} = d/dt L_i
384 L_i = scratch1D_3;
385 for (int edgeOrdinal=0; edgeOrdinal<numMixedEdges; edgeOrdinal++)
386 {
387 const auto & lambda_a = lambda [edgeOrdinal];
388 const auto & lambdaGrad_a = lambdaGrad[edgeOrdinal];
389 Polynomials::shiftedScaledLegendreValues (P_i_minus_1, polyOrder_-1, lambda[4], lambda_a + lambda[4]);
390 Polynomials::shiftedScaledIntegratedLegendreValues_dt(L_i_dt, polyOrder_, lambda[4], lambda_a + lambda[4]);
391 Polynomials::shiftedScaledIntegratedLegendreValues (L_i, polyOrder_, lambda[4], lambda_a + lambda[4]);
392
393 for (int i=2; i<=polyOrder_; i++)
394 {
395 const auto & R_i_minus_1 = L_i_dt(i);
396 for (int d=0; d<3; d++)
397 {
398 // grad [L_i](s0,s1) = [P_{i-1}](s0,s1) * grad s1 + [R_{i-1}](s0,s1) * grad (s0 + s1)
399 // here, s1 = lambda[4], s0 = lambda_a
400 OutputScalar grad_Li_d = P_i_minus_1(i-1) * lambdaGrad[4][d] + R_i_minus_1 * (lambdaGrad_a[d] + lambdaGrad[4][d]);
401 output_(fieldOrdinalOffset,pointOrdinal,d) = grad_Li_d;
402 }
403 fieldOrdinalOffset++;
404 }
405 }
406
407 // quadrilateral faces
408 // rename scratch
409 P_i_minus_1 = scratch1D_1;
410 L_i_dt = scratch1D_2; // R_{i-1} = d/dt L_i
411 L_i = scratch1D_3;
412 auto & P_j_minus_1 = scratch1D_4;
413 auto & L_j_dt = scratch1D_5; // R_{j-1} = d/dt L_j
414 auto & L_j = scratch1D_6;
415 Polynomials::shiftedScaledIntegratedLegendreValues(L_i, polyOrder_, mu[1][0], mu[0][0] + mu[1][0]);
416 Polynomials::shiftedScaledIntegratedLegendreValues(L_j, polyOrder_, mu[1][1], mu[0][1] + mu[1][1]);
417
418 Polynomials::shiftedScaledLegendreValues (P_i_minus_1, polyOrder_-1, mu[1][0], mu[0][0] + mu[1][0]);
419 Polynomials::shiftedScaledIntegratedLegendreValues_dt(L_i_dt, polyOrder_, mu[1][0], mu[0][0] + mu[1][0]);
420 Polynomials::shiftedScaledIntegratedLegendreValues (L_i, polyOrder_, mu[1][0], mu[0][0] + mu[1][0]);
421
422 Polynomials::shiftedScaledLegendreValues (P_j_minus_1, polyOrder_-1, mu[1][1], mu[0][1] + mu[1][1]);
423 Polynomials::shiftedScaledIntegratedLegendreValues_dt(L_j_dt, polyOrder_, mu[1][1], mu[0][1] + mu[1][1]);
424 Polynomials::shiftedScaledIntegratedLegendreValues (L_j, polyOrder_, mu[1][1], mu[0][1] + mu[1][1]);
425
426 // following the ESEAS ordering: j increments first
427 for (int j=2; j<=polyOrder_; j++)
428 {
429 const auto & R_j_minus_1 = L_j_dt(j);
430
431 for (int i=2; i<=polyOrder_; i++)
432 {
433 const auto & R_i_minus_1 = L_i_dt(i);
434
435 OutputScalar phi_quad = L_i(i) * L_j(j);
436
437 for (int d=0; d<3; d++)
438 {
439 // grad [L_j](s0,s1) = [P_{j-1}](s0,s1) * grad s1 + [R_{j-1}](s0,s1) * grad (s0 + s1)
440 // here, s1 = mu[1][1], s0 = mu[0][1]
441 OutputScalar grad_Lj_d = P_j_minus_1(j-1) * muGrad[1][1][d] + R_j_minus_1 * (muGrad[0][1][d] + muGrad[1][1][d]);
442 // for L_i, s1 = mu[1][0], s0 = mu[0][0]
443 OutputScalar grad_Li_d = P_i_minus_1(i-1) * muGrad[1][0][d] + R_i_minus_1 * (muGrad[0][0][d] + muGrad[1][0][d]);
444
445 OutputScalar grad_phi_quad_d = L_i(i) * grad_Lj_d + L_j(j) * grad_Li_d;
446
447 output_(fieldOrdinalOffset,pointOrdinal,d) = mu[0][2] * grad_phi_quad_d + phi_quad * muGrad[0][2][d];
448 }
449
450 fieldOrdinalOffset++;
451 }
452 }
453
454 // triangle faces
455 for (int faceOrdinal=0; faceOrdinal<numTriFaces; faceOrdinal++)
456 {
457 // face 0,2 --> a=1, b=2
458 // face 1,3 --> a=2, b=1
459 int a = (faceOrdinal % 2 == 0) ? 1 : 2;
460 int b = 3 - a;
461 // face 0,3 --> c=0
462 // face 1,2 --> c=1
463 int c = ((faceOrdinal == 0) || (faceOrdinal == 3)) ? 0 : 1;
464
465 const auto & s0 = nu[0][a-1];
466 const auto & s1 = nu[1][a-1];
467 const auto & s2 = nu[2][a-1];
468
469 const auto & s0Grad = nuGrad[0][a-1];
470 const auto & s1Grad = nuGrad[1][a-1];
471 const auto & s2Grad = nuGrad[2][a-1];
472
473 const PointScalar jacobiScaling = s0 + s1 + s2;
474
475 // compute integrated Jacobi values for each desired value of alpha
476 // relabel storage:
477 // 1D containers:
478 P_i_minus_1 = scratch1D_1;
479 L_i_dt = scratch1D_2; // R_{i-1} = d/dt L_i
480 L_i = scratch1D_3;
481 // 2D containers:
482 auto & L_2i_j_dt = scratch2D_1;
483 auto & L_2i_j = scratch2D_2;
484 auto & P_2i_j_minus_1 = scratch2D_3;
485 for (int n=2; n<=polyOrder_; n++)
486 {
487 const double alpha = n*2;
488 const int alphaOrdinal = n-2;
489 using Kokkos::subview;
490 using Kokkos::ALL;
491 auto L_2i_j_dt_alpha = subview(L_2i_j_dt, alphaOrdinal, ALL);
492 auto L_2i_j_alpha = subview(L_2i_j, alphaOrdinal, ALL);
493 auto P_2i_j_minus_1_alpha = subview(P_2i_j_minus_1, alphaOrdinal, ALL);
494 Polynomials::shiftedScaledIntegratedJacobiValues_dt(L_2i_j_dt_alpha, alpha, polyOrder_-2, s2, jacobiScaling);
495 Polynomials::shiftedScaledIntegratedJacobiValues ( L_2i_j_alpha, alpha, polyOrder_-2, s2, jacobiScaling);
496 Polynomials::shiftedScaledJacobiValues (P_2i_j_minus_1_alpha, alpha, polyOrder_-1, s2, jacobiScaling);
497 }
498 Polynomials::shiftedScaledLegendreValues (P_i_minus_1, polyOrder_-1, s1, s0 + s1);
499 Polynomials::shiftedScaledIntegratedLegendreValues_dt(L_i_dt, polyOrder_, s1, s0 + s1);
500 Polynomials::shiftedScaledIntegratedLegendreValues (L_i, polyOrder_, s1, s0 + s1);
501
502 for (int totalPolyOrder=3; totalPolyOrder<=polyOrder_; totalPolyOrder++)
503 {
504 for (int i=2; i<totalPolyOrder; i++)
505 {
506 const int alphaOrdinal = i-2;
507 const int j = totalPolyOrder - i;
508
509 const auto & R_i_minus_1 = L_i_dt(i);
510 OutputScalar phi_tri = L_2i_j(alphaOrdinal,j) * L_i(i);
511
512 for (int d=0; d<3; d++)
513 {
514 // grad [L_i](s0,s1) = [P_{i-1}](s0,s1) * grad s1 + [R_{i-1}](s0,s1) * grad (s0 + s1)
515 OutputScalar grad_Li_d = P_i_minus_1(i-1) * s1Grad[d] + R_i_minus_1 * (s0Grad[d] + s1Grad[d]);
516 OutputScalar grad_L2i_j_d = P_2i_j_minus_1(alphaOrdinal,j-1) * s2Grad[d] + L_2i_j_dt(alphaOrdinal,j) * (s0Grad[d] + s1Grad[d] + s2Grad[d]);
517 OutputScalar grad_phi_tri_d = L_i(i) * grad_L2i_j_d + L_2i_j(alphaOrdinal,j) * grad_Li_d;
518
519 output_(fieldOrdinalOffset,pointOrdinal,d) = mu[c][b-1] * grad_phi_tri_d + phi_tri * muGrad[c][b-1][d];
520 }
521 fieldOrdinalOffset++;
522 }
523 }
524 }
525
526 // interior functions
527 P_i_minus_1 = scratch1D_1;
528 L_i_dt = scratch1D_2; // R_{i-1} = d/dt L_i
529 L_i = scratch1D_3;
530 P_j_minus_1 = scratch1D_4;
531 L_j_dt = scratch1D_5; // R_{j-1} = d/dt L_j
532 L_j = scratch1D_6;
533 auto & P_k_minus_1 = scratch1D_7;
534 auto & L_k_dt = scratch1D_8; // R_{k-1} = d/dt L_k
535 auto & L_k = scratch1D_9;
536
537 Polynomials::shiftedScaledLegendreValues (P_i_minus_1, polyOrder_-1, mu[1][0], mu[0][0] + mu[1][0]);
538 Polynomials::shiftedScaledIntegratedLegendreValues_dt(L_i_dt, polyOrder_, mu[1][0], mu[0][0] + mu[1][0]);
539 Polynomials::shiftedScaledIntegratedLegendreValues (L_i, polyOrder_, mu[1][0], mu[0][0] + mu[1][0]);
540
541 Polynomials::shiftedScaledLegendreValues (P_j_minus_1, polyOrder_-1, mu[1][1], mu[0][1] + mu[1][1]);
542 Polynomials::shiftedScaledIntegratedLegendreValues_dt(L_j_dt, polyOrder_, mu[1][1], mu[0][1] + mu[1][1]);
543 Polynomials::shiftedScaledIntegratedLegendreValues (L_j, polyOrder_, mu[1][1], mu[0][1] + mu[1][1]);
544
545 Polynomials::shiftedScaledLegendreValues (P_k_minus_1, polyOrder_-1, mu[1][2], mu[0][2] + mu[1][2]);
546 Polynomials::shiftedScaledIntegratedLegendreValues_dt(L_k_dt, polyOrder_, mu[1][2], mu[0][2] + mu[1][2]);
547 Polynomials::shiftedScaledIntegratedLegendreValues (L_k, polyOrder_, mu[1][2], mu[0][2] + mu[1][2]);
548
549 // following the ESEAS ordering: k increments first
550 for (int k=2; k<=polyOrder_; k++)
551 {
552 const auto & R_k_minus_1 = L_k_dt(k);
553
554 for (int j=2; j<=polyOrder_; j++)
555 {
556 const auto & R_j_minus_1 = L_j_dt(j);
557
558 for (int i=2; i<=polyOrder_; i++)
559 {
560 const auto & R_i_minus_1 = L_i_dt(i);
561
562 OutputScalar phi_quad = L_i(i) * L_j(j);
563
564 for (int d=0; d<3; d++)
565 {
566 // grad [L_i](s0,s1) = [P_{i-1}](s0,s1) * grad s1 + [R_{i-1}](s0,s1) * grad (s0 + s1)
567 // for L_i, s1 = mu[1][0], s0 = mu[0][0]
568 OutputScalar grad_Li_d = P_i_minus_1(i-1) * muGrad[1][0][d] + R_i_minus_1 * (muGrad[0][0][d] + muGrad[1][0][d]);
569 // for L_j, s1 = mu[1][1], s0 = mu[0][1]
570 OutputScalar grad_Lj_d = P_j_minus_1(j-1) * muGrad[1][1][d] + R_j_minus_1 * (muGrad[0][1][d] + muGrad[1][1][d]);
571 // for L_k, s1 = mu[1][2], s0 = mu[0][2]
572 OutputScalar grad_Lk_d = P_k_minus_1(k-1) * muGrad[1][2][d] + R_k_minus_1 * (muGrad[0][2][d] + muGrad[1][2][d]);
573
574 OutputScalar grad_phi_quad_d = L_i(i) * grad_Lj_d + L_j(j) * grad_Li_d;
575
576 output_(fieldOrdinalOffset,pointOrdinal,d) = L_k(k) * grad_phi_quad_d + phi_quad * grad_Lk_d;
577 }
578
579 fieldOrdinalOffset++;
580 }
581 }
582 }
583
584 for (int basisOrdinal=0; basisOrdinal<numFields_; basisOrdinal++)
585 {
586 // transform derivatives to account for the ref space transformation: Intrepid2 uses (-z,z)^2; ESEAS uses (0,z)^2
587 const auto dx_eseas = output_(basisOrdinal,pointOrdinal,0);
588 const auto dy_eseas = output_(basisOrdinal,pointOrdinal,1);
589 const auto dz_eseas = output_(basisOrdinal,pointOrdinal,2);
590
591 auto &dx_int2 = output_(basisOrdinal,pointOrdinal,0);
592 auto &dy_int2 = output_(basisOrdinal,pointOrdinal,1);
593 auto &dz_int2 = output_(basisOrdinal,pointOrdinal,2);
594
595 transformFromESEASPyramidGradient(dx_int2, dy_int2, dz_int2, dx_eseas, dy_eseas, dz_eseas);
596 }
597
598 } // end OPERATOR_GRAD block
599 break;
600 case OPERATOR_D2:
601 case OPERATOR_D3:
602 case OPERATOR_D4:
603 case OPERATOR_D5:
604 case OPERATOR_D6:
605 case OPERATOR_D7:
606 case OPERATOR_D8:
607 case OPERATOR_D9:
608 case OPERATOR_D10:
609 INTREPID2_TEST_FOR_ABORT( true,
610 ">>> ERROR: (Intrepid2::Hierarchical_HGRAD_PYR_Functor) Computing of second and higher-order derivatives is not currently supported");
611 default:
612 // unsupported operator type
613 device_assert(false);
614 }
615 }
616
617 // Provide the shared memory capacity.
618 // This function takes the team_size as an argument,
619 // which allows team_size-dependent allocations.
620 size_t team_shmem_size (int team_size) const
621 {
622 // we use shared memory to create a fast buffer for basis computations
623 // for the (integrated) Legendre computations, we just need p+1 values stored. For interior functions on the pyramid, we have up to 3 scratch arrays with (integrated) Legendre values stored, for each of the 3 directions (i,j,k indices): a total of 9.
624 // for the (integrated) Jacobi computations, though, we want (p+1)*(# alpha values)
625 // alpha is either 2i or 2(i+j), where i=2,…,p or i+j=3,…,p. So there are at most (p-1) alpha values needed.
626 // We can have up to 3 of the (integrated) Jacobi values needed at once.
627 const int numAlphaValues = std::max(polyOrder_-1, 1); // make it at least 1 so we can avoid zero-extent ranks…
628 size_t shmem_size = 0;
629 if (fad_size_output_ > 0)
630 {
631 // Legendre:
632 shmem_size += 9 * OutputScratchView::shmem_size(polyOrder_ + 1, fad_size_output_);
633 // Jacobi:
634 shmem_size += 3 * OutputScratchView2D::shmem_size(numAlphaValues, polyOrder_ + 1, fad_size_output_);
635 }
636 else
637 {
638 // Legendre:
639 shmem_size += 9 * OutputScratchView::shmem_size(polyOrder_ + 1);
640 // Jacobi:
641 shmem_size += 3 * OutputScratchView2D::shmem_size(numAlphaValues, polyOrder_ + 1);
642 }
643
644 return shmem_size;
645 }
646 };
647
665 template<typename DeviceType,
666 typename OutputScalar = double,
667 typename PointScalar = double,
668 bool defineVertexFunctions = true> // if defineVertexFunctions is true, first four basis functions are 1-x-y-z, x, y, and z. Otherwise, they are 1, x, y, and z.
670 : public Basis<DeviceType,OutputScalar,PointScalar>
671 {
672 public:
674
677
678 using typename BasisBase::OutputViewType;
679 using typename BasisBase::PointViewType;
680 using typename BasisBase::ScalarViewType;
681
682 using typename BasisBase::ExecutionSpace;
683
684 protected:
685 int polyOrder_; // the maximum order of the polynomial
686 EPointType pointType_;
687 public:
698 IntegratedLegendreBasis_HGRAD_PYR(int polyOrder, const EPointType pointType=POINTTYPE_DEFAULT)
699 :
700 polyOrder_(polyOrder),
701 pointType_(pointType)
702 {
703 INTREPID2_TEST_FOR_EXCEPTION(pointType!=POINTTYPE_DEFAULT,std::invalid_argument,"PointType not supported");
704 this->basisCardinality_ = polyOrder * polyOrder * polyOrder + 3 * polyOrder + 1;
705 this->basisDegree_ = polyOrder;
706 this->basisCellTopologyKey_ = shards::Pyramid<>::key;
707 this->basisType_ = BASIS_FEM_HIERARCHICAL;
708 this->basisCoordinates_ = COORDINATES_CARTESIAN;
709 this->functionSpace_ = FUNCTION_SPACE_HGRAD;
710
711 const int degreeLength = 1;
712 this->fieldOrdinalPolynomialDegree_ = OrdinalTypeArray2DHost("Integrated Legendre H(grad) pyramid polynomial degree lookup", this->basisCardinality_, degreeLength);
713 this->fieldOrdinalH1PolynomialDegree_ = OrdinalTypeArray2DHost("Integrated Legendre H(grad) pyramid polynomial H^1 degree lookup", this->basisCardinality_, degreeLength);
714
715 int fieldOrdinalOffset = 0;
716 // **** vertex functions **** //
717 const int numVertices = this->getBaseCellTopology().getVertexCount();
718 for (int i=0; i<numVertices; i++)
719 {
720 // for H(grad) on Pyramid, if defineVertexFunctions is false, first five basis members are linear
721 // if not, then the only difference is that the first member is constant
722 this->fieldOrdinalPolynomialDegree_ (i,0) = 1;
723 this->fieldOrdinalH1PolynomialDegree_(i,0) = 1;
724 }
725 if (!defineVertexFunctions)
726 {
727 this->fieldOrdinalPolynomialDegree_ (0,0) = 0;
728 this->fieldOrdinalH1PolynomialDegree_(0,0) = 0;
729 }
730 fieldOrdinalOffset += numVertices;
731
732 // **** edge functions **** //
733 const int numFunctionsPerEdge = polyOrder - 1; // bubble functions: all but the vertices
734 const int numEdges = this->getBaseCellTopology().getEdgeCount();
735 for (int edgeOrdinal=0; edgeOrdinal<numEdges; edgeOrdinal++)
736 {
737 for (int i=0; i<numFunctionsPerEdge; i++)
738 {
739 this->fieldOrdinalPolynomialDegree_(i+fieldOrdinalOffset,0) = i+2; // vertex functions are 1st order; edge functions start at order 2
740 this->fieldOrdinalH1PolynomialDegree_(i+fieldOrdinalOffset,0) = i+2; // vertex functions are 1st order; edge functions start at order 2
741 }
742 fieldOrdinalOffset += numFunctionsPerEdge;
743 }
744
745 // **** face functions **** //
746 // one quad face
747 const int numFunctionsPerQuadFace = (polyOrder-1)*(polyOrder-1);
748
749 // following the ESEAS ordering: j increments first
750 for (int j=2; j<=polyOrder_; j++)
751 {
752 for (int i=2; i<=polyOrder_; i++)
753 {
754 this->fieldOrdinalPolynomialDegree_ (fieldOrdinalOffset,0) = std::max(i,j);
755 this->fieldOrdinalH1PolynomialDegree_(fieldOrdinalOffset,0) = std::max(i,j);
756 fieldOrdinalOffset++;
757 }
758 }
759
760 const int numFunctionsPerTriFace = ((polyOrder-1)*(polyOrder-2))/2;
761 const int numTriFaces = 4;
762 for (int faceOrdinal=0; faceOrdinal<numTriFaces; faceOrdinal++)
763 {
764 for (int totalPolyOrder=3; totalPolyOrder<=polyOrder_; totalPolyOrder++)
765 {
766 const int totalFaceDofs = (totalPolyOrder-2)*(totalPolyOrder-1)/2;
767 const int totalFaceDofsPrevious = (totalPolyOrder-3)*(totalPolyOrder-2)/2;
768 const int faceDofsForPolyOrder = totalFaceDofs - totalFaceDofsPrevious;
769 for (int i=0; i<faceDofsForPolyOrder; i++)
770 {
771 this->fieldOrdinalPolynomialDegree_ (fieldOrdinalOffset,0) = totalPolyOrder;
772 this->fieldOrdinalH1PolynomialDegree_(fieldOrdinalOffset,0) = totalPolyOrder;
773 fieldOrdinalOffset++;
774 }
775 }
776 }
777
778 // **** interior functions **** //
779 const int numFunctionsPerVolume = (polyOrder-1)*(polyOrder-1)*(polyOrder-1);
780 const int numVolumes = 1; // interior
781 for (int volumeOrdinal=0; volumeOrdinal<numVolumes; volumeOrdinal++)
782 {
783 // following the ESEAS ordering: k increments first
784 for (int k=2; k<=polyOrder_; k++)
785 {
786 for (int j=2; j<=polyOrder_; j++)
787 {
788 for (int i=2; i<=polyOrder_; i++)
789 {
790 const int max_ij = std::max(i,j);
791 const int max_ijk = std::max(max_ij,k);
792 this->fieldOrdinalPolynomialDegree_ (fieldOrdinalOffset,0) = max_ijk;
793 this->fieldOrdinalH1PolynomialDegree_(fieldOrdinalOffset,0) = max_ijk;
794 fieldOrdinalOffset++;
795 }
796 }
797 }
798 }
799
800 INTREPID2_TEST_FOR_EXCEPTION(fieldOrdinalOffset != this->basisCardinality_, std::invalid_argument, "Internal error: basis enumeration is incorrect");
801
802 // initialize tags
803 {
804 // Intrepid2 vertices:
805 // 0: (-1,-1, 0)
806 // 1: ( 1,-1, 0)
807 // 2: ( 1, 1, 0)
808 // 3: (-1, 1, 0)
809 // 4: ( 0, 0, 1)
810
811 // ESEAS vertices:
812 // 0: ( 0, 0, 0)
813 // 1: ( 1, 0, 0)
814 // 2: ( 1, 1, 0)
815 // 3: ( 0, 1, 0)
816 // 4: ( 0, 0, 1)
817
818 // The edge numbering appears to match between ESEAS and Intrepid2
819
820 // ESEAS numbers pyramid faces differently from Intrepid2
821 // See BlendProjectPyraTF in ESEAS.
822 // See PyramidFaceNodeMap in Shards_BasicTopologies
823 // ESEAS: 0123, 014, 124, 324, 034
824 // Intrepid2: 014, 124, 234, 304, 0321
825
826 const int intrepid2FaceOrdinals[5] {4,0,1,2,3}; // index is the ESEAS face ordinal; value is the intrepid2 ordinal
827
828 const auto & cardinality = this->basisCardinality_;
829
830 // Basis-dependent initializations
831 const ordinal_type tagSize = 4; // size of DoF tag, i.e., number of fields in the tag
832 const ordinal_type posScDim = 0; // position in the tag, counting from 0, of the subcell dim
833 const ordinal_type posScOrd = 1; // position in the tag, counting from 0, of the subcell ordinal
834 const ordinal_type posDfOrd = 2; // position in the tag, counting from 0, of DoF ordinal relative to the subcell
835
836 OrdinalTypeArray1DHost tagView("tag view", cardinality*tagSize);
837 const int vertexDim = 0, edgeDim = 1, faceDim = 2, volumeDim = 3;
838
839 if (defineVertexFunctions) {
840 {
841 int tagNumber = 0;
842 for (int vertexOrdinal=0; vertexOrdinal<numVertices; vertexOrdinal++)
843 {
844 tagView(tagNumber*tagSize+0) = vertexDim; // vertex dimension
845 tagView(tagNumber*tagSize+1) = vertexOrdinal; // vertex id
846 tagView(tagNumber*tagSize+2) = 0; // local dof id
847 tagView(tagNumber*tagSize+3) = 1; // total number of dofs at this vertex
848 tagNumber++;
849 }
850 for (int edgeOrdinal=0; edgeOrdinal<numEdges; edgeOrdinal++)
851 {
852 for (int functionOrdinal=0; functionOrdinal<numFunctionsPerEdge; functionOrdinal++)
853 {
854 tagView(tagNumber*tagSize+0) = edgeDim; // edge dimension
855 tagView(tagNumber*tagSize+1) = edgeOrdinal; // edge id
856 tagView(tagNumber*tagSize+2) = functionOrdinal; // local dof id
857 tagView(tagNumber*tagSize+3) = numFunctionsPerEdge; // total number of dofs on this edge
858 tagNumber++;
859 }
860 }
861 {
862 // quad face
863 const int faceOrdinalESEAS = 0;
864 const int faceOrdinalIntrepid2 = intrepid2FaceOrdinals[faceOrdinalESEAS];
865
866 for (int functionOrdinal=0; functionOrdinal<numFunctionsPerQuadFace; functionOrdinal++)
867 {
868 tagView(tagNumber*tagSize+0) = faceDim; // face dimension
869 tagView(tagNumber*tagSize+1) = faceOrdinalIntrepid2; // face id
870 tagView(tagNumber*tagSize+2) = functionOrdinal; // local dof id
871 tagView(tagNumber*tagSize+3) = numFunctionsPerQuadFace; // total number of dofs on this face
872 tagNumber++;
873 }
874 }
875 for (int triFaceOrdinalESEAS=0; triFaceOrdinalESEAS<numTriFaces; triFaceOrdinalESEAS++)
876 {
877 const int faceOrdinalESEAS = triFaceOrdinalESEAS + 1;
878 const int faceOrdinalIntrepid2 = intrepid2FaceOrdinals[faceOrdinalESEAS];
879 for (int functionOrdinal=0; functionOrdinal<numFunctionsPerTriFace; functionOrdinal++)
880 {
881 tagView(tagNumber*tagSize+0) = faceDim; // face dimension
882 tagView(tagNumber*tagSize+1) = faceOrdinalIntrepid2; // face id
883 tagView(tagNumber*tagSize+2) = functionOrdinal; // local dof id
884 tagView(tagNumber*tagSize+3) = numFunctionsPerTriFace; // total number of dofs on this face
885 tagNumber++;
886 }
887 }
888 for (int volumeOrdinal=0; volumeOrdinal<numVolumes; volumeOrdinal++)
889 {
890 for (int functionOrdinal=0; functionOrdinal<numFunctionsPerVolume; functionOrdinal++)
891 {
892 tagView(tagNumber*tagSize+0) = volumeDim; // volume dimension
893 tagView(tagNumber*tagSize+1) = volumeOrdinal; // volume id
894 tagView(tagNumber*tagSize+2) = functionOrdinal; // local dof id
895 tagView(tagNumber*tagSize+3) = numFunctionsPerVolume; // total number of dofs in this volume
896 tagNumber++;
897 }
898 }
899 INTREPID2_TEST_FOR_EXCEPTION(tagNumber != this->basisCardinality_, std::invalid_argument, "Internal error: basis tag enumeration is incorrect");
900 }
901 } else {
902 for (ordinal_type i=0;i<cardinality;++i) {
903 tagView(i*tagSize+0) = volumeDim; // volume dimension
904 tagView(i*tagSize+1) = 0; // volume ordinal
905 tagView(i*tagSize+2) = i; // local dof id
906 tagView(i*tagSize+3) = cardinality; // total number of dofs on this face
907 }
908 }
909
910 // Basis-independent function sets tag and enum data in tagToOrdinal_ and ordinalToTag_ arrays:
911 // tags are constructed on host
913 this->ordinalToTag_,
914 tagView,
915 this->basisCardinality_,
916 tagSize,
917 posScDim,
918 posScOrd,
919 posDfOrd);
920 }
921 }
922
927 const char* getName() const override {
928 return "Intrepid2_IntegratedLegendreBasis_HGRAD_PYR";
929 }
930
933 virtual bool requireOrientation() const override {
934 return (this->getDegree() > 2);
935 }
936
937 // since the getValues() below only overrides the FEM variant, we specify that
938 // we use the base class's getValues(), which implements the FVD variant by throwing an exception.
939 // (It's an error to use the FVD variant on this basis.)
941
960 virtual void getValues( OutputViewType outputValues, const PointViewType inputPoints,
961 const EOperator operatorType = OPERATOR_VALUE ) const override
962 {
963 auto numPoints = inputPoints.extent_int(0);
964
966
967 FunctorType functor(operatorType, outputValues, inputPoints, polyOrder_, defineVertexFunctions);
968
969 const int outputVectorSize = getVectorSizeForHierarchicalParallelism<OutputScalar>();
970 const int pointVectorSize = getVectorSizeForHierarchicalParallelism<PointScalar>();
971 const int vectorSize = std::max(outputVectorSize,pointVectorSize);
972 const int teamSize = 1; // because of the way the basis functions are computed, we don't have a second level of parallelism...
973
974 auto policy = Kokkos::TeamPolicy<ExecutionSpace>(numPoints,teamSize,vectorSize);
975 Kokkos::parallel_for("Hierarchical_HGRAD_PYR_Functor", policy, functor);
976 }
977
987 getSubCellRefBasis(const ordinal_type subCellDim, const ordinal_type subCellOrd) const override{
990 using HGRAD_QUAD = Basis_Derived_HGRAD_QUAD<HGRAD_LINE>;
991 const auto & p = this->basisDegree_;
992 if(subCellDim == 1) // line basis
993 {
994 return Teuchos::rcp(new HGRAD_LINE(p));
995 }
996 else if (subCellDim == 2)
997 {
998 if (subCellOrd == 4) // quad basis
999 {
1000 return Teuchos::rcp(new HGRAD_QUAD(p));
1001 }
1002 else // tri basis
1003 {
1004 return Teuchos::rcp(new HGRAD_TRI(p));
1005 }
1006 }
1007 INTREPID2_TEST_FOR_EXCEPTION(true,std::invalid_argument,"Input parameters out of bounds");
1008 }
1009
1015 getHostBasis() const override {
1016 using HostDeviceType = typename Kokkos::HostSpace::device_type;
1018 return Teuchos::rcp( new HostBasisType(polyOrder_, pointType_) );
1019 }
1020 };
1021} // end namespace Intrepid2
1022
1023// do ETI with default (double) type
1025
1026#endif /* Intrepid2_IntegratedLegendreBasis_HGRAD_PYR_h */
Header file for the abstract base class Intrepid2::Basis.
Teuchos::RCP< Basis< DeviceType, OutputType, PointType > > BasisPtr
Basis Pointer.
Implementation of H(grad) basis on the quadrilateral that is templated on H(grad) on the line.
KOKKOS_INLINE_FUNCTION void device_assert(bool val)
H(grad) basis on the line based on integrated Legendre polynomials.
H(grad) basis on the triangle based on integrated Legendre polynomials.
Free functions, callable from device code, that implement various polynomials useful in basis definit...
Defines several coordinates and their gradients on the pyramid; maps from Intrepid2 (shards) pyramid ...
KOKKOS_INLINE_FUNCTION void affinePyramid(Kokkos::Array< PointScalar, 5 > &lambda, Kokkos::Array< Kokkos::Array< PointScalar, 3 >, 5 > &lambdaGrad, Kokkos::Array< Kokkos::Array< PointScalar, 3 >, 2 > &mu, Kokkos::Array< Kokkos::Array< Kokkos::Array< PointScalar, 3 >, 3 >, 2 > &muGrad, Kokkos::Array< Kokkos::Array< PointScalar, 2 >, 3 > &nu, Kokkos::Array< Kokkos::Array< Kokkos::Array< PointScalar, 3 >, 2 >, 3 > &nuGrad, Kokkos::Array< PointScalar, 3 > &coords)
Compute various affine-like coordinates on the pyramid. See Fuentes et al, Appendix E....
KOKKOS_INLINE_FUNCTION void transformFromESEASPyramidGradient(OutputScalar &dx_int2, OutputScalar &dy_int2, OutputScalar &dz_int2, const OutputScalar &dx_eseas, const OutputScalar &dy_eseas, const OutputScalar &dz_eseas)
Transforms gradients computed on the ESEAS pyramid to gradients on the Intrepid2 pyramid.
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.
shards::CellTopology getBaseCellTopology() const
Returns the base cell topology for which the basis is defined. See Shards documentation https://trili...
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.
Basis defining integrated Legendre basis on the line, a polynomial subspace of H(grad) on the line.
Basis defining integrated Legendre basis on the line, a polynomial subspace of H(grad) on the line.
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 bool requireOrientation() const override
True if orientation is required.
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...
virtual void getValues(OutputViewType outputValues, const PointViewType inputPoints, const EOperator operatorType=OPERATOR_VALUE) const override
Evaluation of a FEM basis on a reference cell.
IntegratedLegendreBasis_HGRAD_PYR(int polyOrder, const EPointType pointType=POINTTYPE_DEFAULT)
Constructor.
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 > OrdinalTypeArray2DHost
View type for 2d host array.
Kokkos::View< ordinal_type *, typename ExecutionSpace::array_layout, Kokkos::HostSpace > OrdinalTypeArray1DHost
View type for 1d host array.
Basis defining integrated Legendre basis on the line, a polynomial subspace of H(grad) on the line: e...
Functor for computing values for the IntegratedLegendreBasis_HGRAD_PYR class.