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  this->functionSpace_ = FUNCTION_SPACE_HDIV;
274 
275  // initialize tags
276  {
277  // Basis-dependent initializations
278  const ordinal_type tagSize = 4; // size of DoF tag, i.e., number of fields in the tag
279  const ordinal_type posScDim = 0; // position in the tag, counting from 0, of the subcell dim
280  const ordinal_type posScOrd = 1; // position in the tag, counting from 0, of the subcell ordinal
281  const ordinal_type posDfOrd = 2; // position in the tag, counting from 0, of DoF ordinal relative to the subcell
282 
283  // An array with local DoF tags assigned to the basis functions, in the order of their local enumeration
284  constexpr ordinal_type maxCardLine = Parameters::MaxOrder + 1;
285  constexpr ordinal_type maxCardBubble = Parameters::MaxOrder;
286  ordinal_type tags[2*maxCardLine*maxCardBubble][4];
287 
288  const ordinal_type edge_x[2] = {0,2};
289  const ordinal_type edge_y[2] = {3,1};
290  {
291  ordinal_type idx = 0;
292 
296 
297  // since there are x/y components in the interior
298  // dof sum should be computed before the information
299  // is assigned to tags
300  const ordinal_type
301  intr_ndofs_per_direction = (cardLine-2)*cardBubble,
302  intr_ndofs = 2*intr_ndofs_per_direction;
303 
304  // x component (lineBasis(y) bubbleBasis(x))
305  for (ordinal_type j=0;j<cardLine;++j) { // y
306  const auto tag_y = lineBasis.getDofTag(j);
307  for (ordinal_type i=0;i<cardBubble;++i,++idx) { // x
308  const auto tag_x = bubbleBasis.getDofTag(i);
309 
310  if (tag_x(0) == 1 && tag_y(0) == 0) {
311  // edge: x edge, y vert
312  tags[idx][0] = 1; // edge dof
313  tags[idx][1] = edge_x[tag_y(1)];
314  tags[idx][2] = tag_x(2); // local dof id
315  tags[idx][3] = tag_x(3); // total number of dofs in this vertex
316  } else {
317  // interior
318  tags[idx][0] = 2; // interior dof
319  tags[idx][1] = 0;
320  tags[idx][2] = tag_x(2) + tag_x(3)*tag_y(2); // local dof id
321  tags[idx][3] = intr_ndofs; // total number of dofs in this vertex
322  }
323  }
324  }
325 
326  // y component (bubbleBasis(y) lineBasis(x))
327  for (ordinal_type j=0;j<cardBubble;++j) { // y
328  const auto tag_y = bubbleBasis.getDofTag(j);
329  for (ordinal_type i=0;i<cardLine;++i,++idx) { // x
330  const auto tag_x = lineBasis.getDofTag(i);
331 
332  if (tag_x(0) == 0 && tag_y(0) == 1) {
333  // edge: x vert, y edge
334  tags[idx][0] = 1; // edge dof
335  tags[idx][1] = edge_y[tag_x(1)];
336  tags[idx][2] = tag_y(2); // local dof id
337  tags[idx][3] = tag_y(3); // total number of dofs in this vertex
338  } else {
339  // interior
340  tags[idx][0] = 2; // interior dof
341  tags[idx][1] = 0;
342  tags[idx][2] = intr_ndofs_per_direction + tag_x(2) + tag_x(3)*tag_y(2); // local dof id
343  tags[idx][3] = intr_ndofs; // total number of dofs in this vertex
344  }
345  }
346  }
347  INTREPID2_TEST_FOR_EXCEPTION( idx != this->basisCardinality_ , std::runtime_error,
348  ">>> ERROR (Basis_HDIV_QUAD_In_FEM): " \
349  "counted tag index is not same as cardinality." );
350  }
351 
352  OrdinalTypeArray1DHost tagView(&tags[0][0], this->basisCardinality_*4);
353 
354  // Basis-independent function sets tag and enum data in tagToOrdinal_ and ordinalToTag_ arrays:
355  // tags are constructed on host
356  this->setOrdinalTagData(this->tagToOrdinal_,
357  this->ordinalToTag_,
358  tagView,
359  this->basisCardinality_,
360  tagSize,
361  posScDim,
362  posScOrd,
363  posDfOrd);
364  }
365 
366  // dofCoords on host and create its mirror view to device
367  Kokkos::DynRankView<typename ScalarViewType::value_type,typename SpT::array_layout,Kokkos::HostSpace>
368  dofCoordsHost("dofCoordsHost", this->basisCardinality_, this->basisCellTopology_.getDimension());
369 
370  // dofCoeffs on host and create its mirror view to device
371  Kokkos::DynRankView<typename ScalarViewType::value_type,typename SpT::array_layout,Kokkos::HostSpace>
372  dofCoeffsHost("dofCoeffsHost", this->basisCardinality_, this->basisCellTopology_.getDimension());
373 
374  Kokkos::DynRankView<typename ScalarViewType::value_type,SpT>
375  dofCoordsLine("dofCoordsLine", cardLine, 1),
376  dofCoordsBubble("dofCoordsBubble", cardBubble, 1);
377 
378  lineBasis.getDofCoords(dofCoordsLine);
379  auto dofCoordsLineHost = Kokkos::create_mirror_view(Kokkos::HostSpace(), dofCoordsLine);
380  Kokkos::deep_copy(dofCoordsLineHost, dofCoordsLine);
381 
382  bubbleBasis.getDofCoords(dofCoordsBubble);
383  auto dofCoordsBubbleHost = Kokkos::create_mirror_view(Kokkos::HostSpace(), dofCoordsBubble);
384  Kokkos::deep_copy(dofCoordsBubbleHost, dofCoordsBubble);
385 
386  {
387  ordinal_type idx = 0;
388 
389  // x component (lineBasis(y) bubbleBasis(x))
390  for (ordinal_type j=0;j<cardLine;++j) { // y
391  for (ordinal_type i=0;i<cardBubble;++i,++idx) { // x
392  dofCoordsHost(idx,0) = dofCoordsBubbleHost(i,0);
393  dofCoordsHost(idx,1) = dofCoordsLineHost(j,0);
394  dofCoeffsHost(idx,1) = 1.0;
395  }
396  }
397 
398  // y component (bubbleBasis(y) lineBasis(x))
399  for (ordinal_type j=0;j<cardBubble;++j) { // y
400  for (ordinal_type i=0;i<cardLine;++i,++idx) { // x
401  dofCoordsHost(idx,0) = dofCoordsLineHost(i,0);
402  dofCoordsHost(idx,1) = dofCoordsBubbleHost(j,0);
403  dofCoeffsHost(idx,0) = 1.0;
404  }
405  }
406  }
407 
408  this->dofCoords_ = Kokkos::create_mirror_view(typename SpT::memory_space(), dofCoordsHost);
409  Kokkos::deep_copy(this->dofCoords_, dofCoordsHost);
410 
411  this->dofCoeffs_ = Kokkos::create_mirror_view(typename SpT::memory_space(), dofCoeffsHost);
412  Kokkos::deep_copy(this->dofCoeffs_, dofCoeffsHost);
413  }
414 
415 }
416 
417 #endif
Kokkos::View< ordinal_type *, typename ExecSpaceType::array_layout, Kokkos::HostSpace > OrdinalTypeArray1DHost
View type for 1d host array.
ordinal_type getCardinality() const
Returns cardinality of the basis.
Implementation of the locally H(grad)-compatible FEM basis of variable order on the [-1...
const OrdinalTypeArrayStride1DHost getDofTag(const ordinal_type dofOrd) const
DoF ordinal to DoF tag lookup.
static constexpr ordinal_type MaxOrder
The maximum reconstruction order.
Basis_HDIV_QUAD_In_FEM(const ordinal_type order, const EPointType pointType=POINTTYPE_EQUISPACED)
Constructor.