Intrepid2
Intrepid2_HGRAD_HEX_Cn_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_HGRAD_HEX_CN_FEMDEF_HPP__
50 #define __INTREPID2_HGRAD_HEX_CN_FEMDEF_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_HGRAD_HEX_Cn_FEM::Serial<opType>::
65  getValues( OutputViewType output,
66  const inputViewType input,
67  workViewType work,
68  const vinvViewType vinv,
69  const ordinal_type operatorDn ) {
70  ordinal_type opDn = operatorDn;
71 
72  const ordinal_type cardLine = vinv.extent(0);
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  viewType work_line(Kokkos::view_wrap(ptr0, vcprop), cardLine, npts);
92  viewType output_x(Kokkos::view_wrap(ptr1, vcprop), cardLine, npts);
93  viewType output_y(Kokkos::view_wrap(ptr2, vcprop), cardLine, npts);
94  viewType output_z(Kokkos::view_wrap(ptr3, vcprop), cardLine, npts);
95 
96  Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_VALUE>::
97  getValues(output_x, input_x, work_line, vinv);
98 
99  Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_VALUE>::
100  getValues(output_y, input_y, work_line, vinv);
101 
102  Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_VALUE>::
103  getValues(output_z, input_z, work_line, vinv);
104 
105  // tensor product
106  ordinal_type idx = 0;
107  for (ordinal_type k=0;k<cardLine;++k) // z
108  for (ordinal_type j=0;j<cardLine;++j) // y
109  for (ordinal_type i=0;i<cardLine;++i,++idx) // x
110  for (ordinal_type l=0;l<npts;++l)
111  output.access(idx,l) = output_x.access(i,l)*output_y.access(j,l)*output_z.access(k,l);
112  break;
113  }
114  case OPERATOR_GRAD:
115  case OPERATOR_D1:
116  case OPERATOR_D2:
117  case OPERATOR_D3:
118  case OPERATOR_D4:
119  case OPERATOR_D5:
120  case OPERATOR_D6:
121  case OPERATOR_D7:
122  case OPERATOR_D8:
123  case OPERATOR_D9:
124  case OPERATOR_D10:
125  opDn = getOperatorOrder(opType);
126  case OPERATOR_Dn: {
127  const ordinal_type dkcard = opDn + 1;
128 
129  ordinal_type d = 0;
130  for (ordinal_type l1=0;l1<dkcard;++l1)
131  for (ordinal_type l0=0;l0<(l1+1);++l0) {
132  const ordinal_type mult_x = (opDn - l1);
133  const ordinal_type mult_y = l1 - l0;
134  const ordinal_type mult_z = l0;
135 
136  //std::cout << " l0, l1 = " << l0 << " " << l1 << std::endl;
137  //std::cout << " x , y , z = " << mult_x << " " << mult_y << " " << mult_z << std::endl;
138 
139  if (mult_x < 0) {
140  // pass
141  } else {
142  viewType work_line(Kokkos::view_wrap(ptr0, vcprop), cardLine, npts);
143  decltype(work_line) output_x, output_y, output_z;
144 
145  if (mult_x) {
146  output_x = viewType(Kokkos::view_wrap(ptr1, vcprop), cardLine, npts, 1);
147  Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_Dn>::
148  getValues(output_x, input_x, work_line, vinv, mult_x);
149  } else {
150  output_x = viewType(Kokkos::view_wrap(ptr1, vcprop), cardLine, npts);
151  Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_VALUE>::
152  getValues(output_x, input_x, work_line, vinv);
153  }
154 
155  if (mult_y) {
156  output_y = viewType(Kokkos::view_wrap(ptr2, vcprop), cardLine, npts, 1);
157  Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_Dn>::
158  getValues(output_y, input_y, work_line, vinv, mult_y);
159  } else {
160  output_y = viewType(Kokkos::view_wrap(ptr2, vcprop), cardLine, npts);
161  Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_VALUE>::
162  getValues(output_y, input_y, work_line, vinv);
163  }
164 
165  if (mult_z) {
166  output_z = viewType(Kokkos::view_wrap(ptr3, vcprop), cardLine, npts, 1);
167  Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_Dn>::
168  getValues(output_z, input_z, work_line, vinv, mult_z);
169  } else {
170  output_z = viewType(Kokkos::view_wrap(ptr3, vcprop), cardLine, npts);
171  Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_VALUE>::
172  getValues(output_z, input_z, work_line, vinv);
173  }
174 
175  // tensor product (extra dimension of ouput x,y and z are ignored)
176  ordinal_type idx = 0;
177  for (ordinal_type k=0;k<cardLine;++k) // z
178  for (ordinal_type j=0;j<cardLine;++j) // y
179  for (ordinal_type i=0;i<cardLine;++i,++idx) // x
180  for (ordinal_type l=0;l<npts;++l)
181  output.access(idx,l,d) = output_x.access(i,l,0)*output_y.access(j,l,0)*output_z.access(k,l,0);
182  ++d;
183  }
184  }
185  break;
186  }
187  default: {
188  INTREPID2_TEST_FOR_ABORT( true ,
189  ">>> ERROR (Basis_HGRAD_HEX_Cn_FEM): Operator type not implemented");
190  break;
191  }
192  }
193  }
194 
195  template<typename DT, ordinal_type numPtsPerEval,
196  typename outputValueValueType, class ...outputValueProperties,
197  typename inputPointValueType, class ...inputPointProperties,
198  typename vinvValueType, class ...vinvProperties>
199  void
200  Basis_HGRAD_HEX_Cn_FEM::
201  getValues( const typename DT::execution_space& space,
202  Kokkos::DynRankView<outputValueValueType,outputValueProperties...> outputValues,
203  const Kokkos::DynRankView<inputPointValueType, inputPointProperties...> inputPoints,
204  const Kokkos::DynRankView<vinvValueType, vinvProperties...> vinv,
205  const EOperator operatorType ) {
206  typedef Kokkos::DynRankView<outputValueValueType,outputValueProperties...> outputValueViewType;
207  typedef Kokkos::DynRankView<inputPointValueType, inputPointProperties...> inputPointViewType;
208  typedef Kokkos::DynRankView<vinvValueType, vinvProperties...> vinvViewType;
209  typedef typename ExecSpace<typename inputPointViewType::execution_space,typename DT::execution_space>::ExecSpaceType ExecSpaceType;
210 
211  // loopSize corresponds to cardinality
212  const auto loopSizeTmp1 = (inputPoints.extent(0)/numPtsPerEval);
213  const auto loopSizeTmp2 = (inputPoints.extent(0)%numPtsPerEval != 0);
214  const auto loopSize = loopSizeTmp1 + loopSizeTmp2;
215  Kokkos::RangePolicy<ExecSpaceType,Kokkos::Schedule<Kokkos::Static> > policy(space, 0, loopSize);
216 
217  typedef typename inputPointViewType::value_type inputPointType;
218 
219  const ordinal_type cardinality = outputValues.extent(0);
220  const ordinal_type cardLine = std::cbrt(cardinality);
221  const ordinal_type workSize = 4*cardLine;
222 
223  auto vcprop = Kokkos::common_view_alloc_prop(inputPoints);
224  typedef typename Kokkos::DynRankView< inputPointType, typename inputPointViewType::memory_space> workViewType;
225  workViewType work(Kokkos::view_alloc(space, "Basis_HGRAD_HEX_Cn_FEM::getValues::work", vcprop), workSize, inputPoints.extent(0));
226 
227  switch (operatorType) {
228  case OPERATOR_VALUE: {
229  typedef Functor<outputValueViewType,inputPointViewType,vinvViewType,workViewType,
230  OPERATOR_VALUE,numPtsPerEval> FunctorType;
231  Kokkos::parallel_for( policy, FunctorType(outputValues, inputPoints, vinv, work) );
232  break;
233  }
234  case OPERATOR_CURL: {
235  typedef Functor<outputValueViewType,inputPointViewType,vinvViewType,workViewType,
236  OPERATOR_CURL,numPtsPerEval> FunctorType;
237  Kokkos::parallel_for( policy, FunctorType(outputValues, inputPoints, vinv, work) );
238  break;
239  }
240  case OPERATOR_GRAD:
241  case OPERATOR_D1:
242  case OPERATOR_D2:
243  case OPERATOR_D3:
244  case OPERATOR_D4:
245  case OPERATOR_D5:
246  case OPERATOR_D6:
247  case OPERATOR_D7:
248  case OPERATOR_D8:
249  case OPERATOR_D9:
250  case OPERATOR_D10: {
251  typedef Functor<outputValueViewType,inputPointViewType,vinvViewType,workViewType,
252  OPERATOR_Dn,numPtsPerEval> FunctorType;
253  Kokkos::parallel_for( policy, FunctorType(outputValues, inputPoints, vinv, work,
254  getOperatorOrder(operatorType)) );
255  break;
256  }
257  default: {
258  INTREPID2_TEST_FOR_EXCEPTION( true , std::invalid_argument,
259  ">>> ERROR (Basis_HGRAD_HEX_Cn_FEM): Operator type not implemented" );
260  // break; commented out since exception is thrown
261  }
262  }
263  }
264  }
265 
266  // -------------------------------------------------------------------------------------
267  template<typename DT, typename OT, typename PT>
269  Basis_HGRAD_HEX_Cn_FEM( const ordinal_type order,
270  const EPointType pointType ) {
271 
272  // this should be in host
273  Basis_HGRAD_LINE_Cn_FEM<DT,OT,PT> lineBasis( order, pointType );
274  const auto cardLine = lineBasis.getCardinality();
275 
276  this->vinv_ = Kokkos::DynRankView<typename ScalarViewType::value_type,DT>("Hgrad::HEX::Cn::vinv", cardLine, cardLine);
277  lineBasis.getVandermondeInverse(this->vinv_);
278 
279  this->basisCardinality_ = cardLine*cardLine*cardLine;
280  this->basisDegree_ = order;
281  this->basisCellTopology_ = shards::CellTopology(shards::getCellTopologyData<shards::Hexahedron<8> >() );
282  this->basisType_ = BASIS_FEM_LAGRANGIAN;
283  this->basisCoordinates_ = COORDINATES_CARTESIAN;
284  this->functionSpace_ = FUNCTION_SPACE_HGRAD;
285  pointType_ = pointType;
286 
287  // initialize tags
288  {
289  // Basis-dependent initializations
290  const ordinal_type tagSize = 4; // size of DoF tag, i.e., number of fields in the tag
291  const ordinal_type posScDim = 0; // position in the tag, counting from 0, of the subcell dim
292  const ordinal_type posScOrd = 1; // position in the tag, counting from 0, of the subcell ordinal
293  const ordinal_type posDfOrd = 2; // position in the tag, counting from 0, of DoF ordinal relative to the subcell
294 
295  // 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.
296  // 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.)
297  INTREPID2_TEST_FOR_EXCEPTION( order > Parameters::MaxOrder, std::invalid_argument, "polynomial order exceeds the max supported by this class");
298 
299  // An array with local DoF tags assigned to the basis functions, in the order of their local enumeration
300  constexpr ordinal_type maxCardLine = Parameters::MaxOrder + 1;
301  ordinal_type tags[maxCardLine*maxCardLine*maxCardLine][4];
302 
303  const ordinal_type vert[2][2][2] = { { {0,1}, {3,2} },
304  { {4,5}, {7,6} } }; //[z][y][x]
305 
306  const ordinal_type edge_x[2][2] = { {0, 4}, {2, 6} };
307  const ordinal_type edge_y[2][2] = { {3, 7}, {1, 5} };
308  const ordinal_type edge_z[2][2] = { {8,11}, {9,10} };
309 
310  const ordinal_type face_yz[2] = {3, 1};
311  const ordinal_type face_xz[2] = {0, 2};
312  const ordinal_type face_xy[2] = {4, 5};
313 
314  {
315  ordinal_type idx = 0;
316  for (auto k=0;k<cardLine;++k) { // z
317  const auto tag_z = lineBasis.getDofTag(k);
318  for (ordinal_type j=0;j<cardLine;++j) { // y
319  const auto tag_y = lineBasis.getDofTag(j);
320  for (ordinal_type i=0;i<cardLine;++i,++idx) { // x
321  const auto tag_x = lineBasis.getDofTag(i);
322 
323  if (tag_x(0) == 0 && tag_y(0) == 0 && tag_z(0) == 0) {
324  // vertices
325  tags[idx][0] = 0; // vertex dof
326  tags[idx][1] = vert[tag_z(1)][tag_y(1)][tag_x(1)]; // vertex id
327  tags[idx][2] = 0; // local dof id
328  tags[idx][3] = 1; // total number of dofs in this vertex
329  } else if (tag_x(0) == 1 && tag_y(0) == 0 && tag_z(0) == 0) {
330  // edge, x edge, y vert, z vert,
331  tags[idx][0] = 1; // edge dof
332  tags[idx][1] = edge_x[tag_y(1)][tag_z(1)]; // edge id
333  tags[idx][2] = tag_x(2); // local dof id
334  tags[idx][3] = tag_x(3); // total number of dofs in this edge
335  } else if (tag_x(0) == 0 && tag_y(0) == 1 && tag_z(0) == 0) {
336  // edge, x vert, y edge, z vert,
337  tags[idx][0] = 1; // edge dof
338  tags[idx][1] = edge_y[tag_x(1)][tag_z(1)]; // edge id
339  tags[idx][2] = tag_y(2); // local dof id
340  tags[idx][3] = tag_y(3); // total number of dofs in this edge
341  } else if (tag_x(0) == 0 && tag_y(0) == 0 && tag_z(0) == 1) {
342  // edge, x vert, y vert, z edge,
343  tags[idx][0] = 1; // edge dof
344  tags[idx][1] = edge_z[tag_x(1)][tag_y(1)]; // edge id
345  tags[idx][2] = tag_z(2); // local dof id
346  tags[idx][3] = tag_z(3); // total number of dofs in this edge
347  } else if (tag_x(0) == 0 && tag_y(0) == 1 && tag_z(0) == 1) {
348  // face, x vert, y edge, z edge
349  tags[idx][0] = 2; // face dof
350  tags[idx][1] = face_yz[tag_x(1)]; // face id
351  tags[idx][2] = tag_y(2) + tag_y(3)*tag_z(2); // local dof id
352  tags[idx][3] = tag_y(3)*tag_z(3); // total number of dofs in this vertex
353  } else if (tag_x(0) == 1 && tag_y(0) == 0 && tag_z(0) == 1) {
354  // face, x edge, y vert, z edge
355  tags[idx][0] = 2; // face dof
356  tags[idx][1] = face_xz[tag_y(1)]; // face id
357  tags[idx][2] = tag_x(2) + tag_x(3)*tag_z(2); // local dof id
358  tags[idx][3] = tag_x(3)*tag_z(3); // total number of dofs in this vertex
359  } else if (tag_x(0) == 1 && tag_y(0) == 1 && tag_z(0) == 0) {
360  // face, x edge, y edge, z vert
361  tags[idx][0] = 2; // face dof
362  tags[idx][1] = face_xy[tag_z(1)]; // face id
363  tags[idx][2] = tag_x(2) + tag_x(3)*tag_y(2); // local dof id
364  tags[idx][3] = tag_x(3)*tag_y(3); // total number of dofs in this vertex
365  } else {
366  // interior
367  tags[idx][0] = 3; // interior dof
368  tags[idx][1] = 0;
369  tags[idx][2] = tag_x(2) + tag_x(3)*tag_y(2) + tag_x(3)*tag_y(3)*tag_z(2); // local dof id
370  tags[idx][3] = tag_x(3)*tag_y(3)*tag_z(3); // total number of dofs in this vertex
371  }
372  }
373  }
374  }
375  }
376 
377  OrdinalTypeArray1DHost tagView(&tags[0][0], this->basisCardinality_*4);
378 
379  // Basis-independent function sets tag and enum data in tagToOrdinal_ and ordinalToTag_ arrays:
380  // tags are constructed on host
381  this->setOrdinalTagData(this->tagToOrdinal_,
382  this->ordinalToTag_,
383  tagView,
384  this->basisCardinality_,
385  tagSize,
386  posScDim,
387  posScOrd,
388  posDfOrd);
389  }
390 
391  // dofCoords on host and create its mirror view to device
392  Kokkos::DynRankView<typename ScalarViewType::value_type,typename DT::execution_space::array_layout,Kokkos::HostSpace>
393  dofCoordsHost("dofCoordsHost", this->basisCardinality_, this->basisCellTopology_.getDimension());
394 
395  Kokkos::DynRankView<typename ScalarViewType::value_type,DT>
396  dofCoordsLine("dofCoordsLine", cardLine, 1);
397 
398  lineBasis.getDofCoords(dofCoordsLine);
399  auto dofCoordsLineHost = Kokkos::create_mirror_view(dofCoordsLine);
400  Kokkos::deep_copy(dofCoordsLineHost, dofCoordsLine);
401  {
402  ordinal_type idx = 0;
403  for (auto k=0;k<cardLine;++k) { // z
404  for (ordinal_type j=0;j<cardLine;++j) { // y
405  for (ordinal_type i=0;i<cardLine;++i,++idx) { // x
406  dofCoordsHost(idx,0) = dofCoordsLineHost(i,0);
407  dofCoordsHost(idx,1) = dofCoordsLineHost(j,0);
408  dofCoordsHost(idx,2) = dofCoordsLineHost(k,0);
409  }
410  }
411  }
412  }
413 
414  this->dofCoords_ = Kokkos::create_mirror_view(typename DT::memory_space(), dofCoordsHost);
415  Kokkos::deep_copy(this->dofCoords_, dofCoordsHost);
416  }
417 
418 }// namespace Intrepid2
419 
420 #endif
const OrdinalTypeArrayStride1DHost getDofTag(const ordinal_type dofOrd) const
DoF ordinal to DoF tag lookup.
ordinal_type getCardinality() const
Returns cardinality of the basis.
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.
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.