Intrepid2
Intrepid2_HGRAD_TET_Cn_FEMDef.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 
16 #ifndef __INTREPID2_HGRAD_TET_CN_FEM_DEF_HPP__
17 #define __INTREPID2_HGRAD_TET_CN_FEM_DEF_HPP__
18 
21 
22 namespace Intrepid2 {
23 
24 // -------------------------------------------------------------------------------------
25 namespace Impl {
26 
27 template<EOperator OpType>
28 template<typename OutputViewType,
29 typename InputViewType,
30 typename WorkViewType,
31 typename VinvViewType>
32 KOKKOS_INLINE_FUNCTION
33 void
34 Basis_HGRAD_TET_Cn_FEM::Serial<OpType>::
35 getValues( OutputViewType output,
36  const InputViewType input,
37  WorkViewType work,
38  const VinvViewType vinv,
39  const ordinal_type order ) {
40 
41  constexpr ordinal_type spaceDim = 3;
42  const ordinal_type
43  card = vinv.extent(0),
44  npts = input.extent(0);
45 
46  typedef typename Kokkos::DynRankView<typename InputViewType::value_type, typename WorkViewType::memory_space> ViewType;
47  auto vcprop = Kokkos::common_view_alloc_prop(input);
48  auto ptr = work.data();
49 
50  switch (OpType) {
51  case OPERATOR_VALUE: {
52  const ViewType phis(Kokkos::view_wrap(ptr, vcprop), card, npts);
53  ViewType dummyView;
54 
55  Impl::Basis_HGRAD_TET_Cn_FEM_ORTH::
56  Serial<OpType>::getValues(phis, input, dummyView, order);
57 
58  for (ordinal_type i=0;i<card;++i)
59  for (ordinal_type j=0;j<npts;++j) {
60  output.access(i,j) = 0.0;
61  for (ordinal_type k=0;k<card;++k)
62  output.access(i,j) += vinv(k,i)*phis.access(k,j);
63  }
64  break;
65  }
66  case OPERATOR_GRAD:
67  case OPERATOR_D1: {
68  const ViewType phis(Kokkos::view_wrap(ptr, vcprop), card, npts, spaceDim);
69  ptr += card*npts*spaceDim*get_dimension_scalar(input);
70  const ViewType workView(Kokkos::view_wrap(ptr, vcprop), card, npts, spaceDim+1);
71  Impl::Basis_HGRAD_TET_Cn_FEM_ORTH::
72  Serial<OpType>::getValues(phis, input, workView, order);
73 
74  for (ordinal_type i=0;i<card;++i)
75  for (ordinal_type j=0;j<npts;++j)
76  for (ordinal_type k=0;k<spaceDim;++k) {
77  output.access(i,j,k) = 0.0;
78  for (ordinal_type l=0;l<card;++l)
79  output.access(i,j,k) += vinv(l,i)*phis.access(l,j,k);
80  }
81  break;
82  }
83  case OPERATOR_D2:
84  case OPERATOR_D3:
85  case OPERATOR_D4:
86  case OPERATOR_D5:
87  case OPERATOR_D6:
88  case OPERATOR_D7:
89  case OPERATOR_D8:
90  case OPERATOR_D9:
91  case OPERATOR_D10: {
92  const ordinal_type dkcard = getDkCardinality<OpType,spaceDim>(); //(orDn + 1);
93  const ViewType phis(Kokkos::view_wrap(ptr, vcprop), card, npts, dkcard);
94  ViewType dummyView;
95 
96  Impl::Basis_HGRAD_TET_Cn_FEM_ORTH::
97  Serial<OpType>::getValues(phis, input, dummyView, order);
98 
99  for (ordinal_type i=0;i<card;++i)
100  for (ordinal_type j=0;j<npts;++j)
101  for (ordinal_type k=0;k<dkcard;++k) {
102  output.access(i,j,k) = 0.0;
103  for (ordinal_type l=0;l<card;++l)
104  output.access(i,j,k) += vinv(l,i)*phis.access(l,j,k);
105  }
106  break;
107  }
108  default: {
109  INTREPID2_TEST_FOR_ABORT( true,
110  ">>> ERROR (Basis_HGRAD_TET_Cn_FEM): Operator type not implemented");
111  }
112  }
113 }
114 
115 template<typename DT, ordinal_type numPtsPerEval,
116 typename outputValueValueType, class ...outputValueProperties,
117 typename inputPointValueType, class ...inputPointProperties,
118 typename vinvValueType, class ...vinvProperties>
119 void
120 Basis_HGRAD_TET_Cn_FEM::
121 getValues(
122  const typename DT::execution_space& space,
123  Kokkos::DynRankView<outputValueValueType,outputValueProperties...> outputValues,
124  const Kokkos::DynRankView<inputPointValueType, inputPointProperties...> inputPoints,
125  const Kokkos::DynRankView<vinvValueType, vinvProperties...> vinv,
126  const ordinal_type order,
127  const EOperator operatorType) {
128  typedef Kokkos::DynRankView<outputValueValueType,outputValueProperties...> outputValueViewType;
129  typedef Kokkos::DynRankView<inputPointValueType, inputPointProperties...> inputPointViewType;
130  typedef Kokkos::DynRankView<vinvValueType, vinvProperties...> vinvViewType;
131  typedef typename ExecSpace<typename inputPointViewType::execution_space,typename DT::execution_space>::ExecSpaceType ExecSpaceType;
132 
133  // loopSize corresponds to cardinality
134  const auto loopSizeTmp1 = (inputPoints.extent(0)/numPtsPerEval);
135  const auto loopSizeTmp2 = (inputPoints.extent(0)%numPtsPerEval != 0);
136  const auto loopSize = loopSizeTmp1 + loopSizeTmp2;
137  Kokkos::RangePolicy<ExecSpaceType,Kokkos::Schedule<Kokkos::Static> > policy(space, 0, loopSize);
138 
139  typedef typename inputPointViewType::value_type inputPointType;
140 
141  const ordinal_type cardinality = outputValues.extent(0);
142  const ordinal_type spaceDim = 3;
143 
144  auto vcprop = Kokkos::common_view_alloc_prop(inputPoints);
145  typedef typename Kokkos::DynRankView< inputPointType, typename inputPointViewType::memory_space> workViewType;
146 
147  switch (operatorType) {
148  case OPERATOR_VALUE: {
149  workViewType work(Kokkos::view_alloc(space, "Basis_HGRAD_TET_Cn_FEM::getValues::work", vcprop), cardinality, inputPoints.extent(0));
150  typedef Functor<outputValueViewType,inputPointViewType,vinvViewType, workViewType,
151  OPERATOR_VALUE,numPtsPerEval> FunctorType;
152  Kokkos::parallel_for( policy, FunctorType(outputValues, inputPoints, vinv, work, order) );
153  break;
154  }
155  case OPERATOR_GRAD:
156  case OPERATOR_D1: {
157  workViewType work(Kokkos::view_alloc(space, "Basis_HGRAD_TET_Cn_FEM::getValues::work", vcprop), cardinality*(2*spaceDim+1), inputPoints.extent(0));
158  typedef Functor<outputValueViewType,inputPointViewType,vinvViewType, workViewType,
159  OPERATOR_D1,numPtsPerEval> FunctorType;
160  Kokkos::parallel_for( policy, FunctorType(outputValues, inputPoints, vinv, work, order) );
161  break;
162  }
163  case OPERATOR_D2: {
164  typedef Functor<outputValueViewType,inputPointViewType,vinvViewType, workViewType,
165  OPERATOR_D2,numPtsPerEval> FunctorType;
166  workViewType work(Kokkos::view_alloc(space, "Basis_HGRAD_TET_Cn_FEM::getValues::work", vcprop), cardinality*outputValues.extent(2), inputPoints.extent(0));
167  Kokkos::parallel_for( policy, FunctorType(outputValues, inputPoints, vinv, work, order) );
168  break;
169  }
170  default: {
171  INTREPID2_TEST_FOR_EXCEPTION( true , std::invalid_argument,
172  ">>> ERROR (Basis_HGRAD_TET_Cn_FEM): Operator type not implemented" );
173  }
174  }
175 }
176 }
177 
178 // -------------------------------------------------------------------------------------
179 template<typename DT, typename OT, typename PT>
181 Basis_HGRAD_TET_Cn_FEM( const ordinal_type order,
182  const EPointType pointType ) {
183  constexpr ordinal_type spaceDim = 3;
184 
185  this->basisCardinality_ = Intrepid2::getPnCardinality<spaceDim>(order); // bigN
186  this->basisDegree_ = order; // small n
187  this->basisCellTopologyKey_ = shards::Tetrahedron<4>::key;
188  this->basisType_ = BASIS_FEM_LAGRANGIAN;
189  this->basisCoordinates_ = COORDINATES_CARTESIAN;
190  this->functionSpace_ = FUNCTION_SPACE_HGRAD;
191  pointType_ = (pointType == POINTTYPE_DEFAULT) ? POINTTYPE_EQUISPACED : pointType;
192 
193  const ordinal_type card = this->basisCardinality_;
194 
195  // points are computed in the host and will be copied
196  Kokkos::DynRankView<scalarType,typename DT::execution_space::array_layout,Kokkos::HostSpace>
197  dofCoords("Hgrad::Tet::Cn::dofCoords", card, spaceDim);
198 
199  // Note: the only reason why equispaced can't support higher order than Parameters::MaxOrder appears to be the fact that the tags below get stored into a fixed-length array.
200  // TODO: relax the maximum order requirement by setting up tags in a different container, perhaps directly into an OrdinalTypeArray1DHost (tagView, below). (As of this writing (1/25/22), looks like other nodal bases do this in a similar way -- those should be fixed at the same time; maybe search for Parameters::MaxOrder.)
201  INTREPID2_TEST_FOR_EXCEPTION( order > Parameters::MaxOrder, std::invalid_argument, "polynomial order exceeds the max supported by this class");
202 
203  // Basis-dependent initializations
204  constexpr ordinal_type tagSize = 4; // size of DoF tag, i.e., number of fields in the tag
205  constexpr ordinal_type maxCard = Intrepid2::getPnCardinality<spaceDim, Parameters::MaxOrder>();
206  ordinal_type tags[maxCard][tagSize];
207 
208  // construct lattice
209 
210  shards::CellTopology cellTopo(shards::getCellTopologyData<shards::Tetrahedron<4> >() );
211  const ordinal_type numEdges = cellTopo.getEdgeCount();
212  const ordinal_type numFaces = cellTopo.getFaceCount();
213 
214  shards::CellTopology edgeTopo(shards::getCellTopologyData<shards::Line<2> >() );
215  shards::CellTopology faceTopo(shards::getCellTopologyData<shards::Triangle<3> >() );
216 
217  const int numVertexes = PointTools::getLatticeSize( cellTopo ,
218  1 ,
219  0 );
220 
221  const int numPtsPerEdge = PointTools::getLatticeSize( edgeTopo ,
222  order ,
223  1 );
224 
225  const int numPtsPerFace = PointTools::getLatticeSize( faceTopo ,
226  order ,
227  1 );
228 
229  const int numPtsPerCell = PointTools::getLatticeSize( cellTopo ,
230  order ,
231  1 );
232 
233  Kokkos::DynRankView<scalarType,typename DT::execution_space::array_layout,Kokkos::HostSpace> vertexes("Hcurl::Tet::In::vertexes", numVertexes , spaceDim );
234  Kokkos::DynRankView<scalarType,typename DT::execution_space::array_layout,Kokkos::HostSpace> linePts("Hcurl::Tet::In::linePts", numPtsPerEdge , 1 );
235  Kokkos::DynRankView<scalarType,typename DT::execution_space::array_layout,Kokkos::HostSpace> triPts("Hcurl::Tet::In::triPts", numPtsPerFace , 2 );
236 
237  // construct lattice
238  const ordinal_type offset = 1;
239 
240 
241  PointTools::getLattice( vertexes,
242  cellTopo ,
243  1, 0,
244  this->pointType_ );
245 
246  PointTools::getLattice( linePts,
247  edgeTopo,
248  order, offset,
249  this->pointType_ );
250 
251  PointTools::getLattice( triPts,
252  faceTopo,
253  order, offset,
254  this->pointType_ );
255 
256  // holds the image of the line points
257  Kokkos::DynRankView<scalarType,typename DT::execution_space::array_layout,Kokkos::HostSpace> edgePts("Hcurl::Tet::In::edgePts", numPtsPerEdge , spaceDim );
258  Kokkos::DynRankView<scalarType,typename DT::execution_space::array_layout,Kokkos::HostSpace> facePts("Hcurl::Tet::In::facePts", numPtsPerFace , spaceDim );
259 
260  for (ordinal_type i=0;i<numVertexes;i++) {
261  auto i_card=i;
262  for(ordinal_type k=0; k<spaceDim; ++k)
263  dofCoords(i_card,k) = vertexes(i,k);
264  tags[i_card][0] = 0; // vertex dof
265  tags[i_card][1] = i; // vertex id
266  tags[i_card][2] = 0; // local dof id
267  tags[i_card][3] = 1; // total vert dof
268  }
269 
270 
271  // these are tangents scaled by the appropriate edge lengths.
272  for (ordinal_type i=0;i<numEdges;i++) { // loop over edges
274  linePts ,
275  1 ,
276  i ,
277  cellTopo );
278 
279 
280  // loop over points (rows of V2)
281  for (ordinal_type j=0;j<numPtsPerEdge;j++) {
282 
283  const ordinal_type i_card = numVertexes + numPtsPerEdge*i+j;
284 
285  //save dof coordinates and coefficients
286  for(ordinal_type k=0; k<spaceDim; ++k)
287  dofCoords(i_card,k) = edgePts(j,k);
288 
289  tags[i_card][0] = 1; // edge dof
290  tags[i_card][1] = i; // edge id
291  tags[i_card][2] = j; // local dof id
292  tags[i_card][3] = numPtsPerEdge; // total edge dof
293 
294  }
295  }
296 
297  if(numPtsPerFace >0) {//handle faces if needed (order >1)
298 
299  for (ordinal_type i=0;i<numFaces;i++) { // loop over faces
300 
302  triPts ,
303  2 ,
304  i ,
305  cellTopo );
306  for (ordinal_type j=0;j<numPtsPerFace;j++) {
307 
308  const ordinal_type i_card = numVertexes+numEdges*numPtsPerEdge+numPtsPerFace*i+j;
309 
310  //save dof coordinates
311  for(ordinal_type k=0; k<spaceDim; ++k)
312  dofCoords(i_card,k) = facePts(j,k);
313 
314  tags[i_card][0] = 2; // face dof
315  tags[i_card][1] = i; // face id
316  tags[i_card][2] = j; // local face id
317  tags[i_card][3] = numPtsPerFace; // total face dof
318  }
319  }
320  }
321 
322 
323  // internal dof, if needed
324  if (numPtsPerCell > 0) {
325  Kokkos::DynRankView<scalarType,typename DT::execution_space::array_layout,Kokkos::HostSpace>
326  cellPoints( "Hcurl::Tet::In::cellPoints", numPtsPerCell , spaceDim );
327  PointTools::getLattice( cellPoints ,
328  cellTopo ,
329  order,
330  1 ,
331  this->pointType_ );
332 
333  // copy values into right positions of V2
334  for (ordinal_type j=0;j<numPtsPerCell;j++) {
335 
336  const ordinal_type i_card = numVertexes+numEdges*numPtsPerEdge+numFaces*numPtsPerFace+j;
337 
338  //save dof coordinates
339  for(ordinal_type dim=0; dim<spaceDim; ++dim)
340  dofCoords(i_card,dim) = cellPoints(j,dim);
341 
342  tags[i_card][0] = spaceDim; // elem dof
343  tags[i_card][1] = 0; // elem id
344  tags[i_card][2] = j; // local dof id
345  tags[i_card][3] = numPtsPerCell; // total vert dof
346  }
347  }
348 
349  this->dofCoords_ = Kokkos::create_mirror_view(typename DT::memory_space(), dofCoords);
350  Kokkos::deep_copy(this->dofCoords_, dofCoords);
351 
352  // form Vandermonde matrix. Actually, this is the transpose of the VDM,
353  // so we transpose on copy below.
354  const ordinal_type lwork = card*card;
355  Kokkos::DynRankView<scalarType,Kokkos::LayoutLeft,Kokkos::HostSpace>
356  vmat("Hgrad::Tet::Cn::vmat", card, card),
357  work("Hgrad::Tet::Cn::work", lwork),
358  ipiv("Hgrad::Tet::Cn::ipiv", card);
359 
360  Impl::Basis_HGRAD_TET_Cn_FEM_ORTH::getValues<Kokkos::HostSpace::execution_space,Parameters::MaxNumPtsPerBasisEval>(typename Kokkos::HostSpace::execution_space{},
361  vmat,
362  dofCoords,
363  order,
364  OPERATOR_VALUE);
365 
366  ordinal_type info = 0;
367  Teuchos::LAPACK<ordinal_type,scalarType> lapack;
368 
369  lapack.GETRF(card, card,
370  vmat.data(), vmat.stride_1(),
371  (ordinal_type*)ipiv.data(),
372  &info);
373 
374  INTREPID2_TEST_FOR_EXCEPTION( info != 0,
375  std::runtime_error ,
376  ">>> ERROR: (Intrepid2::Basis_HGRAD_TET_Cn_FEM) lapack.GETRF returns nonzero info." );
377 
378  lapack.GETRI(card,
379  vmat.data(), vmat.stride_1(),
380  (ordinal_type*)ipiv.data(),
381  work.data(), lwork,
382  &info);
383 
384  INTREPID2_TEST_FOR_EXCEPTION( info != 0,
385  std::runtime_error ,
386  ">>> ERROR: (Intrepid2::Basis_HGRAD_TET_Cn_FEM) lapack.GETRI returns nonzero info." );
387 
388  // create host mirror
389  Kokkos::DynRankView<scalarType,typename DT::execution_space::array_layout,Kokkos::HostSpace>
390  vinv("Hgrad::Line::Cn::vinv", card, card);
391 
392  for (ordinal_type i=0;i<card;++i)
393  for (ordinal_type j=0;j<card;++j)
394  vinv(i,j) = vmat(j,i);
395 
396  this->vinv_ = Kokkos::create_mirror_view(typename DT::memory_space(), vinv);
397  Kokkos::deep_copy(this->vinv_ , vinv);
398 
399  // initialize tags
400  {
401  // Basis-dependent initializations
402  const ordinal_type posScDim = 0; // position in the tag, counting from 0, of the subcell dim
403  const ordinal_type posScOrd = 1; // position in the tag, counting from 0, of the subcell ordinal
404  const ordinal_type posDfOrd = 2; // position in the tag, counting from 0, of DoF ordinal relative to the subcell
405 
406  OrdinalTypeArray1DHost tagView(&tags[0][0], card*tagSize);
407 
408  // Basis-independent function sets tag and enum data in tagToOrdinal_ and ordinalToTag_ arrays:
409  // tags are constructed on host
410  this->setOrdinalTagData(this->tagToOrdinal_,
411  this->ordinalToTag_,
412  tagView,
413  this->basisCardinality_,
414  tagSize,
415  posScDim,
416  posScOrd,
417  posDfOrd);
418  }
419 }
420 
421  template<typename DT, typename OT, typename PT>
422  void
424  ordinal_type& perTeamSpaceSize,
425  ordinal_type& perThreadSpaceSize,
426  const PointViewType inputPoints,
427  const EOperator operatorType) const {
428  perTeamSpaceSize = 0;
429  perThreadSpaceSize = getWorkSizePerPoint(operatorType)*get_dimension_scalar(inputPoints)*sizeof(typename BasisBase::scalarType);
430  }
431 
432  template<typename DT, typename OT, typename PT>
433  KOKKOS_INLINE_FUNCTION
434  void
436  OutputViewType outputValues,
437  const PointViewType inputPoints,
438  const EOperator operatorType,
439  const typename Kokkos::TeamPolicy<typename DT::execution_space>::member_type& team_member,
440  const typename DT::execution_space::scratch_memory_space & scratchStorage,
441  const ordinal_type subcellDim,
442  const ordinal_type subcellOrdinal) const {
443 
444  INTREPID2_TEST_FOR_ABORT( !((subcellDim == -1) && (subcellOrdinal == -1)),
445  ">>> ERROR: (Intrepid2::Basis_HGRAD_TET_Cn_FEM::getValues), The capability of selecting subsets of basis functions has not been implemented yet.");
446 
447  const int numPoints = inputPoints.extent(0);
448  using ScalarType = typename ScalarTraits<typename PointViewType::value_type>::scalar_type;
449  using WorkViewType = Kokkos::DynRankView< ScalarType,typename DT::execution_space::scratch_memory_space,Kokkos::MemoryTraits<Kokkos::Unmanaged> >;
450  constexpr ordinal_type spaceDim = 3;
451  auto sizePerPoint = (operatorType==OPERATOR_VALUE) ?
452  this->vinv_.extent(0)*get_dimension_scalar(inputPoints) :
453  (2*spaceDim+1)*this->vinv_.extent(0)*get_dimension_scalar(inputPoints);
454  WorkViewType workView(scratchStorage, sizePerPoint*team_member.team_size());
455  using range_type = Kokkos::pair<ordinal_type,ordinal_type>;
456  switch(operatorType) {
457  case OPERATOR_VALUE:
458  Kokkos::parallel_for (Kokkos::TeamThreadRange (team_member, numPoints), [=] (ordinal_type& pt) {
459  auto output = Kokkos::subview( outputValues, Kokkos::ALL(), range_type (pt,pt+1), Kokkos::ALL() );
460  const auto input = Kokkos::subview( inputPoints, range_type(pt, pt+1), Kokkos::ALL() );
461  WorkViewType work(workView.data() + sizePerPoint*team_member.team_rank(), sizePerPoint);
462  Impl::Basis_HGRAD_TET_Cn_FEM::Serial<OPERATOR_VALUE>::getValues( output, input, work, this->vinv_, this->basisDegree_);
463  });
464  break;
465  case OPERATOR_GRAD:
466  Kokkos::parallel_for (Kokkos::TeamThreadRange (team_member, numPoints), [=] (ordinal_type& pt) {
467  auto output = Kokkos::subview( outputValues, Kokkos::ALL(), range_type(pt,pt+1), Kokkos::ALL() );
468  const auto input = Kokkos::subview( inputPoints, range_type(pt,pt+1), Kokkos::ALL() );
469  WorkViewType work(workView.data() + sizePerPoint*team_member.team_rank(), sizePerPoint);
470  Impl::Basis_HGRAD_TET_Cn_FEM::Serial<OPERATOR_GRAD>::getValues( output, input, work, this->vinv_, this->basisDegree_);
471  });
472  break;
473  default: {
474  INTREPID2_TEST_FOR_ABORT( true,
475  ">>> ERROR (Basis_HGRAD_TET_Cn_FEM): getValues not implemented for this operator");
476  }
477  }
478  }
479 
480 } // namespace Intrepid2
481 #endif
ScalarTraits< pointValueType >::scalar_type scalarType
Scalar type for point values.
Kokkos::DynRankView< PointValueType, Kokkos::LayoutStride, DeviceType > PointViewType
View type for input points.
static void getLattice(Kokkos::DynRankView< pointValueType, pointProperties...> points, const shards::CellTopology cellType, const ordinal_type order, const ordinal_type offset=0, const EPointType pointType=POINTTYPE_EQUISPACED)
Computes a lattice of points of a given order on a reference simplex, quadrilateral or hexahedron (cu...
virtual void getValues(const ExecutionSpace &space, OutputViewType outputValues, const PointViewType inputPoints, const EOperator operatorType=OPERATOR_VALUE) const override
Evaluation of a FEM basis on a reference cell.
Kokkos::View< ordinal_type *, typename ExecutionSpace::array_layout, Kokkos::HostSpace > OrdinalTypeArray1DHost
View type for 1d host array.
Header file for the Intrepid2::Basis_HGRAD_TET_Cn_FEM class.
static void mapToReferenceSubcell(refSubcellViewType refSubcellPoints, const paramPointViewType paramPoints, const ordinal_type subcellDim, const ordinal_type subcellOrd, const shards::CellTopology parentCell)
Computes parameterization maps of 1- and 2-subcells of reference cells.
virtual void getScratchSpaceSize(ordinal_type &perTeamSpaceSize, ordinal_type &perThreadSpaceSize, const PointViewType inputPoints, const EOperator operatorType=OPERATOR_VALUE) const override
Return the size of the scratch space, in bytes, needed for using the team-level implementation of get...
Basis_HGRAD_TET_Cn_FEM(const ordinal_type order, const EPointType pointType=POINTTYPE_EQUISPACED)
Constructor.
Header file for the Intrepid2::Basis_HGRAD_TET_Cn_FEM_ORTH class.
static constexpr ordinal_type MaxOrder
The maximum reconstruction order.
static ordinal_type getLatticeSize(const shards::CellTopology cellType, const ordinal_type order, const ordinal_type offset=0)
Computes the number of points in a lattice of a given order on a simplex (currently disabled for othe...