Intrepid2
Intrepid2_HCURL_HEX_In_FEMDef.hpp
Go to the documentation of this file.
1 // @HEADER
2 // ************************************************************************
3 //
4 // Intrepid2 Package
5 // Copyright (2007) Sandia Corporation
6 //
7 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
8 // license for use of this work by or on behalf of the U.S. Government.
9 //
10 // Redistribution and use in source and binary forms, with or without
11 // modification, are permitted provided that the following conditions are
12 // met:
13 //
14 // 1. Redistributions of source code must retain the above copyright
15 // notice, this list of conditions and the following disclaimer.
16 //
17 // 2. Redistributions in binary form must reproduce the above copyright
18 // notice, this list of conditions and the following disclaimer in the
19 // documentation and/or other materials provided with the distribution.
20 //
21 // 3. Neither the name of the Corporation nor the names of the
22 // contributors may be used to endorse or promote products derived from
23 // this software without specific prior written permission.
24 //
25 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
26 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
29 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
30 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
31 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
32 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
33 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
34 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
35 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 //
37 // Questions? Contact Kyungjoo Kim (kyukim@sandia.gov), or
38 // Mauro Perego (mperego@sandia.gov)
39 //
40 // ************************************************************************
41 // @HEADER
42 
49 #ifndef __INTREPID2_HCURL_HEX_IN_FEM_DEF_HPP__
50 #define __INTREPID2_HCURL_HEX_IN_FEM_DEF_HPP__
51 
52 namespace Intrepid2 {
53 
54  // -------------------------------------------------------------------------------------
55  namespace Impl {
56 
57  template<EOperator opType>
58  template<typename OutputViewType,
59  typename inputViewType,
60  typename workViewType,
61  typename vinvViewType>
62  KOKKOS_INLINE_FUNCTION
63  void
64  Basis_HCURL_HEX_In_FEM::Serial<opType>::
65  getValues( OutputViewType output,
66  const inputViewType input,
67  workViewType work,
68  const vinvViewType vinvLine,
69  const vinvViewType vinvBubble) {
70  const ordinal_type cardLine = vinvLine.extent(0);
71  const ordinal_type cardBubble = vinvBubble.extent(0);
72 
73  const ordinal_type npts = input.extent(0);
74 
75  typedef Kokkos::pair<ordinal_type,ordinal_type> range_type;
76  const auto input_x = Kokkos::subview(input, Kokkos::ALL(), range_type(0,1));
77  const auto input_y = Kokkos::subview(input, Kokkos::ALL(), range_type(1,2));
78  const auto input_z = Kokkos::subview(input, Kokkos::ALL(), range_type(2,3));
79 
80  const ordinal_type dim_s = get_dimension_scalar(work);
81  auto ptr0 = work.data();
82  auto ptr1 = work.data() + cardLine*npts*dim_s;
83  auto ptr2 = work.data() + 2*cardLine*npts*dim_s;
84  auto ptr3 = work.data() + 3*cardLine*npts*dim_s;
85 
86  typedef typename Kokkos::DynRankView<typename workViewType::value_type, typename workViewType::memory_space> viewType;
87  auto vcprop = Kokkos::common_view_alloc_prop(work);
88 
89  switch (opType) {
90  case OPERATOR_VALUE: {
91 
92  viewType workLine(Kokkos::view_wrap(ptr0, vcprop), cardLine, npts);
93  viewType outputLine_A(Kokkos::view_wrap(ptr1, vcprop), cardLine, npts);
94  viewType outputLine_B(Kokkos::view_wrap(ptr2, vcprop), cardLine, npts);
95  viewType outputBubble(Kokkos::view_wrap(ptr3, vcprop), cardBubble, npts);
96 
97  // tensor product
98  ordinal_type idx = 0;
99  {
100  Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_VALUE>::
101  getValues(outputBubble, input_x, workLine, vinvBubble);
102 
103  Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_VALUE>::
104  getValues(outputLine_A, input_y, workLine, vinvLine);
105 
106  Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_VALUE>::
107  getValues(outputLine_B, input_z, workLine, vinvLine);
108 
109  // x component (lineBasis(z) lineBasis(y) bubbleBasis(x))
110  const auto output_x = outputBubble;
111  const auto output_y = outputLine_A;
112  const auto output_z = outputLine_B;
113 
114  for (ordinal_type k=0;k<cardLine;++k) // z
115  for (ordinal_type j=0;j<cardLine;++j) // y
116  for (ordinal_type i=0;i<cardBubble;++i,++idx) // x
117  for (ordinal_type l=0;l<npts;++l) {
118  output.access(idx,l,0) = output_x.access(i,l)*output_y.access(j,l)*output_z.access(k,l);
119  output.access(idx,l,1) = 0.0;
120  output.access(idx,l,2) = 0.0;
121  }
122  }
123  {
124  Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_VALUE>::
125  getValues(outputLine_A, input_x, workLine, vinvLine);
126 
127  Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_VALUE>::
128  getValues(outputBubble, input_y, workLine, vinvBubble);
129 
130  //Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_VALUE>::
131  // getValues(outputLine_B, input_z, workLine, vinvLine);
132 
133  // y component (lineBasis(z) bubbleBasis(y) lineBasis(x))
134  const auto output_x = outputLine_A;
135  const auto output_y = outputBubble;
136  const auto output_z = outputLine_B;
137 
138  for (ordinal_type k=0;k<cardLine;++k) // z
139  for (ordinal_type j=0;j<cardBubble;++j) // y
140  for (ordinal_type i=0;i<cardLine;++i,++idx) // x
141  for (ordinal_type l=0;l<npts;++l) {
142  output.access(idx,l,0) = 0.0;
143  output.access(idx,l,1) = output_x.access(i,l)*output_y.access(j,l)*output_z.access(k,l);
144  output.access(idx,l,2) = 0.0;
145  }
146  }
147  {
148  //Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_VALUE>::
149  // getValues(outputLine_A, input_x, workLine, vinvLine);
150 
151  Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_VALUE>::
152  getValues(outputLine_B, input_y, workLine, vinvLine);
153 
154  Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_VALUE>::
155  getValues(outputBubble, input_z, workLine, vinvBubble);
156 
157  // z component (bubbleBasis(z) bubbleBasis(y) lineBasis(x))
158  const auto output_x = outputLine_A;
159  const auto output_y = outputLine_B;
160  const auto output_z = outputBubble;
161 
162  for (ordinal_type k=0;k<cardBubble;++k) // z
163  for (ordinal_type j=0;j<cardLine;++j) // y
164  for (ordinal_type i=0;i<cardLine;++i,++idx) // x
165  for (ordinal_type l=0;l<npts;++l) {
166  output.access(idx,l,0) = 0.0;
167  output.access(idx,l,1) = 0.0;
168  output.access(idx,l,2) = output_x.access(i,l)*output_y.access(j,l)*output_z.access(k,l);
169  }
170  }
171  break;
172  }
173  case OPERATOR_CURL: {
174 
175  auto ptr4 = work.data() + 4*cardLine*npts*dim_s;
176  auto ptr5 = work.data() + 5*cardLine*npts*dim_s;
177 
178  viewType workLine(Kokkos::view_wrap(ptr0, vcprop), cardLine, npts);
179  viewType outputLine_A(Kokkos::view_wrap(ptr1, vcprop), cardLine, npts);
180  viewType outputLine_B(Kokkos::view_wrap(ptr2, vcprop), cardLine, npts);
181  viewType outputLine_DA(Kokkos::view_wrap(ptr3, vcprop), cardLine, npts, 1);
182  viewType outputLine_DB(Kokkos::view_wrap(ptr4, vcprop), cardLine, npts, 1);
183  viewType outputBubble(Kokkos::view_wrap(ptr5, vcprop), cardBubble, npts);
184 
185  // tensor product
186  ordinal_type idx = 0;
187 
188  { // x - component
189  Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_VALUE>::
190  getValues(outputBubble, input_x, workLine, vinvBubble);
191 
192  Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_VALUE>::
193  getValues(outputLine_A, input_y, workLine, vinvLine);
194 
195  Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_Dn>::
196  getValues(outputLine_DA, input_y, workLine, vinvLine, 1);
197 
198  Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_VALUE>::
199  getValues(outputLine_B, input_z, workLine, vinvLine);
200 
201  Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_Dn>::
202  getValues(outputLine_DB, input_z, workLine, vinvLine, 1);
203 
204  // x component (lineBasis(z) lineBasis(y) bubbleBasis(x))
205  const auto output_x = outputBubble;
206  const auto output_y = outputLine_A;
207  const auto output_dy = outputLine_DA;
208  const auto output_z = outputLine_B;
209  const auto output_dz = outputLine_DB;
210 
211  for (ordinal_type k=0;k<cardLine;++k) // z
212  for (ordinal_type j=0;j<cardLine;++j) // y
213  for (ordinal_type i=0;i<cardBubble;++i,++idx) // x
214  for (ordinal_type l=0;l<npts;++l) {
215  output.access(idx,l,0) = 0.0;
216  output.access(idx,l,1) = output_x.access(i,l)*output_y.access (j,l) *output_dz.access(k,l,0);
217  output.access(idx,l,2) = -output_x.access(i,l)*output_dy.access(j,l,0)*output_z.access (k,l);
218  }
219  }
220  { // y - component
221  Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_VALUE>::
222  getValues(outputLine_A, input_x, workLine, vinvLine);
223 
224  Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_Dn>::
225  getValues(outputLine_DA, input_x, workLine, vinvLine, 1);
226 
227  Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_VALUE>::
228  getValues(outputBubble, input_y, workLine, vinvBubble);
229 
230  //Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_VALUE>::
231  // getValues(outputLine_B, input_z, workLine, vinvLine);
232 
233  //Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_Dn>::
234  // getValues(outputLine_DB, input_z, workLine, vinvLine, 1);
235 
236  // x component (lineBasis(z) lineBasis(y) bubbleBasis(x))
237  const auto output_x = outputLine_A;
238  const auto output_dx = outputLine_DA;
239  const auto output_y = outputBubble;
240  const auto output_z = outputLine_B;
241  const auto output_dz = outputLine_DB;
242 
243  for (ordinal_type k=0;k<cardLine;++k) // z
244  for (ordinal_type j=0;j<cardBubble;++j) // y
245  for (ordinal_type i=0;i<cardLine;++i,++idx) // x
246  for (ordinal_type l=0;l<npts;++l) {
247  output.access(idx,l,0) = -output_x.access (i,l) *output_y.access(j,l)*output_dz.access(k,l,0);
248  output.access(idx,l,1) = 0.0;
249  output.access(idx,l,2) = output_dx(i,l,0)*output_y.access(j,l)*output_z.access (k,l);
250  }
251  }
252  { // z - component
253  // Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_VALUE>::
254  // getValues(outputLine_A, input_x, workLine, vinvLine);
255 
256  // Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_Dn>::
257  // getValues(outputLine_DA, input_x, workLine, vinvLine, 1);
258 
259  Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_VALUE>::
260  getValues(outputLine_B, input_y, workLine, vinvLine);
261 
262  Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_Dn>::
263  getValues(outputLine_DB, input_y, workLine, vinvLine, 1);
264 
265  Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_VALUE>::
266  getValues(outputBubble, input_z, workLine, vinvBubble);
267 
268  // x component (lineBasis(z) lineBasis(y) bubbleBasis(x))
269  const auto output_x = outputLine_A;
270  const auto output_dx = outputLine_DA;
271  const auto output_y = outputLine_B;
272  const auto output_dy = outputLine_DB;
273  const auto output_z = outputBubble;
274 
275  for (ordinal_type k=0;k<cardBubble;++k) // z
276  for (ordinal_type j=0;j<cardLine;++j) // y
277  for (ordinal_type i=0;i<cardLine;++i,++idx) // x
278  for (ordinal_type l=0;l<npts;++l) {
279  output.access(idx,l,0) = output_x.access (i,l) *output_dy.access(j,l,0)*output_z.access(k,l);
280  output.access(idx,l,1) = -output_dx(i,l,0)*output_y.access (j,l) *output_z.access(k,l);
281  output.access(idx,l,2) = 0.0;
282  }
283  }
284  break;
285  }
286  default: {
287  INTREPID2_TEST_FOR_ABORT( true,
288  ">>> ERROR: (Intrepid2::Basis_HCURL_HEX_In_FEM::Serial::getValues) operator is not supported" );
289  }
290  }
291  }
292  template<typename DT, ordinal_type numPtsPerEval,
293  typename outputValueValueType, class ...outputValueProperties,
294  typename inputPointValueType, class ...inputPointProperties,
295  typename vinvValueType, class ...vinvProperties>
296  void
297  Basis_HCURL_HEX_In_FEM::
298  getValues( Kokkos::DynRankView<outputValueValueType,outputValueProperties...> outputValues,
299  const Kokkos::DynRankView<inputPointValueType, inputPointProperties...> inputPoints,
300  const Kokkos::DynRankView<vinvValueType, vinvProperties...> vinvLine,
301  const Kokkos::DynRankView<vinvValueType, vinvProperties...> vinvBubble,
302  const EOperator operatorType ) {
303  typedef Kokkos::DynRankView<outputValueValueType,outputValueProperties...> outputValueViewType;
304  typedef Kokkos::DynRankView<inputPointValueType, inputPointProperties...> inputPointViewType;
305  typedef Kokkos::DynRankView<vinvValueType, vinvProperties...> vinvViewType;
306  typedef typename ExecSpace<typename inputPointViewType::execution_space,typename DT::execution_space>::ExecSpaceType ExecSpaceType;
307 
308  // loopSize corresponds to cardinality
309  const auto loopSizeTmp1 = (inputPoints.extent(0)/numPtsPerEval);
310  const auto loopSizeTmp2 = (inputPoints.extent(0)%numPtsPerEval != 0);
311  const auto loopSize = loopSizeTmp1 + loopSizeTmp2;
312  Kokkos::RangePolicy<ExecSpaceType,Kokkos::Schedule<Kokkos::Static> > policy(0, loopSize);
313 
314  typedef typename inputPointViewType::value_type inputPointType;
315 
316  const ordinal_type cardinality = outputValues.extent(0);
317  //get basis order based on basis cardinality.
318  ordinal_type order = 0;
319  ordinal_type cardBubble; // = std::cbrt(cardinality/3);
320  ordinal_type cardLine; // = cardBubble+1;
321  do {
322  cardBubble = Intrepid2::getPnCardinality<1>(order);
323  cardLine = Intrepid2::getPnCardinality<1>(++order);
324  } while((3*cardBubble*cardLine*cardLine != cardinality) && (order != Parameters::MaxOrder));
325  auto vcprop = Kokkos::common_view_alloc_prop(inputPoints);
326  typedef typename Kokkos::DynRankView< inputPointType, typename inputPointViewType::memory_space> workViewType;
327 
328  switch (operatorType) {
329  case OPERATOR_VALUE: {
330  auto workSize = Serial<OPERATOR_VALUE>::getWorkSizePerPoint(order);
331  workViewType work(Kokkos::view_alloc("Basis_CURL_HEX_In_FEM::getValues::work", vcprop), workSize, inputPoints.extent(0));
332  typedef Functor<outputValueViewType,inputPointViewType,vinvViewType, workViewType,
333  OPERATOR_VALUE,numPtsPerEval> FunctorType;
334  Kokkos::parallel_for( policy, FunctorType(outputValues, inputPoints, vinvLine, vinvBubble, work) );
335  break;
336  }
337  case OPERATOR_CURL: {
338  auto workSize = Serial<OPERATOR_CURL>::getWorkSizePerPoint(order);
339  workViewType work(Kokkos::view_alloc("Basis_CURL_HEX_In_FEM::getValues::work", vcprop), workSize, inputPoints.extent(0));
340  typedef Functor<outputValueViewType,inputPointViewType,vinvViewType, workViewType,
341  OPERATOR_CURL,numPtsPerEval> FunctorType;
342  Kokkos::parallel_for( policy, FunctorType(outputValues, inputPoints, vinvLine, vinvBubble, work) );
343  break;
344  }
345  default: {
346  INTREPID2_TEST_FOR_EXCEPTION( true , std::invalid_argument,
347  ">>> ERROR (Basis_HCURL_HEX_In_FEM): Operator type not implemented" );
348  // break;commented out since exception is thrown
349  }
350  }
351  }
352  }
353 
354  // -------------------------------------------------------------------------------------
355 
356  template<typename DT, typename OT, typename PT>
358  Basis_HCURL_HEX_In_FEM( const ordinal_type order,
359  const EPointType pointType ) {
360 
361  INTREPID2_TEST_FOR_EXCEPTION( !(pointType == POINTTYPE_EQUISPACED ||
362  pointType == POINTTYPE_WARPBLEND), std::invalid_argument,
363  ">>> ERROR (Basis_HCURL_HEX_In_FEM): pointType must be either equispaced or warpblend.");
364 
365  // this should be created in host and vinv should be deep copied into device space
366  Basis_HGRAD_LINE_Cn_FEM<DT,OT,PT> lineBasis( order, pointType );
367  Basis_HVOL_LINE_Cn_FEM<DT,OT,PT> bubbleBasis( order - 1, POINTTYPE_GAUSS );
368 
369  const ordinal_type
370  cardLine = lineBasis.getCardinality(),
371  cardBubble = bubbleBasis.getCardinality();
372 
373  this->vinvLine_ = Kokkos::DynRankView<typename ScalarViewType::value_type,DT>("Hcurl::Hex::In::vinvLine", cardLine, cardLine);
374  this->vinvBubble_ = Kokkos::DynRankView<typename ScalarViewType::value_type,DT>("Hcurl::Hex::In::vinvBubble", cardBubble, cardBubble);
375 
376  lineBasis.getVandermondeInverse(this->vinvLine_);
377  bubbleBasis.getVandermondeInverse(this->vinvBubble_);
378 
379  this->basisCardinality_ = 3*cardLine*cardLine*cardBubble;
380  this->basisDegree_ = order;
381  this->basisCellTopology_ = shards::CellTopology(shards::getCellTopologyData<shards::Hexahedron<8> >() );
382  this->basisType_ = BASIS_FEM_LAGRANGIAN;
383  this->basisCoordinates_ = COORDINATES_CARTESIAN;
384  this->functionSpace_ = FUNCTION_SPACE_HCURL;
385  pointType_ = pointType;
386 
387  // initialize tags
388  {
389  // Basis-dependent initializations
390  const ordinal_type tagSize = 4; // size of DoF tag, i.e., number of fields in the tag
391  const ordinal_type posScDim = 0; // position in the tag, counting from 0, of the subcell dim
392  const ordinal_type posScOrd = 1; // position in the tag, counting from 0, of the subcell ordinal
393  const ordinal_type posDfOrd = 2; // position in the tag, counting from 0, of DoF ordinal relative to the subcell
394 
395  // 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.
396  // 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.)
397  INTREPID2_TEST_FOR_EXCEPTION( order > Parameters::MaxOrder, std::invalid_argument, "polynomial order exceeds the max supported by this class");
398 
399  // An array with local DoF tags assigned to the basis functions, in the order of their local enumeration
400  constexpr ordinal_type maxCardLine = Parameters::MaxOrder + 1;
401  ordinal_type tags[3*maxCardLine*maxCardLine*maxCardLine][4];
402 
403  const ordinal_type edge_x[2][2] = { {0, 4}, {2, 6} };
404  const ordinal_type edge_y[2][2] = { {3, 7}, {1, 5} };
405  const ordinal_type edge_z[2][2] = { {8,11}, {9,10} };
406 
407  const ordinal_type face_yz[2] = {3, 1};
408  const ordinal_type face_xz[2] = {0, 2};
409  const ordinal_type face_xy[2] = {4, 5};
410 
411  {
412  ordinal_type idx = 0;
413 
417 
418  // since there are x/y components in the interior
419  // dof sum should be computed before the information
420  // is assigned to tags
421  const ordinal_type
422  face_ndofs_per_direction = (cardLine-2)*cardBubble,
423  face_ndofs = 2*face_ndofs_per_direction,
424  intr_ndofs_per_direction = (cardLine-2)*(cardLine-2)*cardBubble,
425  intr_ndofs = 3*intr_ndofs_per_direction;
426 
427  // x component (lineBasis(z) lineBasis(y) bubbleBasis(x))
428  for (ordinal_type k=0;k<cardLine;++k) { // z
429  const auto tag_z = lineBasis.getDofTag(k);
430  for (ordinal_type j=0;j<cardLine;++j) { // y
431  const auto tag_y = lineBasis.getDofTag(j);
432  for (ordinal_type i=0;i<cardBubble;++i,++idx) { // x
433  const auto tag_x = bubbleBasis.getDofTag(i);
434 
435  if (tag_x(0) == 1 && tag_y(0) == 0 && tag_z(0) == 0) {
436  // edge: x edge, y vert, z vert
437  tags[idx][0] = 1; // edge dof
438  tags[idx][1] = edge_x[tag_y(1)][tag_z(1)]; // edge id
439  tags[idx][2] = tag_x(2); // local dof id
440  tags[idx][3] = tag_x(3); // total number of dofs in this edge
441  } else if (tag_x(0) == 1 && tag_y(0) == 0 && tag_z(0) == 1) {
442  // face, x edge, y vert, z edge
443  tags[idx][0] = 2; // face dof
444  tags[idx][1] = face_xz[tag_y(1)]; // face id
445  tags[idx][2] = tag_x(2) + tag_x(3)*tag_z(2); // local dof id
446  tags[idx][3] = face_ndofs; // total number of dofs in this face
447  } else if (tag_x(0) == 1 && tag_y(0) == 1 && tag_z(0) == 0) {
448  // face, x edge, y edge, z vert
449  tags[idx][0] = 2; // face dof
450  tags[idx][1] = face_xy[tag_z(1)]; // face id
451  tags[idx][2] = tag_x(2) + tag_x(3)*tag_y(2); // local dof id
452  tags[idx][3] = face_ndofs; // total number of dofs in this face
453  } else {
454  // interior
455  tags[idx][0] = 3; // interior dof
456  tags[idx][1] = 0;
457  tags[idx][2] = tag_x(2) + tag_x(3)*tag_y(2) + tag_x(3)*tag_y(3)*tag_z(2); // local dof id
458  tags[idx][3] = intr_ndofs; // total number of dofs in this vertex
459  }
460  }
461  }
462  }
463 
464  // y component (lineBasis(z) bubbleBasis(y) lineBasis(x))
465  for (ordinal_type k=0;k<cardLine;++k) { // z
466  const auto tag_z = lineBasis.getDofTag(k);
467  for (ordinal_type j=0;j<cardBubble;++j) { // y
468  const auto tag_y = bubbleBasis.getDofTag(j);
469  for (ordinal_type i=0;i<cardLine;++i,++idx) { // x
470  const auto tag_x = lineBasis.getDofTag(i);
471 
472  if (tag_x(0) == 0 && tag_y(0) == 1 && tag_z(0) == 0) {
473  // edge: x vert, y edge, z vert
474  tags[idx][0] = 1; // edge dof
475  tags[idx][1] = edge_y[tag_x(1)][tag_z(1)]; // edge id
476  tags[idx][2] = tag_y(2); // local dof id
477  tags[idx][3] = tag_y(3); // total number of dofs in this vertex
478  } else if (tag_x(0) == 0 && tag_y(0) == 1 && tag_z(0) == 1) {
479  // face, x vert, y edge, z edge
480  tags[idx][0] = 2; // face dof
481  tags[idx][1] = face_yz[tag_x(1)]; // face id
482  tags[idx][2] = tag_y(2) + tag_y(3)*tag_z(2); // local dof id
483  tags[idx][3] = face_ndofs; // total number of dofs in this vertex
484  } else if (tag_x(0) == 1 && tag_y(0) == 1 && tag_z(0) == 0) {
485  // face, x edge, y edge, z vert
486  tags[idx][0] = 2; // face dof
487  tags[idx][1] = face_xy[tag_z(1)]; // face id
488  tags[idx][2] = face_ndofs_per_direction + tag_x(2) + tag_x(3)*tag_y(2); // local dof id
489  tags[idx][3] = face_ndofs; // total number of dofs in this vertex
490  } else {
491  // interior
492  tags[idx][0] = 3; // interior dof
493  tags[idx][1] = 0;
494  tags[idx][2] = intr_ndofs_per_direction + tag_x(2) + tag_x(3)*tag_y(2) + tag_x(3)*tag_y(3)*tag_z(2); // local dof id
495  tags[idx][3] = intr_ndofs; // total number of dofs in this vertex
496  }
497  }
498  }
499  }
500 
501  // z component (bubbleBasis(z) lineBasis(y) lineBasis(x))
502  for (ordinal_type k=0;k<cardBubble;++k) { // y
503  const auto tag_z = bubbleBasis.getDofTag(k);
504  for (ordinal_type j=0;j<cardLine;++j) { // z
505  const auto tag_y = lineBasis.getDofTag(j);
506  for (ordinal_type i=0;i<cardLine;++i,++idx) { // x
507  const auto tag_x = lineBasis.getDofTag(i);
508 
509  if (tag_x(0) == 0 && tag_y(0) == 0 && tag_z(0) == 1) {
510  // edge: x vert, y vert, z edge
511  tags[idx][0] = 1; // edge dof
512  tags[idx][1] = edge_z[tag_x(1)][tag_y(1)]; // edge id
513  tags[idx][2] = tag_z(2); // local dof id
514  tags[idx][3] = tag_z(3); // total number of dofs in this vertex
515  } else if (tag_x(0) == 0 && tag_y(0) == 1 && tag_z(0) == 1) {
516  // face, x vert, y edge, z edge
517  tags[idx][0] = 2; // face dof
518  tags[idx][1] = face_yz[tag_x(1)]; // face id
519  tags[idx][2] = face_ndofs_per_direction + tag_y(2) + tag_y(3)*tag_z(2); // local dof id
520  tags[idx][3] = face_ndofs; // total number of dofs in this vertex
521  } else if (tag_x(0) == 1 && tag_y(0) == 0 && tag_z(0) == 1) {
522  // face, x edge, y vert, z edge
523  tags[idx][0] = 2; // face dof
524  tags[idx][1] = face_xz[tag_y(1)]; // face id
525  tags[idx][2] = face_ndofs_per_direction + tag_x(2) + tag_x(3)*tag_z(2); // local dof id
526  tags[idx][3] = face_ndofs; // total number of dofs in this vertex
527  } else {
528  // interior
529  tags[idx][0] = 3; // interior dof
530  tags[idx][1] = 0;
531  tags[idx][2] = 2*intr_ndofs_per_direction + tag_x(2) + tag_x(3)*tag_y(2) + tag_x(3)*tag_y(3)*tag_z(2); // local dof id
532  tags[idx][3] = intr_ndofs; // total number of dofs in this vertex
533  }
534  }
535  }
536  }
537 
538  INTREPID2_TEST_FOR_EXCEPTION( idx != this->basisCardinality_ , std::runtime_error,
539  ">>> ERROR (Basis_HCURL_HEX_In_FEM): " \
540  "counted tag index is not same as cardinality." );
541  }
542 
543  OrdinalTypeArray1DHost tagView(&tags[0][0], this->basisCardinality_*4);
544 
545  // Basis-independent function sets tag and enum data in tagToOrdinal_ and ordinalToTag_ arrays:
546  // tags are constructed on host
547  this->setOrdinalTagData(this->tagToOrdinal_,
548  this->ordinalToTag_,
549  tagView,
550  this->basisCardinality_,
551  tagSize,
552  posScDim,
553  posScOrd,
554  posDfOrd);
555  }
556 
557  // dofCoords on host and create its mirror view to device
558  Kokkos::DynRankView<typename ScalarViewType::value_type,typename DT::execution_space::array_layout,Kokkos::HostSpace>
559  dofCoordsHost("dofCoordsHost", this->basisCardinality_, this->basisCellTopology_.getDimension());
560 
561  // dofCoords on host and create its mirror view to device
562  Kokkos::DynRankView<typename ScalarViewType::value_type,typename DT::execution_space::array_layout,Kokkos::HostSpace>
563  dofCoeffsHost("dofCoeffsHost", this->basisCardinality_, this->basisCellTopology_.getDimension());
564 
565  Kokkos::DynRankView<typename ScalarViewType::value_type,DT>
566  dofCoordsLine("dofCoordsLine", cardLine, 1),
567  dofCoordsBubble("dofCoordsBubble", cardBubble, 1);
568 
569  lineBasis.getDofCoords(dofCoordsLine);
570  auto dofCoordsLineHost = Kokkos::create_mirror_view(Kokkos::HostSpace(), dofCoordsLine);
571  Kokkos::deep_copy(dofCoordsLineHost, dofCoordsLine);
572 
573  bubbleBasis.getDofCoords(dofCoordsBubble);
574  auto dofCoordsBubbleHost = Kokkos::create_mirror_view(Kokkos::HostSpace(), dofCoordsBubble);
575  Kokkos::deep_copy(dofCoordsBubbleHost, dofCoordsBubble);
576 
577  {
578  ordinal_type idx = 0;
579 
580  // x component (lineBasis(z) lineBasis(y) bubbleBasis(x))
581  for (ordinal_type k=0;k<cardLine;++k) { // z
582  for (ordinal_type j=0;j<cardLine;++j) { // y
583  for (ordinal_type i=0;i<cardBubble;++i,++idx) { // x
584  dofCoordsHost(idx,0) = dofCoordsBubbleHost(i,0);
585  dofCoordsHost(idx,1) = dofCoordsLineHost(j,0);
586  dofCoordsHost(idx,2) = dofCoordsLineHost(k,0);
587  dofCoeffsHost(idx,0) = 1.0;
588  }
589  }
590  }
591 
592  // y component (lineBasis(z) bubbleBasis(y) lineBasis(x))
593  for (ordinal_type k=0;k<cardLine;++k) { // z
594  for (ordinal_type j=0;j<cardBubble;++j) { // y
595  for (ordinal_type i=0;i<cardLine;++i,++idx) { // x
596  dofCoordsHost(idx,0) = dofCoordsLineHost(i,0);
597  dofCoordsHost(idx,1) = dofCoordsBubbleHost(j,0);
598  dofCoordsHost(idx,2) = dofCoordsLineHost(k,0);
599  dofCoeffsHost(idx,1) = 1.0;
600  }
601  }
602  }
603 
604  // z component (bubbleBasis(z) lineBasis(y) lineBasis(x))
605  for (ordinal_type k=0;k<cardBubble;++k) { // z
606  for (ordinal_type j=0;j<cardLine;++j) { // y
607  for (ordinal_type i=0;i<cardLine;++i,++idx) { // x
608  dofCoordsHost(idx,0) = dofCoordsLineHost(i,0);
609  dofCoordsHost(idx,1) = dofCoordsLineHost(j,0);
610  dofCoordsHost(idx,2) = dofCoordsBubbleHost(k,0);
611  dofCoeffsHost(idx,2) = 1.0;
612  }
613  }
614  }
615  }
616 
617  this->dofCoords_ = Kokkos::create_mirror_view(typename DT::memory_space(), dofCoordsHost);
618  Kokkos::deep_copy(this->dofCoords_, dofCoordsHost);
619 
620  this->dofCoeffs_ = Kokkos::create_mirror_view(typename DT::memory_space(), dofCoeffsHost);
621  Kokkos::deep_copy(this->dofCoeffs_, dofCoeffsHost);
622  }
623 }
624 
625 #endif
const OrdinalTypeArrayStride1DHost getDofTag(const ordinal_type dofOrd) const
DoF ordinal to DoF tag lookup.
ordinal_type getCardinality() const
Returns cardinality of the basis.
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...
Implementation of the locally HVOL-compatible FEM basis of variable order on the [-1,1] reference line cell, using Lagrange polynomials.
Basis_HCURL_HEX_In_FEM(const ordinal_type order, const EPointType pointType=POINTTYPE_EQUISPACED)
Constructor.
static constexpr ordinal_type MaxOrder
The maximum reconstruction order.