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 
38 namespace 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 
675  using typename BasisBase::OrdinalTypeArray1DHost;
676  using typename BasisBase::OrdinalTypeArray2DHost;
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
912  this->setOrdinalTagData(this->tagToOrdinal_,
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.)
940  using BasisBase::getValues;
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 
986  BasisPtr<DeviceType,OutputScalar,PointScalar>
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 
1014  virtual BasisPtr<typename Kokkos::HostSpace::device_type, OutputScalar, PointScalar>
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 */
H(grad) basis on the line based on integrated Legendre polynomials.
Kokkos::View< ordinal_type *, typename ExecutionSpace::array_layout, Kokkos::HostSpace > OrdinalTypeArray1DHost
View type for 1d host array.
unsigned basisCellTopologyKey_
Identifier of the base topology of the cells for which the basis is defined. See the Shards package f...
Basis defining integrated Legendre basis on the line, a polynomial subspace of H(grad) on the line...
Defines several coordinates and their gradients on the pyramid; maps from Intrepid2 (shards) pyramid ...
An abstract base class that defines interface for concrete basis implementations for Finite Element (...
Kokkos::View< ordinal_type *, typename ExecutionSpace::array_layout, Kokkos::HostSpace > OrdinalTypeArray1DHost
View type for 1d host array.
shards::CellTopology getBaseCellTopology() const
Returns the base cell topology for which the basis is defined. See Shards documentation https://trili...
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...
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.
Implementation of H(grad) basis on the quadrilateral that is templated on H(grad) on the line...
Kokkos::View< ordinal_type **, typename ExecutionSpace::array_layout, Kokkos::HostSpace > OrdinalTypeArray2DHost
View type for 2d host array.
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...
IntegratedLegendreBasis_HGRAD_PYR(int polyOrder, const EPointType pointType=POINTTYPE_DEFAULT)
Constructor.
Kokkos::DynRankView< OutputValueType, Kokkos::LayoutStride, DeviceType > OutputViewType
View type for basis value output.
Basis defining integrated Legendre basis on the line, a polynomial subspace of H(grad) on the line: e...
Basis defining integrated Legendre basis on the line, a polynomial subspace of H(grad) on the line...
ordinal_type basisCardinality_
Cardinality of the basis, i.e., the number of basis functions/degrees-of-freedom. ...
BasisPtr< DeviceType, OutputScalar, PointScalar > getSubCellRefBasis(const ordinal_type subCellDim, const ordinal_type subCellOrd) const override
returns the basis associated to a subCell.
H(grad) basis on the triangle based on integrated Legendre polynomials.
OrdinalTypeArray3DHost tagToOrdinal_
DoF tag to ordinal lookup table.
OrdinalTypeArray2DHost ordinalToTag_
&quot;true&quot; if tagToOrdinal_ and ordinalToTag_ have been initialized
Kokkos::DynRankView< OutputValueType, Kokkos::LayoutStride, DeviceType > OutputViewType
View type for basis value output.
ordinal_type getDegree() const
Returns the degree of the basis.
ECoordinates basisCoordinates_
The coordinate system for which the basis is defined.
OrdinalTypeArray2DHost fieldOrdinalH1PolynomialDegree_
H^1 polynomial degree for each degree of freedom. Only defined for hierarchical bases right now...
Functor for computing values for the IntegratedLegendreBasis_HGRAD_PYR class.
OrdinalTypeArray2DHost fieldOrdinalPolynomialDegree_
Polynomial degree for each degree of freedom. Only defined for hierarchical bases right now...
virtual void getValues(OutputViewType outputValues, const PointViewType inputPoints, const EOperator operatorType=OPERATOR_VALUE) const override
Evaluation of a FEM basis on a reference cell.
void setOrdinalTagData(OrdinalTypeView3D &tagToOrdinal, OrdinalTypeView2D &ordinalToTag, const OrdinalTypeView1D tags, const ordinal_type basisCard, const ordinal_type tagSize, const ordinal_type posScDim, const ordinal_type posScOrd, const ordinal_type posDfOrd)
Fills ordinalToTag_ and tagToOrdinal_ by basis-specific tag data.
Kokkos::DynRankView< PointValueType, Kokkos::LayoutStride, DeviceType > PointViewType
View type for input points.
Header file for the abstract base class Intrepid2::Basis.
virtual bool requireOrientation() const override
True if orientation is required.
typename DeviceType::execution_space ExecutionSpace
(Kokkos) Execution space for basis.
Kokkos::DynRankView< PointValueType, Kokkos::LayoutStride, DeviceType > PointViewType
View type for input points.