Intrepid2
Intrepid2_HGRAD_HEX_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_HEX_CN_FEMDEF_HPP__
17 #define __INTREPID2_HGRAD_HEX_CN_FEMDEF_HPP__
18 
19 namespace Intrepid2 {
20 
21  // -------------------------------------------------------------------------------------
22  namespace Impl {
23 
24  template<EOperator opType>
25  template<typename OutputViewType,
26  typename inputViewType,
27  typename workViewType,
28  typename vinvViewType>
29  KOKKOS_INLINE_FUNCTION
30  void
31  Basis_HGRAD_HEX_Cn_FEM::Serial<opType>::
32  getValues( OutputViewType output,
33  const inputViewType input,
34  workViewType work,
35  const vinvViewType vinv,
36  const ordinal_type operatorDn ) {
37  ordinal_type opDn = operatorDn;
38 
39  const ordinal_type cardLine = vinv.extent(0);
40  const ordinal_type npts = input.extent(0);
41 
42  typedef Kokkos::pair<ordinal_type,ordinal_type> range_type;
43  const auto input_x = Kokkos::subview(input, Kokkos::ALL(), range_type(0,1));
44  const auto input_y = Kokkos::subview(input, Kokkos::ALL(), range_type(1,2));
45  const auto input_z = Kokkos::subview(input, Kokkos::ALL(), range_type(2,3));
46 
47  const ordinal_type dim_s = get_dimension_scalar(input);
48  auto ptr0 = work.data();
49  auto ptr1 = work.data()+cardLine*npts*dim_s;
50  auto ptr2 = work.data()+2*cardLine*npts*dim_s;
51  auto ptr3 = work.data()+3*cardLine*npts*dim_s;
52 
53  typedef typename Kokkos::DynRankView<typename inputViewType::value_type, typename workViewType::memory_space> viewType;
54  auto vcprop = Kokkos::common_view_alloc_prop(input);
55 
56  switch (opType) {
57  case OPERATOR_VALUE: {
58  viewType work_line(Kokkos::view_wrap(ptr0, vcprop), cardLine, npts);
59  viewType output_x(Kokkos::view_wrap(ptr1, vcprop), cardLine, npts);
60  viewType output_y(Kokkos::view_wrap(ptr2, vcprop), cardLine, npts);
61  viewType output_z(Kokkos::view_wrap(ptr3, vcprop), cardLine, npts);
62 
63  Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_VALUE>::
64  getValues(output_x, input_x, work_line, vinv);
65 
66  Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_VALUE>::
67  getValues(output_y, input_y, work_line, vinv);
68 
69  Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_VALUE>::
70  getValues(output_z, input_z, work_line, vinv);
71 
72  // tensor product
73  ordinal_type idx = 0;
74  for (ordinal_type k=0;k<cardLine;++k) // z
75  for (ordinal_type j=0;j<cardLine;++j) // y
76  for (ordinal_type i=0;i<cardLine;++i,++idx) // x
77  for (ordinal_type l=0;l<npts;++l)
78  output.access(idx,l) = output_x.access(i,l)*output_y.access(j,l)*output_z.access(k,l);
79  break;
80  }
81  case OPERATOR_GRAD:
82  case OPERATOR_D1:
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  opDn = getOperatorOrder(opType);
93  case OPERATOR_Dn: {
94  const ordinal_type dkcard = opDn + 1;
95 
96  ordinal_type d = 0;
97  for (ordinal_type l1=0;l1<dkcard;++l1)
98  for (ordinal_type l0=0;l0<(l1+1);++l0) {
99  const ordinal_type mult_x = (opDn - l1);
100  const ordinal_type mult_y = l1 - l0;
101  const ordinal_type mult_z = l0;
102 
103  //std::cout << " l0, l1 = " << l0 << " " << l1 << std::endl;
104  //std::cout << " x , y , z = " << mult_x << " " << mult_y << " " << mult_z << std::endl;
105 
106  if (mult_x < 0) {
107  // pass
108  } else {
109  viewType work_line(Kokkos::view_wrap(ptr0, vcprop), cardLine, npts);
110  decltype(work_line) output_x, output_y, output_z;
111 
112  if (mult_x) {
113  output_x = viewType(Kokkos::view_wrap(ptr1, vcprop), cardLine, npts, 1);
114  Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_Dn>::
115  getValues(output_x, input_x, work_line, vinv, mult_x);
116  } else {
117  output_x = viewType(Kokkos::view_wrap(ptr1, vcprop), cardLine, npts);
118  Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_VALUE>::
119  getValues(output_x, input_x, work_line, vinv);
120  }
121 
122  if (mult_y) {
123  output_y = viewType(Kokkos::view_wrap(ptr2, vcprop), cardLine, npts, 1);
124  Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_Dn>::
125  getValues(output_y, input_y, work_line, vinv, mult_y);
126  } else {
127  output_y = viewType(Kokkos::view_wrap(ptr2, vcprop), cardLine, npts);
128  Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_VALUE>::
129  getValues(output_y, input_y, work_line, vinv);
130  }
131 
132  if (mult_z) {
133  output_z = viewType(Kokkos::view_wrap(ptr3, vcprop), cardLine, npts, 1);
134  Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_Dn>::
135  getValues(output_z, input_z, work_line, vinv, mult_z);
136  } else {
137  output_z = viewType(Kokkos::view_wrap(ptr3, vcprop), cardLine, npts);
138  Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_VALUE>::
139  getValues(output_z, input_z, work_line, vinv);
140  }
141 
142  // tensor product (extra dimension of ouput x,y and z are ignored)
143  ordinal_type idx = 0;
144  for (ordinal_type k=0;k<cardLine;++k) // z
145  for (ordinal_type j=0;j<cardLine;++j) // y
146  for (ordinal_type i=0;i<cardLine;++i,++idx) // x
147  for (ordinal_type l=0;l<npts;++l)
148  output.access(idx,l,d) = output_x.access(i,l,0)*output_y.access(j,l,0)*output_z.access(k,l,0);
149  ++d;
150  }
151  }
152  break;
153  }
154  default: {
155  INTREPID2_TEST_FOR_ABORT( true ,
156  ">>> ERROR (Basis_HGRAD_HEX_Cn_FEM): Operator type not implemented");
157  break;
158  }
159  }
160  }
161 
162  template<typename DT, ordinal_type numPtsPerEval,
163  typename outputValueValueType, class ...outputValueProperties,
164  typename inputPointValueType, class ...inputPointProperties,
165  typename vinvValueType, class ...vinvProperties>
166  void
167  Basis_HGRAD_HEX_Cn_FEM::
168  getValues( const typename DT::execution_space& space,
169  Kokkos::DynRankView<outputValueValueType,outputValueProperties...> outputValues,
170  const Kokkos::DynRankView<inputPointValueType, inputPointProperties...> inputPoints,
171  const Kokkos::DynRankView<vinvValueType, vinvProperties...> vinv,
172  const EOperator operatorType ) {
173  typedef Kokkos::DynRankView<outputValueValueType,outputValueProperties...> outputValueViewType;
174  typedef Kokkos::DynRankView<inputPointValueType, inputPointProperties...> inputPointViewType;
175  typedef Kokkos::DynRankView<vinvValueType, vinvProperties...> vinvViewType;
176  typedef typename ExecSpace<typename inputPointViewType::execution_space,typename DT::execution_space>::ExecSpaceType ExecSpaceType;
177 
178  // loopSize corresponds to cardinality
179  const auto loopSizeTmp1 = (inputPoints.extent(0)/numPtsPerEval);
180  const auto loopSizeTmp2 = (inputPoints.extent(0)%numPtsPerEval != 0);
181  const auto loopSize = loopSizeTmp1 + loopSizeTmp2;
182  Kokkos::RangePolicy<ExecSpaceType,Kokkos::Schedule<Kokkos::Static> > policy(space, 0, loopSize);
183 
184  typedef typename inputPointViewType::value_type inputPointType;
185 
186  const ordinal_type cardinality = outputValues.extent(0);
187  const ordinal_type cardLine = std::cbrt(cardinality);
188  const ordinal_type workSize = 4*cardLine;
189 
190  auto vcprop = Kokkos::common_view_alloc_prop(inputPoints);
191  typedef typename Kokkos::DynRankView< inputPointType, typename inputPointViewType::memory_space> workViewType;
192  workViewType work(Kokkos::view_alloc(space, "Basis_HGRAD_HEX_Cn_FEM::getValues::work", vcprop), workSize, inputPoints.extent(0));
193 
194  switch (operatorType) {
195  case OPERATOR_VALUE: {
196  typedef Functor<outputValueViewType,inputPointViewType,vinvViewType,workViewType,
197  OPERATOR_VALUE,numPtsPerEval> FunctorType;
198  Kokkos::parallel_for( policy, FunctorType(outputValues, inputPoints, vinv, work) );
199  break;
200  }
201  case OPERATOR_CURL: {
202  typedef Functor<outputValueViewType,inputPointViewType,vinvViewType,workViewType,
203  OPERATOR_CURL,numPtsPerEval> FunctorType;
204  Kokkos::parallel_for( policy, FunctorType(outputValues, inputPoints, vinv, work) );
205  break;
206  }
207  case OPERATOR_GRAD:
208  case OPERATOR_D1:
209  case OPERATOR_D2:
210  case OPERATOR_D3:
211  case OPERATOR_D4:
212  case OPERATOR_D5:
213  case OPERATOR_D6:
214  case OPERATOR_D7:
215  case OPERATOR_D8:
216  case OPERATOR_D9:
217  case OPERATOR_D10: {
218  typedef Functor<outputValueViewType,inputPointViewType,vinvViewType,workViewType,
219  OPERATOR_Dn,numPtsPerEval> FunctorType;
220  Kokkos::parallel_for( policy, FunctorType(outputValues, inputPoints, vinv, work,
221  getOperatorOrder(operatorType)) );
222  break;
223  }
224  default: {
225  INTREPID2_TEST_FOR_EXCEPTION( true , std::invalid_argument,
226  ">>> ERROR (Basis_HGRAD_HEX_Cn_FEM): Operator type not implemented" );
227  // break; commented out since exception is thrown
228  }
229  }
230  }
231  }
232 
233  // -------------------------------------------------------------------------------------
234  template<typename DT, typename OT, typename PT>
236  Basis_HGRAD_HEX_Cn_FEM( const ordinal_type order,
237  const EPointType pointType ) {
238 
239  // this should be in host
240  Basis_HGRAD_LINE_Cn_FEM<DT,OT,PT> lineBasis( order, pointType );
241  const auto cardLine = lineBasis.getCardinality();
242 
243  this->vinv_ = Kokkos::DynRankView<typename ScalarViewType::value_type,DT>("Hgrad::HEX::Cn::vinv", cardLine, cardLine);
244  lineBasis.getVandermondeInverse(this->vinv_);
245 
246  const ordinal_type spaceDim = 3;
247  this->basisCardinality_ = cardLine*cardLine*cardLine;
248  this->basisDegree_ = order;
249  this->basisCellTopologyKey_ = shards::Hexahedron<8>::key;
250  this->basisType_ = BASIS_FEM_LAGRANGIAN;
251  this->basisCoordinates_ = COORDINATES_CARTESIAN;
252  this->functionSpace_ = FUNCTION_SPACE_HGRAD;
253  pointType_ = pointType;
254 
255  // initialize tags
256  {
257  // Basis-dependent initializations
258  const ordinal_type tagSize = 4; // size of DoF tag, i.e., number of fields in the tag
259  const ordinal_type posScDim = 0; // position in the tag, counting from 0, of the subcell dim
260  const ordinal_type posScOrd = 1; // position in the tag, counting from 0, of the subcell ordinal
261  const ordinal_type posDfOrd = 2; // position in the tag, counting from 0, of DoF ordinal relative to the subcell
262 
263  // 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.
264  // 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.)
265  INTREPID2_TEST_FOR_EXCEPTION( order > Parameters::MaxOrder, std::invalid_argument, "polynomial order exceeds the max supported by this class");
266 
267  // An array with local DoF tags assigned to the basis functions, in the order of their local enumeration
268  constexpr ordinal_type maxCardLine = Parameters::MaxOrder + 1;
269  ordinal_type tags[maxCardLine*maxCardLine*maxCardLine][4];
270 
271  const ordinal_type vert[2][2][2] = { { {0,1}, {3,2} },
272  { {4,5}, {7,6} } }; //[z][y][x]
273 
274  const ordinal_type edge_x[2][2] = { {0, 4}, {2, 6} };
275  const ordinal_type edge_y[2][2] = { {3, 7}, {1, 5} };
276  const ordinal_type edge_z[2][2] = { {8,11}, {9,10} };
277 
278  const ordinal_type face_yz[2] = {3, 1};
279  const ordinal_type face_xz[2] = {0, 2};
280  const ordinal_type face_xy[2] = {4, 5};
281 
282  {
283  ordinal_type idx = 0;
284  for (auto k=0;k<cardLine;++k) { // z
285  const auto tag_z = lineBasis.getDofTag(k);
286  for (ordinal_type j=0;j<cardLine;++j) { // y
287  const auto tag_y = lineBasis.getDofTag(j);
288  for (ordinal_type i=0;i<cardLine;++i,++idx) { // x
289  const auto tag_x = lineBasis.getDofTag(i);
290 
291  if (tag_x(0) == 0 && tag_y(0) == 0 && tag_z(0) == 0) {
292  // vertices
293  tags[idx][0] = 0; // vertex dof
294  tags[idx][1] = vert[tag_z(1)][tag_y(1)][tag_x(1)]; // vertex id
295  tags[idx][2] = 0; // local dof id
296  tags[idx][3] = 1; // total number of dofs in this vertex
297  } else if (tag_x(0) == 1 && tag_y(0) == 0 && tag_z(0) == 0) {
298  // edge, x edge, y vert, z vert,
299  tags[idx][0] = 1; // edge dof
300  tags[idx][1] = edge_x[tag_y(1)][tag_z(1)]; // edge id
301  tags[idx][2] = tag_x(2); // local dof id
302  tags[idx][3] = tag_x(3); // total number of dofs in this edge
303  } else if (tag_x(0) == 0 && tag_y(0) == 1 && tag_z(0) == 0) {
304  // edge, x vert, y edge, z vert,
305  tags[idx][0] = 1; // edge dof
306  tags[idx][1] = edge_y[tag_x(1)][tag_z(1)]; // edge id
307  tags[idx][2] = tag_y(2); // local dof id
308  tags[idx][3] = tag_y(3); // total number of dofs in this edge
309  } else if (tag_x(0) == 0 && tag_y(0) == 0 && tag_z(0) == 1) {
310  // edge, x vert, y vert, z edge,
311  tags[idx][0] = 1; // edge dof
312  tags[idx][1] = edge_z[tag_x(1)][tag_y(1)]; // edge id
313  tags[idx][2] = tag_z(2); // local dof id
314  tags[idx][3] = tag_z(3); // total number of dofs in this edge
315  } else if (tag_x(0) == 0 && tag_y(0) == 1 && tag_z(0) == 1) {
316  // face, x vert, y edge, z edge
317  tags[idx][0] = 2; // face dof
318  tags[idx][1] = face_yz[tag_x(1)]; // face id
319  tags[idx][2] = tag_y(2) + tag_y(3)*tag_z(2); // local dof id
320  tags[idx][3] = tag_y(3)*tag_z(3); // total number of dofs in this vertex
321  } else if (tag_x(0) == 1 && tag_y(0) == 0 && tag_z(0) == 1) {
322  // face, x edge, y vert, z edge
323  tags[idx][0] = 2; // face dof
324  tags[idx][1] = face_xz[tag_y(1)]; // face id
325  tags[idx][2] = tag_x(2) + tag_x(3)*tag_z(2); // local dof id
326  tags[idx][3] = tag_x(3)*tag_z(3); // total number of dofs in this vertex
327  } else if (tag_x(0) == 1 && tag_y(0) == 1 && tag_z(0) == 0) {
328  // face, x edge, y edge, z vert
329  tags[idx][0] = 2; // face dof
330  tags[idx][1] = face_xy[tag_z(1)]; // face id
331  tags[idx][2] = tag_x(2) + tag_x(3)*tag_y(2); // local dof id
332  tags[idx][3] = tag_x(3)*tag_y(3); // total number of dofs in this vertex
333  } else {
334  // interior
335  tags[idx][0] = 3; // interior dof
336  tags[idx][1] = 0;
337  tags[idx][2] = tag_x(2) + tag_x(3)*tag_y(2) + tag_x(3)*tag_y(3)*tag_z(2); // local dof id
338  tags[idx][3] = tag_x(3)*tag_y(3)*tag_z(3); // total number of dofs in this vertex
339  }
340  }
341  }
342  }
343  }
344 
345  OrdinalTypeArray1DHost tagView(&tags[0][0], this->basisCardinality_*4);
346 
347  // Basis-independent function sets tag and enum data in tagToOrdinal_ and ordinalToTag_ arrays:
348  // tags are constructed on host
349  this->setOrdinalTagData(this->tagToOrdinal_,
350  this->ordinalToTag_,
351  tagView,
352  this->basisCardinality_,
353  tagSize,
354  posScDim,
355  posScOrd,
356  posDfOrd);
357  }
358 
359  // dofCoords on host and create its mirror view to device
360  Kokkos::DynRankView<typename ScalarViewType::value_type,typename DT::execution_space::array_layout,Kokkos::HostSpace>
361  dofCoordsHost("dofCoordsHost", this->basisCardinality_, spaceDim);
362 
363  Kokkos::DynRankView<typename ScalarViewType::value_type,DT>
364  dofCoordsLine("dofCoordsLine", cardLine, 1);
365 
366  lineBasis.getDofCoords(dofCoordsLine);
367  auto dofCoordsLineHost = Kokkos::create_mirror_view(dofCoordsLine);
368  Kokkos::deep_copy(dofCoordsLineHost, dofCoordsLine);
369  {
370  ordinal_type idx = 0;
371  for (auto k=0;k<cardLine;++k) { // z
372  for (ordinal_type j=0;j<cardLine;++j) { // y
373  for (ordinal_type i=0;i<cardLine;++i,++idx) { // x
374  dofCoordsHost(idx,0) = dofCoordsLineHost(i,0);
375  dofCoordsHost(idx,1) = dofCoordsLineHost(j,0);
376  dofCoordsHost(idx,2) = dofCoordsLineHost(k,0);
377  }
378  }
379  }
380  }
381 
382  this->dofCoords_ = Kokkos::create_mirror_view(typename DT::memory_space(), dofCoordsHost);
383  Kokkos::deep_copy(this->dofCoords_, dofCoordsHost);
384  }
385 
386  template<typename DT, typename OT, typename PT>
387  void
389  ordinal_type& perTeamSpaceSize,
390  ordinal_type& perThreadSpaceSize,
391  const PointViewType inputPoints,
392  const EOperator operatorType) const {
393  (void) operatorType; //avoid warning for unused variable
394  perTeamSpaceSize = 0;
395  perThreadSpaceSize = 4*this->vinv_.extent(0)*get_dimension_scalar(inputPoints)*sizeof(typename BasisBase::scalarType);
396  }
397 
398  template<typename DT, typename OT, typename PT>
399  KOKKOS_INLINE_FUNCTION
400  void
402  OutputViewType outputValues,
403  const PointViewType inputPoints,
404  const EOperator operatorType,
405  const typename Kokkos::TeamPolicy<typename DT::execution_space>::member_type& team_member,
406  const typename DT::execution_space::scratch_memory_space & scratchStorage,
407  const ordinal_type subcellDim,
408  const ordinal_type subcellOrdinal) const {
409 
410  INTREPID2_TEST_FOR_ABORT( !((subcellDim == -1) && (subcellOrdinal == -1)),
411  ">>> ERROR: (Intrepid2::Basis_HGRAD_HEX_Cn_FEM::getValues), The capability of selecting subsets of basis functions has not been implemented yet.");
412 
413  const int numPoints = inputPoints.extent(0);
414  using ScalarType = typename ScalarTraits<typename PointViewType::value_type>::scalar_type;
415  using WorkViewType = Kokkos::DynRankView< ScalarType,typename DT::execution_space::scratch_memory_space,Kokkos::MemoryTraits<Kokkos::Unmanaged> >;
416  ordinal_type sizePerPoint = 4*this->vinv_.extent(0)*get_dimension_scalar(inputPoints);
417  WorkViewType workView(scratchStorage, sizePerPoint*team_member.team_size());
418  using range_type = Kokkos::pair<ordinal_type,ordinal_type>;
419 
420  switch(operatorType) {
421  case OPERATOR_VALUE:
422  Kokkos::parallel_for (Kokkos::TeamThreadRange (team_member, numPoints), [=] (ordinal_type& pt) {
423  auto output = Kokkos::subview( outputValues, Kokkos::ALL(), range_type (pt,pt+1), Kokkos::ALL() );
424  const auto input = Kokkos::subview( inputPoints, range_type(pt, pt+1), Kokkos::ALL() );
425  WorkViewType work(workView.data() + sizePerPoint*team_member.team_rank(), sizePerPoint);
426  Impl::Basis_HGRAD_HEX_Cn_FEM::Serial<OPERATOR_VALUE>::getValues( output, input, work, this->vinv_ );
427  });
428  break;
429  case OPERATOR_GRAD:
430  Kokkos::parallel_for (Kokkos::TeamThreadRange (team_member, numPoints), [=] (ordinal_type& pt) {
431  auto output = Kokkos::subview( outputValues, Kokkos::ALL(), range_type(pt,pt+1), Kokkos::ALL() );
432  const auto input = Kokkos::subview( inputPoints, range_type(pt,pt+1), Kokkos::ALL() );
433  WorkViewType work(workView.data() + sizePerPoint*team_member.team_rank(), sizePerPoint);
434  Impl::Basis_HGRAD_HEX_Cn_FEM::Serial<OPERATOR_GRAD>::getValues( output, input, work, this->vinv_ );
435  });
436  break;
437  default: {
438  INTREPID2_TEST_FOR_ABORT( true,
439  ">>> ERROR (Basis_HGRAD_TET_Cn_FEM): getValues not implemented for this operator");
440  }
441  }
442  }
443 }// namespace Intrepid2
444 
445 #endif
const OrdinalTypeArrayStride1DHost getDofTag(const ordinal_type dofOrd) const
DoF ordinal to DoF tag lookup.
ordinal_type getCardinality() const
Returns cardinality of the basis.
ScalarTraits< pointValueType >::scalar_type scalarType
Scalar type for point values.
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.
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_HEX_Cn_FEM(const ordinal_type order, const EPointType pointType=POINTTYPE_EQUISPACED)
Constructor.
Kokkos::View< ordinal_type *, typename ExecutionSpace::array_layout, Kokkos::HostSpace > OrdinalTypeArray1DHost
View type for 1d host array.
Kokkos::DynRankView< PointValueType, Kokkos::LayoutStride, DeviceType > PointViewType
View type for input points.
virtual void getDofCoords(ScalarViewType dofCoords) const override
Returns spatial locations (coordinates) of degrees of freedom on the reference cell.
Implementation of the locally H(grad)-compatible FEM basis of variable order on the [-1...
static constexpr ordinal_type MaxOrder
The maximum reconstruction order.