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