Intrepid2
Intrepid2_HCURL_QUAD_In_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
15
16#ifndef __INTREPID2_HCURL_QUAD_IN_FEM_DEF_HPP__
17#define __INTREPID2_HCURL_QUAD_IN_FEM_DEF_HPP__
18
19namespace 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
32 getValues( OutputViewType output,
33 const InputViewType input,
34 WorkViewType work,
35 const VinvViewType vinvLine,
36 const VinvViewType vinvBubble) {
37 const ordinal_type cardLine = vinvLine.extent(0);
38 const ordinal_type cardBubble = vinvBubble.extent(0);
39
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
46 const int dim_s = get_dimension_scalar(input);
47 auto ptr0 = work.data();
48 auto ptr1 = work.data()+cardLine*npts*dim_s;
49 auto ptr2 = work.data()+2*cardLine*npts*dim_s;
50
51 typedef typename Kokkos::DynRankView<typename InputViewType::value_type, typename WorkViewType::memory_space> ViewType;
52
53 switch (OpType) {
54 case OPERATOR_VALUE: {
55 ViewType workLine = createMatchingUnmanagedView<ViewType>(input, ptr0, cardLine, npts);
56 ViewType outputLine = createMatchingUnmanagedView<ViewType>(input, ptr1, cardLine, npts);
57 ViewType outputBubble = createMatchingUnmanagedView<ViewType>(input, ptr2, cardBubble, npts);
58
59 // tensor product
60 ordinal_type idx = 0;
61 {
62 Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_VALUE>::
63 getValues(outputBubble, input_x, workLine, vinvBubble);
64
65 Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_VALUE>::
66 getValues(outputLine, input_y, workLine, vinvLine);
67
68 // x component (lineBasis(y) bubbleBasis(x))
69 const auto output_x = outputBubble;
70 const auto output_y = outputLine;
71
72 for (ordinal_type j=0;j<cardLine;++j) // y
73 for (ordinal_type i=0;i<cardBubble;++i,++idx) // x
74 for (ordinal_type k=0;k<npts;++k) {
75 output.access(idx,k,0) = output_x.access(i,k)*output_y.access(j,k);
76 output.access(idx,k,1) = 0.0;
77 }
78 }
79
80 {
81 Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_VALUE>::
82 getValues(outputBubble, input_y, workLine, vinvBubble);
83
84 Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_VALUE>::
85 getValues(outputLine, input_x, workLine, vinvLine);
86
87 // y component (bubbleBasis(y) lineBasis(x))
88 const auto output_x = outputLine;
89 const auto output_y = outputBubble;
90 for (ordinal_type j=0;j<cardBubble;++j) // y
91 for (ordinal_type i=0;i<cardLine;++i,++idx) // x
92 for (ordinal_type k=0;k<npts;++k) {
93 output.access(idx,k,0) = 0.0;
94 output.access(idx,k,1) = output_x.access(i,k)*output_y.access(j,k);
95 }
96 }
97
98 break;
99 }
100 case OPERATOR_CURL: {
101 ordinal_type idx = 0;
102 { // x - component
103 ViewType workLine = createMatchingUnmanagedView<ViewType>(input, ptr0, cardLine, npts);
104 // x bubble value
105 ViewType output_x = createMatchingUnmanagedView<ViewType>(input, ptr2, cardBubble, npts);
106 // y line grad
107 ViewType output_y = createMatchingUnmanagedView<ViewType>(input, ptr1, cardLine, npts,1);
108
109 Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_VALUE>::
110 getValues(output_x, input_x, workLine, vinvBubble);
111
112 Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_Dn>::
113 getValues(output_y, input_y, workLine, vinvLine, 1);
114
115 // tensor product (extra dimension of ouput x and y are ignored)
116 for (ordinal_type j=0;j<cardLine;++j) // y
117 for (ordinal_type i=0;i<cardBubble;++i,++idx) // x
118 for (ordinal_type k=0;k<npts;++k)
119 output.access(idx,k) = -output_x.access(i,k)*output_y.access(j,k,0);
120 }
121 { // y - component
122 ViewType workLine = createMatchingUnmanagedView<ViewType>(input, ptr0, cardLine, npts);
123 // x line grad
124 ViewType output_x = createMatchingUnmanagedView<ViewType>(input, ptr1, cardLine, npts,1);
125 // y bubble value
126 ViewType output_y = createMatchingUnmanagedView<ViewType>(input, ptr2, cardBubble, npts);
127
128 Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_VALUE>::
129 getValues(output_y, input_y, workLine, vinvBubble);
130
131 Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_Dn>::
132 getValues(output_x, input_x, workLine, vinvLine, 1);
133
134 // tensor product (extra dimension of ouput x and y are ignored)
135 for (ordinal_type j=0;j<cardBubble;++j) // y
136 for (ordinal_type i=0;i<cardLine;++i,++idx) // x
137 for (ordinal_type k=0;k<npts;++k)
138 output.access(idx,k) = output_x.access(i,k,0)*output_y.access(j,k);
139 }
140 break;
141 }
142 default: {
143 INTREPID2_TEST_FOR_ABORT( true,
144 ">>> ERROR: (Intrepid2::Basis_HCURL_QUAD_In_FEM::Serial::getValues) operator is not supported" );
145 }
146 }
147 }
148
149 template<typename DT, ordinal_type numPtsPerEval,
150 typename outputValueValueType, class ...outputValueProperties,
151 typename inputPointValueType, class ...inputPointProperties,
152 typename vinvValueType, class ...vinvProperties>
153 void
154 Basis_HCURL_QUAD_In_FEM::
155 getValues( Kokkos::DynRankView<outputValueValueType,outputValueProperties...> outputValues,
156 const Kokkos::DynRankView<inputPointValueType, inputPointProperties...> inputPoints,
157 const Kokkos::DynRankView<vinvValueType, vinvProperties...> vinvLine,
158 const Kokkos::DynRankView<vinvValueType, vinvProperties...> vinvBubble,
159 const EOperator operatorType ) {
160 typedef Kokkos::DynRankView<outputValueValueType,outputValueProperties...> outputValueViewType;
161 typedef Kokkos::DynRankView<inputPointValueType, inputPointProperties...> inputPointViewType;
162 typedef Kokkos::DynRankView<vinvValueType, vinvProperties...> vinvViewType;
163 typedef typename ExecSpace<typename inputPointViewType::execution_space,typename DT::execution_space>::ExecSpaceType ExecSpaceType;
164
165 // loopSize corresponds to cardinality
166 const auto loopSizeTmp1 = (inputPoints.extent(0)/numPtsPerEval);
167 const auto loopSizeTmp2 = (inputPoints.extent(0)%numPtsPerEval != 0);
168 const auto loopSize = loopSizeTmp1 + loopSizeTmp2;
169 Kokkos::RangePolicy<ExecSpaceType,Kokkos::Schedule<Kokkos::Static> > policy(0, loopSize);
170
171 const ordinal_type cardinality = outputValues.extent(0);
172 //get basis order based on basis cardinality.
173 ordinal_type order = 0;
174 ordinal_type cardBubble; // = std::sqrt(cardinality/2);
175 ordinal_type cardLine; // = cardBubble+1;
176 do {
177 cardBubble = Intrepid2::getPnCardinality<1>(order);
178 cardLine = Intrepid2::getPnCardinality<1>(++order);
179 } while((2*cardBubble*cardLine != cardinality) && (order != Parameters::MaxOrder));
180
181 switch (operatorType) {
182 case OPERATOR_VALUE: {
183 auto workSize = Serial<OPERATOR_VALUE>::getWorkSizePerPoint(order);
184 auto work = createMatchingDynRankView(inputPoints, "Basis_HCURL_QUAD_In_FEM::getValues::work", workSize, inputPoints.extent(0));
185 typedef Functor<outputValueViewType,inputPointViewType,vinvViewType, decltype(work),
186 OPERATOR_VALUE,numPtsPerEval> FunctorType;
187 Kokkos::parallel_for( policy, FunctorType(outputValues, inputPoints, vinvLine, vinvBubble, work) );
188 break;
189 }
190 case OPERATOR_CURL: {
191 auto workSize = Serial<OPERATOR_CURL>::getWorkSizePerPoint(order);
192 auto work = createMatchingDynRankView(inputPoints, "Basis_HCURL_QUAD_In_FEM::getValues::work", workSize, inputPoints.extent(0));
193 typedef Functor<outputValueViewType,inputPointViewType,vinvViewType, decltype(work),
194 OPERATOR_CURL,numPtsPerEval> FunctorType;
195 Kokkos::parallel_for( policy, FunctorType(outputValues, inputPoints, vinvLine, vinvBubble, work) );
196 break;
197 }
198 default: {
199 INTREPID2_TEST_FOR_EXCEPTION( true , std::invalid_argument,
200 ">>> ERROR (Basis_HCURL_QUAD_In_FEM): Operator type not implemented" );
201 }
202 }
203 }
204 }
205
206 // -------------------------------------------------------------------------------------
207 template<typename DT, typename OT, typename PT>
209 Basis_HCURL_QUAD_In_FEM( const ordinal_type order,
210 const EPointType pointType ) {
211
212 INTREPID2_TEST_FOR_EXCEPTION( !(pointType == POINTTYPE_EQUISPACED ||
213 pointType == POINTTYPE_WARPBLEND), std::invalid_argument,
214 ">>> ERROR (Basis_HCURL_QUAD_In_FEM): pointType must be either equispaced or warpblend.");
215
216 // this should be in host
217 Basis_HGRAD_LINE_Cn_FEM<DT,OT,PT> lineBasis( order, pointType );
218 Basis_HVOL_LINE_Cn_FEM<DT,OT,PT> bubbleBasis( order - 1, POINTTYPE_GAUSS );
219
220 const ordinal_type
221 cardLine = lineBasis.getCardinality(),
222 cardBubble = bubbleBasis.getCardinality();
223
224 this->vinvLine_ = Kokkos::DynRankView<typename ScalarViewType::value_type,DT>("Hcurl::Quad::In::vinvLine", cardLine, cardLine);
225 this->vinvBubble_ = Kokkos::DynRankView<typename ScalarViewType::value_type,DT>("Hcurl::Quad::In::vinvBubble", cardBubble, cardBubble);
226
227 lineBasis.getVandermondeInverse(this->vinvLine_);
228 bubbleBasis.getVandermondeInverse(this->vinvBubble_);
229
230 const ordinal_type spaceDim = 2;
231 this->basisCardinality_ = 2*cardLine*cardBubble;
232 this->basisDegree_ = order;
233 this->basisCellTopologyKey_ = shards::Quadrilateral<4>::key;
234 this->basisType_ = BASIS_FEM_LAGRANGIAN;
235 this->basisCoordinates_ = COORDINATES_CARTESIAN;
236 this->functionSpace_ = FUNCTION_SPACE_HCURL;
237 pointType_ = pointType;
238
239 // initialize tags
240 {
241 // Basis-dependent initializations
242 const ordinal_type tagSize = 4; // size of DoF tag, i.e., number of fields in the tag
243 const ordinal_type posScDim = 0; // position in the tag, counting from 0, of the subcell dim
244 const ordinal_type posScOrd = 1; // position in the tag, counting from 0, of the subcell ordinal
245 const ordinal_type posDfOrd = 2; // position in the tag, counting from 0, of DoF ordinal relative to the subcell
246
247 // 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.
248 // 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.)
249 INTREPID2_TEST_FOR_EXCEPTION( order > Parameters::MaxOrder, std::invalid_argument, "polynomial order exceeds the max supported by this class");
250
251 // An array with local DoF tags assigned to the basis functions, in the order of their local enumeration
252 constexpr ordinal_type maxCardLine = Parameters::MaxOrder + 1;
253 constexpr ordinal_type maxCardBubble = Parameters::MaxOrder;
254 ordinal_type tags[2*maxCardLine*maxCardBubble][4];
255
256 const ordinal_type edge_x[2] = {0,2};
257 const ordinal_type edge_y[2] = {3,1};
258 {
259 ordinal_type idx = 0;
260
264
265 // since there are x/y components in the interior
266 // dof sum should be computed before the information
267 // is assigned to tags
268 const ordinal_type
269 intr_ndofs_per_direction = (cardLine-2)*cardBubble,
270 intr_ndofs = 2*intr_ndofs_per_direction;
271
272 // x component (lineBasis(y) bubbleBasis(x))
273 for (ordinal_type j=0;j<cardLine;++j) { // y
274 const auto tag_y = lineBasis.getDofTag(j);
275 for (ordinal_type i=0;i<cardBubble;++i,++idx) { // x
276 const auto tag_x = bubbleBasis.getDofTag(i);
277
278 if (tag_x(0) == 1 && tag_y(0) == 0) {
279 // edge: x edge, y vert
280 tags[idx][0] = 1; // edge dof
281 tags[idx][1] = edge_x[tag_y(1)];
282 tags[idx][2] = tag_x(2); // local dof id
283 tags[idx][3] = tag_x(3); // total number of dofs in this vertex
284 } else {
285 // interior
286 tags[idx][0] = 2; // interior dof
287 tags[idx][1] = 0;
288 tags[idx][2] = tag_x(2) + tag_x(3)*tag_y(2); // local dof id
289 tags[idx][3] = intr_ndofs; // total number of dofs in this vertex
290 }
291 }
292 }
293
294 // y component (bubbleBasis(y) lineBasis(x))
295 for (ordinal_type j=0;j<cardBubble;++j) { // y
296 const auto tag_y = bubbleBasis.getDofTag(j);
297 for (ordinal_type i=0;i<cardLine;++i,++idx) { // x
298 const auto tag_x = lineBasis.getDofTag(i);
299
300 if (tag_x(0) == 0 && tag_y(0) == 1) {
301 // edge: x vert, y edge
302 tags[idx][0] = 1; // edge dof
303 tags[idx][1] = edge_y[tag_x(1)];
304 tags[idx][2] = tag_y(2); // local dof id
305 tags[idx][3] = tag_y(3); // total number of dofs in this vertex
306 } else {
307 // interior
308 tags[idx][0] = 2; // interior dof
309 tags[idx][1] = 0;
310 tags[idx][2] = intr_ndofs_per_direction + tag_x(2) + tag_x(3)*tag_y(2); // local dof id
311 tags[idx][3] = intr_ndofs; // total number of dofs in this vertex
312 }
313 }
314 }
315 INTREPID2_TEST_FOR_EXCEPTION( idx != this->basisCardinality_ , std::runtime_error,
316 ">>> ERROR (Basis_HCURL_QUAD_In_FEM): " \
317 "counted tag index is not same as cardinality." );
318 }
319
320 OrdinalTypeArray1DHost tagView(&tags[0][0], this->basisCardinality_*4);
321
322 // Basis-independent function sets tag and enum data in tagToOrdinal_ and ordinalToTag_ arrays:
323 // tags are constructed on host
325 this->ordinalToTag_,
326 tagView,
327 this->basisCardinality_,
328 tagSize,
329 posScDim,
330 posScOrd,
331 posDfOrd);
332 }
333
334 // dofCoords on host and create its mirror view to device
335 Kokkos::DynRankView<typename ScalarViewType::value_type,typename DT::execution_space::array_layout,Kokkos::HostSpace>
336 dofCoordsHost("dofCoordsHost", this->basisCardinality_, spaceDim);
337
338 // dofCoeffs on host and create its mirror view to device
339 Kokkos::DynRankView<typename ScalarViewType::value_type,typename DT::execution_space::array_layout,Kokkos::HostSpace>
340 dofCoeffsHost("dofCoeffsHost", this->basisCardinality_, spaceDim);
341
342 Kokkos::DynRankView<typename ScalarViewType::value_type,DT>
343 dofCoordsLine("dofCoordsLine", cardLine, 1),
344 dofCoordsBubble("dofCoordsBubble", cardBubble, 1);
345
346 lineBasis.getDofCoords(dofCoordsLine);
347 auto dofCoordsLineHost = Kokkos::create_mirror_view(dofCoordsLine);
348 Kokkos::deep_copy(dofCoordsLineHost, dofCoordsLine);
349
350 bubbleBasis.getDofCoords(dofCoordsBubble);
351 auto dofCoordsBubbleHost = Kokkos::create_mirror_view(dofCoordsBubble);
352 Kokkos::deep_copy(dofCoordsBubbleHost, dofCoordsBubble);
353
354 {
355 ordinal_type idx = 0;
356
357 // x component (lineBasis(y) bubbleBasis(x))
358 for (ordinal_type j=0;j<cardLine;++j) { // y
359 for (ordinal_type i=0;i<cardBubble;++i,++idx) { // x
360 dofCoordsHost(idx,0) = dofCoordsBubbleHost(i,0);
361 dofCoordsHost(idx,1) = dofCoordsLineHost(j,0);
362 dofCoeffsHost(idx,0) = 1.0;
363 }
364 }
365
366 // y component (bubbleBasis(y) lineBasis(x))
367 for (ordinal_type j=0;j<cardBubble;++j) { // y
368 for (ordinal_type i=0;i<cardLine;++i,++idx) { // x
369 dofCoordsHost(idx,0) = dofCoordsLineHost(i,0);
370 dofCoordsHost(idx,1) = dofCoordsBubbleHost(j,0);
371 dofCoeffsHost(idx,1) = 1.0;
372 }
373 }
374 }
375
376 this->dofCoords_ = Kokkos::create_mirror_view(typename DT::memory_space(), dofCoordsHost);
377 Kokkos::deep_copy(this->dofCoords_, dofCoordsHost);
378
379 this->dofCoeffs_ = Kokkos::create_mirror_view(typename DT::memory_space(), dofCoeffsHost);
380 Kokkos::deep_copy(this->dofCoeffs_, dofCoeffsHost);
381 }
382
383 template<typename DT, typename OT, typename PT>
384 void
385 Basis_HCURL_QUAD_In_FEM<DT,OT,PT>::getScratchSpaceSize(
386 ordinal_type& perTeamSpaceSize,
387 ordinal_type& perThreadSpaceSize,
388 const PointViewType inputPoints,
389 const EOperator operatorType) const {
390 perTeamSpaceSize = 0;
391 perThreadSpaceSize = (2*this->vinvLine_.extent(0)+this->vinvBubble_.extent(0))*get_dimension_scalar(inputPoints)*sizeof(typename BasisBase::scalarType);
392 }
393
394 template<typename DT, typename OT, typename PT>
395 KOKKOS_INLINE_FUNCTION
396 void
397 Basis_HCURL_QUAD_In_FEM<DT,OT,PT>::getValues(
398 OutputViewType outputValues,
399 const PointViewType inputPoints,
400 const EOperator operatorType,
401 const typename Kokkos::TeamPolicy<typename DT::execution_space>::member_type& team_member,
402 const typename DT::execution_space::scratch_memory_space & scratchStorage,
403 const ordinal_type subcellDim,
404 const ordinal_type subcellOrdinal) const {
405
406 INTREPID2_TEST_FOR_ABORT( !((subcellDim == -1) && (subcellOrdinal == -1)),
407 ">>> ERROR: (Intrepid2::Basis_HCURL_QUAD_In_FEM::getValues), The capability of selecting subsets of basis functions has not been implemented yet.");
408
409 const int numPoints = inputPoints.extent(0);
410 using ScalarType = typename ScalarTraits<typename PointViewType::value_type>::scalar_type;
411 using WorkViewType = Kokkos::DynRankView< ScalarType,typename DT::execution_space::scratch_memory_space,Kokkos::MemoryTraits<Kokkos::Unmanaged> >;
412 ordinal_type sizePerPoint = (2*this->vinvLine_.extent(0)+this->vinvBubble_.extent(0))*get_dimension_scalar(inputPoints);
413 WorkViewType workView(scratchStorage, sizePerPoint*team_member.team_size());
414 using range_type = Kokkos::pair<ordinal_type,ordinal_type>;
415
416 switch(operatorType) {
417 case OPERATOR_VALUE:
418 Kokkos::parallel_for (Kokkos::TeamThreadRange (team_member, numPoints), [=, &vinvLine_ = this->vinvLine_, &vinvBubble_ = this-> vinvBubble_] (ordinal_type& pt) {
419 auto output = Kokkos::subview( outputValues, Kokkos::ALL(), range_type (pt,pt+1), Kokkos::ALL() );
420 const auto input = Kokkos::subview( inputPoints, range_type(pt, pt+1), Kokkos::ALL() );
421 WorkViewType work(workView.data() + sizePerPoint*team_member.team_rank(), sizePerPoint);
422 Impl::Basis_HCURL_QUAD_In_FEM::Serial<OPERATOR_VALUE>::getValues( output, input, work, vinvLine_, vinvBubble_ );
423 });
424 break;
425 case OPERATOR_CURL:
426 Kokkos::parallel_for (Kokkos::TeamThreadRange (team_member, numPoints), [=, &vinvLine_ = this->vinvLine_, &vinvBubble_ = this->vinvBubble_] (ordinal_type& pt) {
427 auto output = Kokkos::subview( outputValues, Kokkos::ALL(), range_type(pt,pt+1), Kokkos::ALL() );
428 const auto input = Kokkos::subview( inputPoints, range_type(pt,pt+1), Kokkos::ALL() );
429 WorkViewType work(workView.data() + sizePerPoint*team_member.team_rank(), sizePerPoint);
430 Impl::Basis_HCURL_QUAD_In_FEM::Serial<OPERATOR_CURL>::getValues( output, input, work, vinvLine_, vinvBubble_ );
431 });
432 break;
433 default: {
434 INTREPID2_TEST_FOR_ABORT( true,
435 ">>> ERROR (Basis_HCURL_QUAD_In_FEM): getValues not implemented for this operator");
436 }
437 }
438 }
439
440} // namespace Intrepid2
441
442#endif
KOKKOS_INLINE_FUNCTION std::enable_if< std::is_pointer_v< CtorProp > &&!std::is_convertible_v< CtorProp, constchar * >, OutViewType >::type createMatchingUnmanagedView(const InViewType &view, const CtorProp &data, const Dims... dims)
Creates an unmanaged view that matches the value_type of the provided view The type of the output vie...
DeduceDynRankView< InViewType >::type createMatchingDynRankView(const InViewType &view, const CtorProp &prop, const Dims... dims)
Creates and returns a view that matches the value_type of the provided view The output view type is d...
Kokkos::DynRankView< typename ScalarViewType::value_type, DeviceType > vinvLine_
inverse of Generalized Vandermonde matrix (isotropic order)
Basis_HCURL_QUAD_In_FEM(const ordinal_type order, const EPointType pointType=POINTTYPE_EQUISPACED)
Constructor.
Implementation of the locally H(grad)-compatible FEM basis of variable order on the [-1,...
virtual void getDofCoords(ScalarViewType dofCoords) const override
Returns spatial locations (coordinates) of degrees of freedom on the reference cell.
Implementation of the locally HVOL-compatible FEM basis of variable order on the [-1,...
virtual void getDofCoords(ScalarViewType dofCoords) const override
Returns spatial locations (coordinates) of degrees of freedom on the reference cell.
const OrdinalTypeArrayStride1DHost getDofTag(const ordinal_type dofOrd) const
DoF ordinal to DoF tag lookup.
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)
ordinal_type getCardinality() const
Returns cardinality of the basis.
Kokkos::DynRankView< scalarType, DeviceType > dofCoords_
Kokkos::DynRankView< scalarType, DeviceType > dofCoeffs_
static constexpr ordinal_type MaxOrder
The maximum reconstruction order.