Intrepid2
Intrepid2_IntegratedLegendreBasis_HGRAD_TRI.hpp
Go to the documentation of this file.
1 // @HEADER
2 // *****************************************************************************
3 // Intrepid2 Package
4 //
5 // Copyright 2007 NTESS and the Intrepid2 contributors.
6 // SPDX-License-Identifier: BSD-3-Clause
7 // *****************************************************************************
8 // @HEADER
9 
15 #ifndef Intrepid2_IntegratedLegendreBasis_HGRAD_TRI_h
16 #define Intrepid2_IntegratedLegendreBasis_HGRAD_TRI_h
17 
18 #include <Kokkos_DynRankView.hpp>
19 
20 #include <Intrepid2_config.h>
21 
22 #include "Intrepid2_Basis.hpp"
25 #include "Intrepid2_Utils.hpp"
26 
27 namespace Intrepid2
28 {
34  template<class DeviceType, class OutputScalar, class PointScalar,
35  class OutputFieldType, class InputPointsType>
37  {
38  using ExecutionSpace = typename DeviceType::execution_space;
39  using ScratchSpace = typename ExecutionSpace::scratch_memory_space;
40  using OutputScratchView = Kokkos::View<OutputScalar*,ScratchSpace,Kokkos::MemoryTraits<Kokkos::Unmanaged>>;
41  using PointScratchView = Kokkos::View<PointScalar*, ScratchSpace,Kokkos::MemoryTraits<Kokkos::Unmanaged>>;
42 
43  using TeamPolicy = Kokkos::TeamPolicy<ExecutionSpace>;
44  using TeamMember = typename TeamPolicy::member_type;
45 
46  EOperator opType_;
47 
48  OutputFieldType output_; // F,P
49  InputPointsType inputPoints_; // P,D
50 
51  int polyOrder_;
52  bool defineVertexFunctions_;
53  int numFields_, numPoints_;
54 
55  size_t fad_size_output_;
56 
57  static const int numVertices = 3;
58  static const int numEdges = 3;
59  const int edge_start_[numEdges] = {0,1,0}; // edge i is from edge_start_[i] to edge_end_[i]
60  const int edge_end_[numEdges] = {1,2,2}; // edge i is from edge_start_[i] to edge_end_[i]
61 
62  Hierarchical_HGRAD_TRI_Functor(EOperator opType, OutputFieldType output, InputPointsType inputPoints,
63  int polyOrder, bool defineVertexFunctions)
64  : opType_(opType), output_(output), inputPoints_(inputPoints),
65  polyOrder_(polyOrder), defineVertexFunctions_(defineVertexFunctions),
66  fad_size_output_(getScalarDimensionForView(output))
67  {
68  numFields_ = output.extent_int(0);
69  numPoints_ = output.extent_int(1);
70  INTREPID2_TEST_FOR_EXCEPTION(numPoints_ != inputPoints.extent_int(0), std::invalid_argument, "point counts need to match!");
71  INTREPID2_TEST_FOR_EXCEPTION(numFields_ != (polyOrder_+1)*(polyOrder_+2)/2, std::invalid_argument, "output field size does not match basis cardinality");
72  }
73 
74  KOKKOS_INLINE_FUNCTION
75  void operator()( const TeamMember & teamMember ) const
76  {
77  auto pointOrdinal = teamMember.league_rank();
78  OutputScratchView edge_field_values_at_point, jacobi_values_at_point, other_values_at_point, other_values2_at_point;
79  if (fad_size_output_ > 0) {
80  edge_field_values_at_point = OutputScratchView(teamMember.team_shmem(), polyOrder_ + 1, fad_size_output_);
81  jacobi_values_at_point = OutputScratchView(teamMember.team_shmem(), polyOrder_ + 1, fad_size_output_);
82  other_values_at_point = OutputScratchView(teamMember.team_shmem(), polyOrder_ + 1, fad_size_output_);
83  other_values2_at_point = OutputScratchView(teamMember.team_shmem(), polyOrder_ + 1, fad_size_output_);
84  }
85  else {
86  edge_field_values_at_point = OutputScratchView(teamMember.team_shmem(), polyOrder_ + 1);
87  jacobi_values_at_point = OutputScratchView(teamMember.team_shmem(), polyOrder_ + 1);
88  other_values_at_point = OutputScratchView(teamMember.team_shmem(), polyOrder_ + 1);
89  other_values2_at_point = OutputScratchView(teamMember.team_shmem(), polyOrder_ + 1);
90  }
91 
92  const auto & x = inputPoints_(pointOrdinal,0);
93  const auto & y = inputPoints_(pointOrdinal,1);
94 
95  // write as barycentric coordinates:
96  const PointScalar lambda[3] = {1. - x - y, x, y};
97  const PointScalar lambda_dx[3] = {-1., 1., 0.};
98  const PointScalar lambda_dy[3] = {-1., 0., 1.};
99 
100  const int num1DEdgeFunctions = polyOrder_ - 1;
101 
102  switch (opType_)
103  {
104  case OPERATOR_VALUE:
105  {
106  // vertex functions come first, according to vertex ordering: (0,0), (1,0), (0,1)
107  for (int vertexOrdinal=0; vertexOrdinal<numVertices; vertexOrdinal++)
108  {
109  output_(vertexOrdinal,pointOrdinal) = lambda[vertexOrdinal];
110  }
111  if (!defineVertexFunctions_)
112  {
113  // "DG" basis case
114  // here, we overwrite the first vertex function with 1:
115  output_(0,pointOrdinal) = 1.0;
116  }
117 
118  // edge functions
119  int fieldOrdinalOffset = 3;
120  for (int edgeOrdinal=0; edgeOrdinal<numEdges; edgeOrdinal++)
121  {
122  const auto & s0 = lambda[edge_start_[edgeOrdinal]];
123  const auto & s1 = lambda[ edge_end_[edgeOrdinal]];
124 
125  Polynomials::shiftedScaledIntegratedLegendreValues(edge_field_values_at_point, polyOrder_, PointScalar(s1), PointScalar(s0+s1));
126  for (int edgeFunctionOrdinal=0; edgeFunctionOrdinal<num1DEdgeFunctions; edgeFunctionOrdinal++)
127  {
128  // the first two integrated legendre functions are essentially the vertex functions; hence the +2 on on the RHS here:
129  output_(edgeFunctionOrdinal+fieldOrdinalOffset,pointOrdinal) = edge_field_values_at_point(edgeFunctionOrdinal+2);
130  }
131  fieldOrdinalOffset += num1DEdgeFunctions;
132  }
133 
134  // face functions
135  {
136  // these functions multiply the edge functions from the 01 edge by integrated Jacobi functions, appropriately scaled
137  const double jacobiScaling = 1.0; // s0 + s1 + s2
138 
139  const int max_ij_sum = polyOrder_;
140  const int min_i = 2;
141  const int min_j = 1;
142  const int min_ij_sum = min_i + min_j;
143  for (int ij_sum = min_ij_sum; ij_sum <= max_ij_sum; ij_sum++)
144  {
145  for (int i=min_i; i<=ij_sum-min_j; i++)
146  {
147  const int j = ij_sum - i;
148  const int edgeBasisOrdinal = i+numVertices-2; // i+1: where the value of the edge function is stored in output_
149  const auto & edgeValue = output_(edgeBasisOrdinal,pointOrdinal);
150  const double alpha = i*2.0;
151 
152  Polynomials::shiftedScaledIntegratedJacobiValues(jacobi_values_at_point, alpha, polyOrder_-2, lambda[2], jacobiScaling);
153  const auto & jacobiValue = jacobi_values_at_point(j);
154  output_(fieldOrdinalOffset,pointOrdinal) = edgeValue * jacobiValue;
155  fieldOrdinalOffset++;
156  }
157  }
158  }
159  } // end OPERATOR_VALUE
160  break;
161  case OPERATOR_GRAD:
162  case OPERATOR_D1:
163  {
164  // vertex functions
165  if (defineVertexFunctions_)
166  {
167  // standard, "CG" basis case
168  // first vertex function is 1-x-y
169  output_(0,pointOrdinal,0) = -1.0;
170  output_(0,pointOrdinal,1) = -1.0;
171  }
172  else
173  {
174  // "DG" basis case
175  // here, the first "vertex" function is 1, so the derivative is 0:
176  output_(0,pointOrdinal,0) = 0.0;
177  output_(0,pointOrdinal,1) = 0.0;
178  }
179  // second vertex function is x
180  output_(1,pointOrdinal,0) = 1.0;
181  output_(1,pointOrdinal,1) = 0.0;
182  // third vertex function is y
183  output_(2,pointOrdinal,0) = 0.0;
184  output_(2,pointOrdinal,1) = 1.0;
185 
186  // edge functions
187  int fieldOrdinalOffset = 3;
188  /*
189  Per Fuentes et al. (see Appendix E.1, E.2), the edge functions, defined for i ≥ 2, are
190  [L_i](s0,s1) = L_i(s1; s0+s1)
191  and have gradients:
192  grad [L_i](s0,s1) = [P_{i-1}](s0,s1) grad s1 + [R_{i-1}](s0,s1) grad (s0 + s1)
193  where
194  [R_{i-1}](s0,s1) = R_{i-1}(s1; s0+s1) = d/dt L_{i}(s0; s0+s1)
195  The P_i we have implemented in shiftedScaledLegendreValues, while d/dt L_{i+1} is
196  implemented in shiftedScaledIntegratedLegendreValues_dt.
197  */
198  // rename the scratch memory to match our usage here:
199  auto & P_i_minus_1 = edge_field_values_at_point;
200  auto & L_i_dt = jacobi_values_at_point;
201  for (int edgeOrdinal=0; edgeOrdinal<numEdges; edgeOrdinal++)
202  {
203  const auto & s0 = lambda[edge_start_[edgeOrdinal]];
204  const auto & s1 = lambda[ edge_end_[edgeOrdinal]];
205 
206  const auto & s0_dx = lambda_dx[edge_start_[edgeOrdinal]];
207  const auto & s0_dy = lambda_dy[edge_start_[edgeOrdinal]];
208  const auto & s1_dx = lambda_dx[ edge_end_[edgeOrdinal]];
209  const auto & s1_dy = lambda_dy[ edge_end_[edgeOrdinal]];
210 
211  Polynomials::shiftedScaledLegendreValues (P_i_minus_1, polyOrder_-1, PointScalar(s1), PointScalar(s0+s1));
212  Polynomials::shiftedScaledIntegratedLegendreValues_dt(L_i_dt, polyOrder_, PointScalar(s1), PointScalar(s0+s1));
213  for (int edgeFunctionOrdinal=0; edgeFunctionOrdinal<num1DEdgeFunctions; edgeFunctionOrdinal++)
214  {
215  // the first two (integrated) Legendre functions are essentially the vertex functions; hence the +2 here:
216  const int i = edgeFunctionOrdinal+2;
217  output_(edgeFunctionOrdinal+fieldOrdinalOffset,pointOrdinal,0) = P_i_minus_1(i-1) * s1_dx + L_i_dt(i) * (s1_dx + s0_dx);
218  output_(edgeFunctionOrdinal+fieldOrdinalOffset,pointOrdinal,1) = P_i_minus_1(i-1) * s1_dy + L_i_dt(i) * (s1_dy + s0_dy);
219  }
220  fieldOrdinalOffset += num1DEdgeFunctions;
221  }
222 
223  /*
224  Fuentes et al give the face functions as phi_{ij}, with gradient:
225  grad phi_{ij}(s0,s1,s2) = [L^{2i}_j](s0+s1,s2) grad [L_i](s0,s1) + [L_i](s0,s1) grad [L^{2i}_j](s0+s1,s2)
226  where:
227  - grad [L_i](s0,s1) is the edge function gradient we computed above
228  - [L_i](s0,s1) is the edge function which we have implemented above (in OPERATOR_VALUE)
229  - L^{2i}_j is a Jacobi polynomial with:
230  [L^{2i}_j](s0,s1) = L^{2i}_j(s1;s0+s1)
231  and the gradient for j ≥ 1 is
232  grad [L^{2i}_j](s0,s1) = [P^{2i}_{j-1}](s0,s1) grad s1 + [R^{2i}_{j-1}(s0,s1)] grad (s0 + s1)
233  Here,
234  [P^{2i}_{j-1}](s0,s1) = P^{2i}_{j-1}(s1,s0+s1)
235  and
236  [R^{2i}_{j-1}(s0,s1)] = d/dt L^{2i}_j(s1,s0+s1)
237  We have implemented P^{alpha}_{j} as shiftedScaledJacobiValues,
238  and d/dt L^{alpha}_{j} as shiftedScaledIntegratedJacobiValues_dt.
239  */
240  // rename the scratch memory to match our usage here:
241  auto & P_2i_j_minus_1 = edge_field_values_at_point;
242  auto & L_2i_j_dt = jacobi_values_at_point;
243  auto & L_i = other_values_at_point;
244  auto & L_2i_j = other_values2_at_point;
245  {
246  // face functions multiply the edge functions from the 01 edge by integrated Jacobi functions, appropriately scaled
247  const double jacobiScaling = 1.0; // s0 + s1 + s2
248 
249  const int max_ij_sum = polyOrder_;
250  const int min_i = 2;
251  const int min_j = 1;
252  const int min_ij_sum = min_i + min_j;
253  for (int ij_sum = min_ij_sum; ij_sum <= max_ij_sum; ij_sum++)
254  {
255  for (int i=min_i; i<=ij_sum-min_j; i++)
256  {
257  const int j = ij_sum - i;
258  // the edge function here is for edge 01, in the first set of edge functions.
259  const int edgeBasisOrdinal = i+numVertices-2; // i+1: where the value of the edge function is stored in output_
260  const auto & grad_L_i_dx = output_(edgeBasisOrdinal,pointOrdinal,0);
261  const auto & grad_L_i_dy = output_(edgeBasisOrdinal,pointOrdinal,1);
262 
263  const double alpha = i*2.0;
264 
265  Polynomials::shiftedScaledIntegratedLegendreValues (L_i, polyOrder_, lambda[1], lambda[0]+lambda[1]);
266  Polynomials::shiftedScaledIntegratedJacobiValues_dt(L_2i_j_dt, alpha, polyOrder_, lambda[2], jacobiScaling);
267  Polynomials::shiftedScaledIntegratedJacobiValues ( L_2i_j, alpha, polyOrder_, lambda[2], jacobiScaling);
268  Polynomials::shiftedScaledJacobiValues(P_2i_j_minus_1, alpha, polyOrder_-1, lambda[2], jacobiScaling);
269 
270  const auto & s0_dx = lambda_dx[0];
271  const auto & s0_dy = lambda_dy[0];
272  const auto & s1_dx = lambda_dx[1];
273  const auto & s1_dy = lambda_dy[1];
274  const auto & s2_dx = lambda_dx[2];
275  const auto & s2_dy = lambda_dy[2];
276 
277  const OutputScalar basisValue_dx = L_2i_j(j) * grad_L_i_dx + L_i(i) * (P_2i_j_minus_1(j-1) * s2_dx + L_2i_j_dt(j) * (s0_dx + s1_dx + s2_dx));
278  const OutputScalar basisValue_dy = L_2i_j(j) * grad_L_i_dy + L_i(i) * (P_2i_j_minus_1(j-1) * s2_dy + L_2i_j_dt(j) * (s0_dy + s1_dy + s2_dy));
279 
280  output_(fieldOrdinalOffset,pointOrdinal,0) = basisValue_dx;
281  output_(fieldOrdinalOffset,pointOrdinal,1) = basisValue_dy;
282  fieldOrdinalOffset++;
283  }
284  }
285  }
286  }
287  break;
288  case OPERATOR_D2:
289  case OPERATOR_D3:
290  case OPERATOR_D4:
291  case OPERATOR_D5:
292  case OPERATOR_D6:
293  case OPERATOR_D7:
294  case OPERATOR_D8:
295  case OPERATOR_D9:
296  case OPERATOR_D10:
297  INTREPID2_TEST_FOR_ABORT( true,
298  ">>> ERROR: (Intrepid2::Basis_HGRAD_TRI_Cn_FEM_ORTH::OrthPolynomialTri) Computing of second and higher-order derivatives is not currently supported");
299  default:
300  // unsupported operator type
301  device_assert(false);
302  }
303  }
304 
305  // Provide the shared memory capacity.
306  // This function takes the team_size as an argument,
307  // which allows team_size-dependent allocations.
308  size_t team_shmem_size (int team_size) const
309  {
310  // we will use shared memory to create a fast buffer for basis computations
311  size_t shmem_size = 0;
312  if (fad_size_output_ > 0)
313  shmem_size += 4 * OutputScratchView::shmem_size(polyOrder_ + 1, fad_size_output_);
314  else
315  shmem_size += 4 * OutputScratchView::shmem_size(polyOrder_ + 1);
316 
317  return shmem_size;
318  }
319  };
320 
337  template<typename DeviceType,
338  typename OutputScalar = double,
339  typename PointScalar = double,
340  bool defineVertexFunctions = true> // if defineVertexFunctions is true, first three basis functions are 1-x-y, x, and y. Otherwise, they are 1, x, and y.
342  : public Basis<DeviceType,OutputScalar,PointScalar>
343  {
344  public:
347 
348  using typename BasisBase::OrdinalTypeArray1DHost;
349  using typename BasisBase::OrdinalTypeArray2DHost;
350 
351  using typename BasisBase::OutputViewType;
352  using typename BasisBase::PointViewType;
353  using typename BasisBase::ScalarViewType;
354 
355  using typename BasisBase::ExecutionSpace;
356 
357  protected:
358  int polyOrder_; // the maximum order of the polynomial
359  EPointType pointType_;
360  public:
371  IntegratedLegendreBasis_HGRAD_TRI(int polyOrder, const EPointType pointType=POINTTYPE_DEFAULT)
372  :
373  polyOrder_(polyOrder),
374  pointType_(pointType)
375  {
376  INTREPID2_TEST_FOR_EXCEPTION(pointType!=POINTTYPE_DEFAULT,std::invalid_argument,"PointType not supported");
377 
378  this->basisCardinality_ = ((polyOrder+2) * (polyOrder+1)) / 2;
379  this->basisDegree_ = polyOrder;
380  this->basisCellTopologyKey_ = shards::Triangle<>::key;
381  this->basisType_ = BASIS_FEM_HIERARCHICAL;
382  this->basisCoordinates_ = COORDINATES_CARTESIAN;
383  this->functionSpace_ = FUNCTION_SPACE_HGRAD;
384 
385  const int degreeLength = 1;
386  this->fieldOrdinalPolynomialDegree_ = OrdinalTypeArray2DHost("Integrated Legendre H(grad) triangle polynomial degree lookup", this->basisCardinality_, degreeLength);
387  this->fieldOrdinalH1PolynomialDegree_ = OrdinalTypeArray2DHost("Integrated Legendre H(grad) triangle polynomial degree lookup", this->basisCardinality_, degreeLength);
388 
389  int fieldOrdinalOffset = 0;
390  // **** vertex functions **** //
391  const int numVertices = this->getBaseCellTopology().getVertexCount();
392  const int numFunctionsPerVertex = 1;
393  const int numVertexFunctions = numVertices * numFunctionsPerVertex;
394  for (int i=0; i<numVertexFunctions; i++)
395  {
396  // for H(grad) on triangle, if defineVertexFunctions is false, first three basis members are linear
397  // if not, then the only difference is that the first member is constant
398  this->fieldOrdinalPolynomialDegree_ (i,0) = 1;
399  this->fieldOrdinalH1PolynomialDegree_(i,0) = 1;
400  }
401  if (!defineVertexFunctions)
402  {
403  this->fieldOrdinalPolynomialDegree_ (0,0) = 0;
404  this->fieldOrdinalH1PolynomialDegree_(0,0) = 0;
405  }
406  fieldOrdinalOffset += numVertexFunctions;
407 
408  // **** edge functions **** //
409  const int numFunctionsPerEdge = polyOrder - 1; // bubble functions: all but the vertices
410  const int numEdges = this->getBaseCellTopology().getEdgeCount();
411  for (int edgeOrdinal=0; edgeOrdinal<numEdges; edgeOrdinal++)
412  {
413  for (int i=0; i<numFunctionsPerEdge; i++)
414  {
415  this->fieldOrdinalPolynomialDegree_(i+fieldOrdinalOffset,0) = i+2; // vertex functions are 1st order; edge functions start at order 2
416  this->fieldOrdinalH1PolynomialDegree_(i+fieldOrdinalOffset,0) = i+2; // vertex functions are 1st order; edge functions start at order 2
417  }
418  fieldOrdinalOffset += numFunctionsPerEdge;
419  }
420 
421  // **** face functions **** //
422  const int max_ij_sum = polyOrder;
423  const int min_i = 2;
424  const int min_j = 1;
425  const int min_ij_sum = min_i + min_j;
426  for (int ij_sum = min_ij_sum; ij_sum <= max_ij_sum; ij_sum++)
427  {
428  for (int i=min_i; i<=ij_sum-min_j; i++)
429  {
430  const int j = ij_sum - i;
431  this->fieldOrdinalPolynomialDegree_(fieldOrdinalOffset,0) = i+j;
432  this->fieldOrdinalH1PolynomialDegree_(fieldOrdinalOffset,0) = i+j;
433  fieldOrdinalOffset++;
434  }
435  }
436  const int numFaces = 1;
437  const int numFunctionsPerFace = ((polyOrder-1)*(polyOrder-2))/2;
438  INTREPID2_TEST_FOR_EXCEPTION(fieldOrdinalOffset != this->basisCardinality_, std::invalid_argument, "Internal error: basis enumeration is incorrect");
439 
440  // initialize tags
441  {
442  const auto & cardinality = this->basisCardinality_;
443 
444  // Basis-dependent initializations
445  const ordinal_type tagSize = 4; // size of DoF tag, i.e., number of fields in the tag
446  const ordinal_type posScDim = 0; // position in the tag, counting from 0, of the subcell dim
447  const ordinal_type posScOrd = 1; // position in the tag, counting from 0, of the subcell ordinal
448  const ordinal_type posDfOrd = 2; // position in the tag, counting from 0, of DoF ordinal relative to the subcell
449 
450  OrdinalTypeArray1DHost tagView("tag view", cardinality*tagSize);
451  const int vertexDim = 0, edgeDim = 1, faceDim = 2;
452 
453  if (defineVertexFunctions) {
454  {
455  int tagNumber = 0;
456  for (int vertexOrdinal=0; vertexOrdinal<numVertices; vertexOrdinal++)
457  {
458  for (int functionOrdinal=0; functionOrdinal<numFunctionsPerVertex; functionOrdinal++)
459  {
460  tagView(tagNumber*tagSize+0) = vertexDim; // vertex dimension
461  tagView(tagNumber*tagSize+1) = vertexOrdinal; // vertex id
462  tagView(tagNumber*tagSize+2) = functionOrdinal; // local dof id
463  tagView(tagNumber*tagSize+3) = numFunctionsPerVertex; // total number of dofs in this vertex
464  tagNumber++;
465  }
466  }
467  for (int edgeOrdinal=0; edgeOrdinal<numEdges; edgeOrdinal++)
468  {
469  for (int functionOrdinal=0; functionOrdinal<numFunctionsPerEdge; functionOrdinal++)
470  {
471  tagView(tagNumber*tagSize+0) = edgeDim; // edge dimension
472  tagView(tagNumber*tagSize+1) = edgeOrdinal; // edge id
473  tagView(tagNumber*tagSize+2) = functionOrdinal; // local dof id
474  tagView(tagNumber*tagSize+3) = numFunctionsPerEdge; // total number of dofs on this edge
475  tagNumber++;
476  }
477  }
478  for (int faceOrdinal=0; faceOrdinal<numFaces; faceOrdinal++)
479  {
480  for (int functionOrdinal=0; functionOrdinal<numFunctionsPerFace; functionOrdinal++)
481  {
482  tagView(tagNumber*tagSize+0) = faceDim; // face dimension
483  tagView(tagNumber*tagSize+1) = faceOrdinal; // face id
484  tagView(tagNumber*tagSize+2) = functionOrdinal; // local dof id
485  tagView(tagNumber*tagSize+3) = numFunctionsPerFace; // total number of dofs on this face
486  tagNumber++;
487  }
488  }
489  }
490  } else {
491  for (ordinal_type i=0;i<cardinality;++i) {
492  tagView(i*tagSize+0) = faceDim; // face dimension
493  tagView(i*tagSize+1) = 0; // face id
494  tagView(i*tagSize+2) = i; // local dof id
495  tagView(i*tagSize+3) = cardinality; // total number of dofs on this face
496  }
497  }
498 
499  // Basis-independent function sets tag and enum data in tagToOrdinal_ and ordinalToTag_ arrays:
500  // tags are constructed on host
501  this->setOrdinalTagData(this->tagToOrdinal_,
502  this->ordinalToTag_,
503  tagView,
504  this->basisCardinality_,
505  tagSize,
506  posScDim,
507  posScOrd,
508  posDfOrd);
509  }
510  }
511 
516  const char* getName() const override {
517  return "Intrepid2_IntegratedLegendreBasis_HGRAD_TRI";
518  }
519 
522  virtual bool requireOrientation() const override {
523  return (this->getDegree() > 2);
524  }
525 
526  // since the getValues() below only overrides the FEM variant, we specify that
527  // we use the base class's getValues(), which implements the FVD variant by throwing an exception.
528  // (It's an error to use the FVD variant on this basis.)
529  using BasisBase::getValues;
530 
549  virtual void getValues( OutputViewType outputValues, const PointViewType inputPoints,
550  const EOperator operatorType = OPERATOR_VALUE ) const override
551  {
552  auto numPoints = inputPoints.extent_int(0);
553 
555 
556  FunctorType functor(operatorType, outputValues, inputPoints, polyOrder_, defineVertexFunctions);
557 
558  const int outputVectorSize = getVectorSizeForHierarchicalParallelism<OutputScalar>();
559  const int pointVectorSize = getVectorSizeForHierarchicalParallelism<PointScalar>();
560  const int vectorSize = std::max(outputVectorSize,pointVectorSize);
561  const int teamSize = 1; // because of the way the basis functions are computed, we don't have a second level of parallelism...
562 
563  auto policy = Kokkos::TeamPolicy<ExecutionSpace>(numPoints,teamSize,vectorSize);
564  Kokkos::parallel_for("Hierarchical_HGRAD_TRI_Functor", policy, functor);
565  }
566 
575  BasisPtr<DeviceType,OutputScalar,PointScalar>
576  getSubCellRefBasis(const ordinal_type subCellDim, const ordinal_type subCellOrd) const override{
577  if(subCellDim == 1) {
578  return Teuchos::rcp(new
580  (this->basisDegree_));
581  }
582  INTREPID2_TEST_FOR_EXCEPTION(true,std::invalid_argument,"Input parameters out of bounds");
583  }
584 
589  virtual BasisPtr<typename Kokkos::HostSpace::device_type, OutputScalar, PointScalar>
590  getHostBasis() const override {
591  using HostDeviceType = typename Kokkos::HostSpace::device_type;
593  return Teuchos::rcp( new HostBasisType(polyOrder_, pointType_) );
594  }
595  };
596 } // end namespace Intrepid2
597 
598 #endif /* Intrepid2_IntegratedLegendreBasis_HGRAD_TRI_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.
virtual bool requireOrientation() const override
True if orientation is required.
unsigned basisCellTopologyKey_
Identifier of the base topology of the cells for which the basis is defined. See the Shards package f...
Kokkos::View< ordinal_type *, typename ExecutionSpace::array_layout, Kokkos::HostSpace > OrdinalTypeArray1DHost
View type for 1d host array.
IntegratedLegendreBasis_HGRAD_TRI(int polyOrder, const EPointType pointType=POINTTYPE_DEFAULT)
Constructor.
An abstract base class that defines interface for concrete basis implementations for Finite Element (...
shards::CellTopology getBaseCellTopology() const
Returns the base cell topology for which the basis is defined. See Shards documentation https://trili...
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< 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.
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::DynRankView< OutputValueType, Kokkos::LayoutStride, DeviceType > OutputViewType
View type for basis value output.
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...
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_TRI class.
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. ...
OrdinalTypeArray3DHost tagToOrdinal_
DoF tag to ordinal lookup table.
Kokkos::DynRankView< OutputValueType, Kokkos::LayoutStride, DeviceType > OutputViewType
View type for basis value output.
OrdinalTypeArray2DHost ordinalToTag_
&quot;true&quot; if tagToOrdinal_ and ordinalToTag_ have been initialized
ordinal_type getDegree() const
Returns the degree of the basis.
ECoordinates basisCoordinates_
The coordinate system for which the basis is defined.
OrdinalTypeArray2DHost fieldOrdinalH1PolynomialDegree_
H^1 polynomial degree for each degree of freedom. Only defined for hierarchical bases right now...
OrdinalTypeArray2DHost fieldOrdinalPolynomialDegree_
Polynomial degree for each degree of freedom. Only defined for hierarchical bases right now...
void setOrdinalTagData(OrdinalTypeView3D &tagToOrdinal, OrdinalTypeView2D &ordinalToTag, const OrdinalTypeView1D tags, const ordinal_type basisCard, const ordinal_type tagSize, const ordinal_type posScDim, const ordinal_type posScOrd, const ordinal_type posDfOrd)
Fills ordinalToTag_ and tagToOrdinal_ by basis-specific tag data.
Kokkos::DynRankView< PointValueType, Kokkos::LayoutStride, DeviceType > PointViewType
View type for input points.
Kokkos::DynRankView< PointValueType, Kokkos::LayoutStride, DeviceType > PointViewType
View type for input points.
Header file for the abstract base class Intrepid2::Basis.
typename DeviceType::execution_space ExecutionSpace
(Kokkos) Execution space for basis.