Intrepid2
Intrepid2_HDIV_QUAD_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_HDIV_QUAD_IN_FEM_DEF_HPP__
50 #define __INTREPID2_HDIV_QUAD_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_HDIV_QUAD_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 
79  const int dim_s = get_dimension_scalar(work);
80  auto ptr0 = work.data();
81  auto ptr1 = work.data()+cardLine*npts*dim_s;
82  auto ptr2 = work.data()+2*cardLine*npts*dim_s;
83 
84 
85  typedef typename Kokkos::DynRankView<typename workViewType::value_type, typename workViewType::memory_space> viewType;
86  auto vcprop = Kokkos::common_view_alloc_prop(work);
87 
88  switch (opType) {
89  case OPERATOR_VALUE: {
90  viewType workLine(Kokkos::view_wrap(ptr0, vcprop), cardLine, npts);
91  viewType outputLine(Kokkos::view_wrap(ptr1, vcprop), cardLine, npts);
92  viewType outputBubble(Kokkos::view_wrap(ptr2, vcprop), cardBubble, npts);
93 
94  // tensor product
95  ordinal_type idx = 0;
96  {
97  Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_VALUE>::
98  getValues(outputBubble, input_x, workLine, vinvBubble);
99 
100  Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_VALUE>::
101  getValues(outputLine, input_y, workLine, vinvLine);
102 
103  // x component (lineBasis(y) bubbleBasis(x))
104  const auto output_x = outputBubble;
105  const auto output_y = outputLine;
106 
107  for (ordinal_type j=0;j<cardLine;++j) // y
108  for (ordinal_type i=0;i<cardBubble;++i,++idx) // x
109  for (ordinal_type k=0;k<npts;++k) {
110  output.access(idx,k,0) = 0.0;
111  output.access(idx,k,1) = output_x.access(i,k)*output_y.access(j,k);
112  }
113  }
114  {
115  Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_VALUE>::
116  getValues(outputBubble, input_y, workLine, vinvBubble);
117 
118  Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_VALUE>::
119  getValues(outputLine, input_x, workLine, vinvLine);
120 
121  // y component (bubbleBasis(y) lineBasis(x))
122  const auto output_x = outputLine;
123  const auto output_y = outputBubble;
124  for (ordinal_type j=0;j<cardBubble;++j) // y
125  for (ordinal_type i=0;i<cardLine;++i,++idx) // x
126  for (ordinal_type k=0;k<npts;++k) {
127  output.access(idx,k,0) = output_x.access(i,k)*output_y.access(j,k);
128  output.access(idx,k,1) = 0.0;
129  }
130  }
131  break;
132  }
133  case OPERATOR_DIV: {
134  ordinal_type idx = 0;
135  { // x - component
136  viewType workLine(Kokkos::view_wrap(ptr0, vcprop), cardLine, npts);
137  // x bubble value
138  viewType output_x(Kokkos::view_wrap(ptr2, vcprop), cardBubble, npts);
139  // y line grad
140  viewType output_y(Kokkos::view_wrap(ptr1, vcprop), cardLine, npts,1);
141 
142  Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_VALUE>::
143  getValues(output_x, input_x, workLine, vinvBubble);
144 
145  Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_Dn>::
146  getValues(output_y, input_y, workLine, vinvLine, 1);
147 
148  // tensor product (extra dimension of ouput x and y are ignored)
149  for (ordinal_type j=0;j<cardLine;++j) // y
150  for (ordinal_type i=0;i<cardBubble;++i,++idx) // x
151  for (ordinal_type k=0;k<npts;++k)
152  output.access(idx,k) = output_x.access(i,k)*output_y.access(j,k,0);
153  }
154  { // y - component
155  viewType workLine(Kokkos::view_wrap(ptr0, vcprop), cardLine, npts);
156  // x line grad
157  viewType output_x(Kokkos::view_wrap(ptr1, vcprop), cardLine, npts,1);
158  // y bubble value
159  viewType output_y(Kokkos::view_wrap(ptr2, vcprop), cardBubble, npts);
160 
161  Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_VALUE>::
162  getValues(output_y, input_y, workLine, vinvBubble);
163 
164  Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_Dn>::
165  getValues(output_x, input_x, workLine, vinvLine, 1);
166 
167  // tensor product (extra dimension of ouput x and y are ignored)
168  for (ordinal_type j=0;j<cardBubble;++j) // y
169  for (ordinal_type i=0;i<cardLine;++i,++idx) // x
170  for (ordinal_type k=0;k<npts;++k)
171  output.access(idx,k) = output_x.access(i,k,0)*output_y.access(j,k);
172  }
173  break;
174  }
175  default: {
176  INTREPID2_TEST_FOR_ABORT( true,
177  ">>> ERROR: (Intrepid2::Basis_HDIV_QUAD_In_FEM::Serial::getValues) operator is not supported" );
178  }
179  }
180  }
181 
182  template<typename SpT, ordinal_type numPtsPerEval,
183  typename outputValueValueType, class ...outputValueProperties,
184  typename inputPointValueType, class ...inputPointProperties,
185  typename vinvValueType, class ...vinvProperties>
186  void
187  Basis_HDIV_QUAD_In_FEM::
188  getValues( Kokkos::DynRankView<outputValueValueType,outputValueProperties...> outputValues,
189  const Kokkos::DynRankView<inputPointValueType, inputPointProperties...> inputPoints,
190  const Kokkos::DynRankView<vinvValueType, vinvProperties...> vinvLine,
191  const Kokkos::DynRankView<vinvValueType, vinvProperties...> vinvBubble,
192  const EOperator operatorType ) {
193  typedef Kokkos::DynRankView<outputValueValueType,outputValueProperties...> outputValueViewType;
194  typedef Kokkos::DynRankView<inputPointValueType, inputPointProperties...> inputPointViewType;
195  typedef Kokkos::DynRankView<vinvValueType, vinvProperties...> vinvViewType;
196  typedef typename ExecSpace<typename inputPointViewType::execution_space,SpT>::ExecSpaceType ExecSpaceType;
197 
198  // loopSize corresponds to cardinality
199  const auto loopSizeTmp1 = (inputPoints.extent(0)/numPtsPerEval);
200  const auto loopSizeTmp2 = (inputPoints.extent(0)%numPtsPerEval != 0);
201  const auto loopSize = loopSizeTmp1 + loopSizeTmp2;
202  Kokkos::RangePolicy<ExecSpaceType,Kokkos::Schedule<Kokkos::Static> > policy(0, loopSize);
203 
204  typedef typename inputPointViewType::value_type inputPointType;
205 
206  const ordinal_type cardinality = outputValues.extent(0);
207  //get basis order based on basis cardinality.
208  ordinal_type order = 0; // = std::sqrt(cardinality/2);
209  ordinal_type cardBubble; // = std::sqrt(cardinality/2);
210  ordinal_type cardLine; // = cardBubble+1;
211  do {
212  cardBubble = Intrepid2::getPnCardinality<1>(order);
213  cardLine = Intrepid2::getPnCardinality<1>(++order);
214  } while((2*cardBubble*cardLine != cardinality) && (order != Parameters::MaxOrder));
215 
216  auto vcprop = Kokkos::common_view_alloc_prop(inputPoints);
217  typedef typename Kokkos::DynRankView< inputPointType, typename inputPointViewType::memory_space> workViewType;
218 
219  switch (operatorType) {
220  case OPERATOR_VALUE: {
221  auto workSize = Serial<OPERATOR_VALUE>::getWorkSizePerPoint(order);
222  workViewType work(Kokkos::view_alloc("Basis_HDIV_QUAD_In_FEM::getValues::work", vcprop), workSize, inputPoints.extent(0));
223  typedef Functor<outputValueViewType,inputPointViewType,vinvViewType, workViewType,
224  OPERATOR_VALUE,numPtsPerEval> FunctorType;
225  Kokkos::parallel_for( policy, FunctorType(outputValues, inputPoints, vinvLine, vinvBubble, work) );
226  break;
227  }
228  case OPERATOR_DIV: {
229  auto workSize = Serial<OPERATOR_DIV>::getWorkSizePerPoint(order);
230  workViewType work(Kokkos::view_alloc("Basis_HDIV_QUAD_In_FEM::getValues::work", vcprop), workSize, inputPoints.extent(0));
231  typedef Functor<outputValueViewType,inputPointViewType,vinvViewType, workViewType,
232  OPERATOR_DIV,numPtsPerEval> FunctorType;
233  Kokkos::parallel_for( policy, FunctorType(outputValues, inputPoints, vinvLine, vinvBubble, work) );
234  break;
235  }
236  default: {
237  INTREPID2_TEST_FOR_EXCEPTION( true , std::invalid_argument,
238  ">>> ERROR (Basis_HDIV_QUAD_In_FEM): Operator type not implemented" );
239  }
240  }
241  }
242  }
243 
244  // -------------------------------------------------------------------------------------
245  template<typename SpT, typename OT, typename PT>
247  Basis_HDIV_QUAD_In_FEM( const ordinal_type order,
248  const EPointType pointType ) {
249 
250  INTREPID2_TEST_FOR_EXCEPTION( !(pointType == POINTTYPE_EQUISPACED ||
251  pointType == POINTTYPE_WARPBLEND), std::invalid_argument,
252  ">>> ERROR (Basis_HDIV_QUAD_In_FEM): pointType must be either equispaced or warpblend.");
253 
254  // this should be in host
255  Basis_HGRAD_LINE_Cn_FEM<SpT,OT,PT> lineBasis( order, pointType );
256  Basis_HGRAD_LINE_Cn_FEM<SpT,OT,PT> bubbleBasis( order - 1, POINTTYPE_GAUSS );
257 
258  const ordinal_type
259  cardLine = lineBasis.getCardinality(),
260  cardBubble = bubbleBasis.getCardinality();
261 
262  this->vinvLine_ = Kokkos::DynRankView<typename scalarViewType::value_type,SpT>("Hdiv::Quad::In::vinvLine", cardLine, cardLine);
263  this->vinvBubble_ = Kokkos::DynRankView<typename scalarViewType::value_type,SpT>("Hdiv::Quad::In::vinvBubble", cardBubble, cardBubble);
264 
265  lineBasis.getVandermondeInverse(this->vinvLine_);
266  bubbleBasis.getVandermondeInverse(this->vinvBubble_);
267 
268  this->basisCardinality_ = 2*cardLine*cardBubble;
269  this->basisDegree_ = order;
270  this->basisCellTopology_ = shards::CellTopology(shards::getCellTopologyData<shards::Quadrilateral<4> >() );
271  this->basisType_ = BASIS_FEM_FIAT;
272  this->basisCoordinates_ = COORDINATES_CARTESIAN;
273 
274  // initialize tags
275  {
276  // Basis-dependent initializations
277  const ordinal_type tagSize = 4; // size of DoF tag, i.e., number of fields in the tag
278  const ordinal_type posScDim = 0; // position in the tag, counting from 0, of the subcell dim
279  const ordinal_type posScOrd = 1; // position in the tag, counting from 0, of the subcell ordinal
280  const ordinal_type posDfOrd = 2; // position in the tag, counting from 0, of DoF ordinal relative to the subcell
281 
282  // An array with local DoF tags assigned to the basis functions, in the order of their local enumeration
283  constexpr ordinal_type maxCardLine = Parameters::MaxOrder + 1;
284  constexpr ordinal_type maxCardBubble = Parameters::MaxOrder;
285  ordinal_type tags[2*maxCardLine*maxCardBubble][4];
286 
287  const ordinal_type edge_x[2] = {0,2};
288  const ordinal_type edge_y[2] = {3,1};
289  {
290  ordinal_type idx = 0;
291 
295 
296  // since there are x/y components in the interior
297  // dof sum should be computed before the information
298  // is assigned to tags
299  const ordinal_type
300  intr_ndofs_per_direction = (cardLine-2)*cardBubble,
301  intr_ndofs = 2*intr_ndofs_per_direction;
302 
303  // x component (lineBasis(y) bubbleBasis(x))
304  for (ordinal_type j=0;j<cardLine;++j) { // y
305  const auto tag_y = lineBasis.getDofTag(j);
306  for (ordinal_type i=0;i<cardBubble;++i,++idx) { // x
307  const auto tag_x = bubbleBasis.getDofTag(i);
308 
309  if (tag_x(0) == 1 && tag_y(0) == 0) {
310  // edge: x edge, y vert
311  tags[idx][0] = 1; // edge dof
312  tags[idx][1] = edge_x[tag_y(1)];
313  tags[idx][2] = tag_x(2); // local dof id
314  tags[idx][3] = tag_x(3); // total number of dofs in this vertex
315  } else {
316  // interior
317  tags[idx][0] = 2; // interior dof
318  tags[idx][1] = 0;
319  tags[idx][2] = tag_x(2) + tag_x(3)*tag_y(2); // local dof id
320  tags[idx][3] = intr_ndofs; // total number of dofs in this vertex
321  }
322  }
323  }
324 
325  // y component (bubbleBasis(y) lineBasis(x))
326  for (ordinal_type j=0;j<cardBubble;++j) { // y
327  const auto tag_y = bubbleBasis.getDofTag(j);
328  for (ordinal_type i=0;i<cardLine;++i,++idx) { // x
329  const auto tag_x = lineBasis.getDofTag(i);
330 
331  if (tag_x(0) == 0 && tag_y(0) == 1) {
332  // edge: x vert, y edge
333  tags[idx][0] = 1; // edge dof
334  tags[idx][1] = edge_y[tag_x(1)];
335  tags[idx][2] = tag_y(2); // local dof id
336  tags[idx][3] = tag_y(3); // total number of dofs in this vertex
337  } else {
338  // interior
339  tags[idx][0] = 2; // interior dof
340  tags[idx][1] = 0;
341  tags[idx][2] = intr_ndofs_per_direction + tag_x(2) + tag_x(3)*tag_y(2); // local dof id
342  tags[idx][3] = intr_ndofs; // total number of dofs in this vertex
343  }
344  }
345  }
346  INTREPID2_TEST_FOR_EXCEPTION( idx != this->basisCardinality_ , std::runtime_error,
347  ">>> ERROR (Basis_HDIV_QUAD_In_FEM): " \
348  "counted tag index is not same as cardinality." );
349  }
350 
351  ordinal_type_array_1d_host tagView(&tags[0][0], this->basisCardinality_*4);
352 
353  // Basis-independent function sets tag and enum data in tagToOrdinal_ and ordinalToTag_ arrays:
354  // tags are constructed on host
355  this->setOrdinalTagData(this->tagToOrdinal_,
356  this->ordinalToTag_,
357  tagView,
358  this->basisCardinality_,
359  tagSize,
360  posScDim,
361  posScOrd,
362  posDfOrd);
363  }
364 
365  // dofCoords on host and create its mirror view to device
366  Kokkos::DynRankView<typename scalarViewType::value_type,typename SpT::array_layout,Kokkos::HostSpace>
367  dofCoordsHost("dofCoordsHost", this->basisCardinality_, this->basisCellTopology_.getDimension());
368 
369  // dofCoeffs on host and create its mirror view to device
370  Kokkos::DynRankView<typename scalarViewType::value_type,typename SpT::array_layout,Kokkos::HostSpace>
371  dofCoeffsHost("dofCoeffsHost", this->basisCardinality_, this->basisCellTopology_.getDimension());
372 
373  Kokkos::DynRankView<typename scalarViewType::value_type,SpT>
374  dofCoordsLine("dofCoordsLine", cardLine, 1),
375  dofCoordsBubble("dofCoordsBubble", cardBubble, 1);
376 
377  lineBasis.getDofCoords(dofCoordsLine);
378  auto dofCoordsLineHost = Kokkos::create_mirror_view(Kokkos::HostSpace(), dofCoordsLine);
379  Kokkos::deep_copy(dofCoordsLineHost, dofCoordsLine);
380 
381  bubbleBasis.getDofCoords(dofCoordsBubble);
382  auto dofCoordsBubbleHost = Kokkos::create_mirror_view(Kokkos::HostSpace(), dofCoordsBubble);
383  Kokkos::deep_copy(dofCoordsBubbleHost, dofCoordsBubble);
384 
385  {
386  ordinal_type idx = 0;
387 
388  // x component (lineBasis(y) bubbleBasis(x))
389  for (ordinal_type j=0;j<cardLine;++j) { // y
390  for (ordinal_type i=0;i<cardBubble;++i,++idx) { // x
391  dofCoordsHost(idx,0) = dofCoordsBubbleHost(i,0);
392  dofCoordsHost(idx,1) = dofCoordsLineHost(j,0);
393  dofCoeffsHost(idx,1) = 1.0;
394  }
395  }
396 
397  // y component (bubbleBasis(y) lineBasis(x))
398  for (ordinal_type j=0;j<cardBubble;++j) { // y
399  for (ordinal_type i=0;i<cardLine;++i,++idx) { // x
400  dofCoordsHost(idx,0) = dofCoordsLineHost(i,0);
401  dofCoordsHost(idx,1) = dofCoordsBubbleHost(j,0);
402  dofCoeffsHost(idx,0) = 1.0;
403  }
404  }
405  }
406 
407  this->dofCoords_ = Kokkos::create_mirror_view(typename SpT::memory_space(), dofCoordsHost);
408  Kokkos::deep_copy(this->dofCoords_, dofCoordsHost);
409 
410  this->dofCoeffs_ = Kokkos::create_mirror_view(typename SpT::memory_space(), dofCoeffsHost);
411  Kokkos::deep_copy(this->dofCoeffs_, dofCoeffsHost);
412  }
413 
414 }
415 
416 #endif
ordinal_type getCardinality() const
Returns cardinality of the basis.
Kokkos::View< ordinal_type *,typename ExecSpaceType::array_layout, Kokkos::HostSpace > ordinal_type_array_1d_host
View type for 1d host array.
const ordinal_type_array_stride_1d_host getDofTag(const ordinal_type dofOrd) const
DoF ordinal to DoF tag lookup.
Implementation of the locally H(grad)-compatible FEM basis of variable order on the [-1...
static constexpr ordinal_type MaxOrder
The maximum reconstruction order.
Basis_HDIV_QUAD_In_FEM(const ordinal_type order, const EPointType pointType=POINTTYPE_EQUISPACED)
Constructor.
virtual void getDofCoords(scalarViewType dofCoords) const
Returns spatial locations (coordinates) of degrees of freedom on the reference cell.