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