Intrepid2
Intrepid2_HCURL_QUAD_In_FEMDef.hpp
Go to the documentation of this file.
1// @HEADER
2// *****************************************************************************
3// Intrepid2 Package
4//
5// Copyright 2007 NTESS and the Intrepid2 contributors.
6// SPDX-License-Identifier: BSD-3-Clause
7// *****************************************************************************
8// @HEADER
9
16#ifndef __INTREPID2_HCURL_QUAD_IN_FEM_DEF_HPP__
17#define __INTREPID2_HCURL_QUAD_IN_FEM_DEF_HPP__
18
19namespace Intrepid2 {
20
21 // -------------------------------------------------------------------------------------
22 namespace Impl {
23
24 template<EOperator OpType>
25 template<typename OutputViewType,
26 typename InputViewType,
27 typename WorkViewType,
28 typename VinvViewType>
29 KOKKOS_INLINE_FUNCTION
30 void
31 Basis_HCURL_QUAD_In_FEM::Serial<OpType>::
32 getValues( OutputViewType output,
33 const InputViewType input,
34 WorkViewType work,
35 const VinvViewType vinvLine,
36 const VinvViewType vinvBubble) {
37 const ordinal_type cardLine = vinvLine.extent(0);
38 const ordinal_type cardBubble = vinvBubble.extent(0);
39
40 const ordinal_type npts = input.extent(0);
41
42 typedef Kokkos::pair<ordinal_type,ordinal_type> range_type;
43 const auto input_x = Kokkos::subview(input, Kokkos::ALL(), range_type(0,1));
44 const auto input_y = Kokkos::subview(input, Kokkos::ALL(), range_type(1,2));
45
46 const int dim_s = get_dimension_scalar(input);
47 auto ptr0 = work.data();
48 auto ptr1 = work.data()+cardLine*npts*dim_s;
49 auto ptr2 = work.data()+2*cardLine*npts*dim_s;
50
51 typedef typename Kokkos::DynRankView<typename InputViewType::value_type, typename WorkViewType::memory_space> ViewType;
52 auto vcprop = Kokkos::common_view_alloc_prop(input);
53
54 switch (OpType) {
55 case OPERATOR_VALUE: {
56 ViewType workLine(Kokkos::view_wrap(ptr0, vcprop), cardLine, npts);
57 ViewType outputLine(Kokkos::view_wrap(ptr1, vcprop), cardLine, npts);
58 ViewType outputBubble(Kokkos::view_wrap(ptr2, vcprop), cardBubble, npts);
59
60 // tensor product
61 ordinal_type idx = 0;
62 {
63 Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_VALUE>::
64 getValues(outputBubble, input_x, workLine, vinvBubble);
65
66 Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_VALUE>::
67 getValues(outputLine, input_y, workLine, vinvLine);
68
69 // x component (lineBasis(y) bubbleBasis(x))
70 const auto output_x = outputBubble;
71 const auto output_y = outputLine;
72
73 for (ordinal_type j=0;j<cardLine;++j) // y
74 for (ordinal_type i=0;i<cardBubble;++i,++idx) // x
75 for (ordinal_type k=0;k<npts;++k) {
76 output.access(idx,k,0) = output_x.access(i,k)*output_y.access(j,k);
77 output.access(idx,k,1) = 0.0;
78 }
79 }
80
81 {
82 Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_VALUE>::
83 getValues(outputBubble, input_y, workLine, vinvBubble);
84
85 Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_VALUE>::
86 getValues(outputLine, input_x, workLine, vinvLine);
87
88 // y component (bubbleBasis(y) lineBasis(x))
89 const auto output_x = outputLine;
90 const auto output_y = outputBubble;
91 for (ordinal_type j=0;j<cardBubble;++j) // y
92 for (ordinal_type i=0;i<cardLine;++i,++idx) // x
93 for (ordinal_type k=0;k<npts;++k) {
94 output.access(idx,k,0) = 0.0;
95 output.access(idx,k,1) = output_x.access(i,k)*output_y.access(j,k);
96 }
97 }
98
99 break;
100 }
101 case OPERATOR_CURL: {
102 ordinal_type idx = 0;
103 { // x - component
104 ViewType workLine(Kokkos::view_wrap(ptr0, vcprop), cardLine, npts);
105 // x bubble value
106 ViewType output_x(Kokkos::view_wrap(ptr2, vcprop), cardBubble, npts);
107 // y line grad
108 ViewType output_y(Kokkos::view_wrap(ptr1, vcprop), cardLine, npts,1);
109
110 Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_VALUE>::
111 getValues(output_x, input_x, workLine, vinvBubble);
112
113 Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_Dn>::
114 getValues(output_y, input_y, workLine, vinvLine, 1);
115
116 // tensor product (extra dimension of ouput x and y are ignored)
117 for (ordinal_type j=0;j<cardLine;++j) // y
118 for (ordinal_type i=0;i<cardBubble;++i,++idx) // x
119 for (ordinal_type k=0;k<npts;++k)
120 output.access(idx,k) = -output_x.access(i,k)*output_y.access(j,k,0);
121 }
122 { // y - component
123 ViewType workLine(Kokkos::view_wrap(ptr0, vcprop), cardLine, npts);
124 // x line grad
125 ViewType output_x(Kokkos::view_wrap(ptr1, vcprop), cardLine, npts,1);
126 // y bubble value
127 ViewType output_y(Kokkos::view_wrap(ptr2, vcprop), cardBubble, npts);
128
129 Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_VALUE>::
130 getValues(output_y, input_y, workLine, vinvBubble);
131
132 Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_Dn>::
133 getValues(output_x, input_x, workLine, vinvLine, 1);
134
135 // tensor product (extra dimension of ouput x and y are ignored)
136 for (ordinal_type j=0;j<cardBubble;++j) // y
137 for (ordinal_type i=0;i<cardLine;++i,++idx) // x
138 for (ordinal_type k=0;k<npts;++k)
139 output.access(idx,k) = output_x.access(i,k,0)*output_y.access(j,k);
140 }
141 break;
142 }
143 default: {
144 INTREPID2_TEST_FOR_ABORT( true,
145 ">>> ERROR: (Intrepid2::Basis_HCURL_QUAD_In_FEM::Serial::getValues) operator is not supported" );
146 }
147 }
148 }
149
150 template<typename DT, ordinal_type numPtsPerEval,
151 typename outputValueValueType, class ...outputValueProperties,
152 typename inputPointValueType, class ...inputPointProperties,
153 typename vinvValueType, class ...vinvProperties>
154 void
155 Basis_HCURL_QUAD_In_FEM::
156 getValues( Kokkos::DynRankView<outputValueValueType,outputValueProperties...> outputValues,
157 const Kokkos::DynRankView<inputPointValueType, inputPointProperties...> inputPoints,
158 const Kokkos::DynRankView<vinvValueType, vinvProperties...> vinvLine,
159 const Kokkos::DynRankView<vinvValueType, vinvProperties...> vinvBubble,
160 const EOperator operatorType ) {
161 typedef Kokkos::DynRankView<outputValueValueType,outputValueProperties...> outputValueViewType;
162 typedef Kokkos::DynRankView<inputPointValueType, inputPointProperties...> inputPointViewType;
163 typedef Kokkos::DynRankView<vinvValueType, vinvProperties...> vinvViewType;
164 typedef typename ExecSpace<typename inputPointViewType::execution_space,typename DT::execution_space>::ExecSpaceType ExecSpaceType;
165
166 // loopSize corresponds to cardinality
167 const auto loopSizeTmp1 = (inputPoints.extent(0)/numPtsPerEval);
168 const auto loopSizeTmp2 = (inputPoints.extent(0)%numPtsPerEval != 0);
169 const auto loopSize = loopSizeTmp1 + loopSizeTmp2;
170 Kokkos::RangePolicy<ExecSpaceType,Kokkos::Schedule<Kokkos::Static> > policy(0, loopSize);
171
172 typedef typename inputPointViewType::value_type inputPointType;
173
174 const ordinal_type cardinality = outputValues.extent(0);
175 //get basis order based on basis cardinality.
176 ordinal_type order = 0;
177 ordinal_type cardBubble; // = std::sqrt(cardinality/2);
178 ordinal_type cardLine; // = cardBubble+1;
179 do {
180 cardBubble = Intrepid2::getPnCardinality<1>(order);
181 cardLine = Intrepid2::getPnCardinality<1>(++order);
182 } while((2*cardBubble*cardLine != cardinality) && (order != Parameters::MaxOrder));
183
184 auto vcprop = Kokkos::common_view_alloc_prop(inputPoints);
185 typedef typename Kokkos::DynRankView< inputPointType, typename inputPointViewType::memory_space> workViewType;
186
187 switch (operatorType) {
188 case OPERATOR_VALUE: {
189 auto workSize = Serial<OPERATOR_VALUE>::getWorkSizePerPoint(order);
190 workViewType work(Kokkos::view_alloc("Basis_HCURL_QUAD_In_FEM::getValues::work", vcprop), workSize, inputPoints.extent(0));
191 typedef Functor<outputValueViewType,inputPointViewType,vinvViewType, workViewType,
192 OPERATOR_VALUE,numPtsPerEval> FunctorType;
193 Kokkos::parallel_for( policy, FunctorType(outputValues, inputPoints, vinvLine, vinvBubble, work) );
194 break;
195 }
196 case OPERATOR_CURL: {
197 auto workSize = Serial<OPERATOR_CURL>::getWorkSizePerPoint(order);
198 workViewType work(Kokkos::view_alloc("Basis_HCURL_QUAD_In_FEM::getValues::work", vcprop), workSize, inputPoints.extent(0));
199 typedef Functor<outputValueViewType,inputPointViewType,vinvViewType, workViewType,
200 OPERATOR_CURL,numPtsPerEval> FunctorType;
201 Kokkos::parallel_for( policy, FunctorType(outputValues, inputPoints, vinvLine, vinvBubble, work) );
202 break;
203 }
204 default: {
205 INTREPID2_TEST_FOR_EXCEPTION( true , std::invalid_argument,
206 ">>> ERROR (Basis_HCURL_QUAD_In_FEM): Operator type not implemented" );
207 }
208 }
209 }
210 }
211
212 // -------------------------------------------------------------------------------------
213 template<typename DT, typename OT, typename PT>
215 Basis_HCURL_QUAD_In_FEM( const ordinal_type order,
216 const EPointType pointType ) {
217
218 INTREPID2_TEST_FOR_EXCEPTION( !(pointType == POINTTYPE_EQUISPACED ||
219 pointType == POINTTYPE_WARPBLEND), std::invalid_argument,
220 ">>> ERROR (Basis_HCURL_QUAD_In_FEM): pointType must be either equispaced or warpblend.");
221
222 // this should be in host
223 Basis_HGRAD_LINE_Cn_FEM<DT,OT,PT> lineBasis( order, pointType );
224 Basis_HVOL_LINE_Cn_FEM<DT,OT,PT> bubbleBasis( order - 1, POINTTYPE_GAUSS );
225
226 const ordinal_type
227 cardLine = lineBasis.getCardinality(),
228 cardBubble = bubbleBasis.getCardinality();
229
230 this->vinvLine_ = Kokkos::DynRankView<typename ScalarViewType::value_type,DT>("Hcurl::Quad::In::vinvLine", cardLine, cardLine);
231 this->vinvBubble_ = Kokkos::DynRankView<typename ScalarViewType::value_type,DT>("Hcurl::Quad::In::vinvBubble", cardBubble, cardBubble);
232
233 lineBasis.getVandermondeInverse(this->vinvLine_);
234 bubbleBasis.getVandermondeInverse(this->vinvBubble_);
235
236 const ordinal_type spaceDim = 2;
237 this->basisCardinality_ = 2*cardLine*cardBubble;
238 this->basisDegree_ = order;
239 this->basisCellTopologyKey_ = shards::Quadrilateral<4>::key;
240 this->basisType_ = BASIS_FEM_LAGRANGIAN;
241 this->basisCoordinates_ = COORDINATES_CARTESIAN;
242 this->functionSpace_ = FUNCTION_SPACE_HCURL;
243 pointType_ = pointType;
244
245 // initialize tags
246 {
247 // Basis-dependent initializations
248 const ordinal_type tagSize = 4; // size of DoF tag, i.e., number of fields in the tag
249 const ordinal_type posScDim = 0; // position in the tag, counting from 0, of the subcell dim
250 const ordinal_type posScOrd = 1; // position in the tag, counting from 0, of the subcell ordinal
251 const ordinal_type posDfOrd = 2; // position in the tag, counting from 0, of DoF ordinal relative to the subcell
252
253 // 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.
254 // 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.)
255 INTREPID2_TEST_FOR_EXCEPTION( order > Parameters::MaxOrder, std::invalid_argument, "polynomial order exceeds the max supported by this class");
256
257 // An array with local DoF tags assigned to the basis functions, in the order of their local enumeration
258 constexpr ordinal_type maxCardLine = Parameters::MaxOrder + 1;
259 constexpr ordinal_type maxCardBubble = Parameters::MaxOrder;
260 ordinal_type tags[2*maxCardLine*maxCardBubble][4];
261
262 const ordinal_type edge_x[2] = {0,2};
263 const ordinal_type edge_y[2] = {3,1};
264 {
265 ordinal_type idx = 0;
266
270
271 // since there are x/y components in the interior
272 // dof sum should be computed before the information
273 // is assigned to tags
274 const ordinal_type
275 intr_ndofs_per_direction = (cardLine-2)*cardBubble,
276 intr_ndofs = 2*intr_ndofs_per_direction;
277
278 // x component (lineBasis(y) bubbleBasis(x))
279 for (ordinal_type j=0;j<cardLine;++j) { // y
280 const auto tag_y = lineBasis.getDofTag(j);
281 for (ordinal_type i=0;i<cardBubble;++i,++idx) { // x
282 const auto tag_x = bubbleBasis.getDofTag(i);
283
284 if (tag_x(0) == 1 && tag_y(0) == 0) {
285 // edge: x edge, y vert
286 tags[idx][0] = 1; // edge dof
287 tags[idx][1] = edge_x[tag_y(1)];
288 tags[idx][2] = tag_x(2); // local dof id
289 tags[idx][3] = tag_x(3); // total number of dofs in this vertex
290 } else {
291 // interior
292 tags[idx][0] = 2; // interior dof
293 tags[idx][1] = 0;
294 tags[idx][2] = tag_x(2) + tag_x(3)*tag_y(2); // local dof id
295 tags[idx][3] = intr_ndofs; // total number of dofs in this vertex
296 }
297 }
298 }
299
300 // y component (bubbleBasis(y) lineBasis(x))
301 for (ordinal_type j=0;j<cardBubble;++j) { // y
302 const auto tag_y = bubbleBasis.getDofTag(j);
303 for (ordinal_type i=0;i<cardLine;++i,++idx) { // x
304 const auto tag_x = lineBasis.getDofTag(i);
305
306 if (tag_x(0) == 0 && tag_y(0) == 1) {
307 // edge: x vert, y edge
308 tags[idx][0] = 1; // edge dof
309 tags[idx][1] = edge_y[tag_x(1)];
310 tags[idx][2] = tag_y(2); // local dof id
311 tags[idx][3] = tag_y(3); // total number of dofs in this vertex
312 } else {
313 // interior
314 tags[idx][0] = 2; // interior dof
315 tags[idx][1] = 0;
316 tags[idx][2] = intr_ndofs_per_direction + tag_x(2) + tag_x(3)*tag_y(2); // local dof id
317 tags[idx][3] = intr_ndofs; // total number of dofs in this vertex
318 }
319 }
320 }
321 INTREPID2_TEST_FOR_EXCEPTION( idx != this->basisCardinality_ , std::runtime_error,
322 ">>> ERROR (Basis_HCURL_QUAD_In_FEM): " \
323 "counted tag index is not same as cardinality." );
324 }
325
326 OrdinalTypeArray1DHost tagView(&tags[0][0], this->basisCardinality_*4);
327
328 // Basis-independent function sets tag and enum data in tagToOrdinal_ and ordinalToTag_ arrays:
329 // tags are constructed on host
330 this->setOrdinalTagData(this->tagToOrdinal_,
331 this->ordinalToTag_,
332 tagView,
333 this->basisCardinality_,
334 tagSize,
335 posScDim,
336 posScOrd,
337 posDfOrd);
338 }
339
340 // dofCoords on host and create its mirror view to device
341 Kokkos::DynRankView<typename ScalarViewType::value_type,typename DT::execution_space::array_layout,Kokkos::HostSpace>
342 dofCoordsHost("dofCoordsHost", this->basisCardinality_, spaceDim);
343
344 // dofCoeffs on host and create its mirror view to device
345 Kokkos::DynRankView<typename ScalarViewType::value_type,typename DT::execution_space::array_layout,Kokkos::HostSpace>
346 dofCoeffsHost("dofCoeffsHost", this->basisCardinality_, spaceDim);
347
348 Kokkos::DynRankView<typename ScalarViewType::value_type,DT>
349 dofCoordsLine("dofCoordsLine", cardLine, 1),
350 dofCoordsBubble("dofCoordsBubble", cardBubble, 1);
351
352 lineBasis.getDofCoords(dofCoordsLine);
353 auto dofCoordsLineHost = Kokkos::create_mirror_view(dofCoordsLine);
354 Kokkos::deep_copy(dofCoordsLineHost, dofCoordsLine);
355
356 bubbleBasis.getDofCoords(dofCoordsBubble);
357 auto dofCoordsBubbleHost = Kokkos::create_mirror_view(dofCoordsBubble);
358 Kokkos::deep_copy(dofCoordsBubbleHost, dofCoordsBubble);
359
360 {
361 ordinal_type idx = 0;
362
363 // x component (lineBasis(y) bubbleBasis(x))
364 for (ordinal_type j=0;j<cardLine;++j) { // y
365 for (ordinal_type i=0;i<cardBubble;++i,++idx) { // x
366 dofCoordsHost(idx,0) = dofCoordsBubbleHost(i,0);
367 dofCoordsHost(idx,1) = dofCoordsLineHost(j,0);
368 dofCoeffsHost(idx,0) = 1.0;
369 }
370 }
371
372 // y component (bubbleBasis(y) lineBasis(x))
373 for (ordinal_type j=0;j<cardBubble;++j) { // y
374 for (ordinal_type i=0;i<cardLine;++i,++idx) { // x
375 dofCoordsHost(idx,0) = dofCoordsLineHost(i,0);
376 dofCoordsHost(idx,1) = dofCoordsBubbleHost(j,0);
377 dofCoeffsHost(idx,1) = 1.0;
378 }
379 }
380 }
381
382 this->dofCoords_ = Kokkos::create_mirror_view(typename DT::memory_space(), dofCoordsHost);
383 Kokkos::deep_copy(this->dofCoords_, dofCoordsHost);
384
385 this->dofCoeffs_ = Kokkos::create_mirror_view(typename DT::memory_space(), dofCoeffsHost);
386 Kokkos::deep_copy(this->dofCoeffs_, dofCoeffsHost);
387 }
388
389 template<typename DT, typename OT, typename PT>
390 void
392 ordinal_type& perTeamSpaceSize,
393 ordinal_type& perThreadSpaceSize,
394 const PointViewType inputPoints,
395 const EOperator operatorType) const {
396 perTeamSpaceSize = 0;
397 perThreadSpaceSize = (2*this->vinvLine_.extent(0)+this->vinvBubble_.extent(0))*get_dimension_scalar(inputPoints)*sizeof(typename BasisBase::scalarType);
398 }
399
400 template<typename DT, typename OT, typename PT>
401 KOKKOS_INLINE_FUNCTION
402 void
403 Basis_HCURL_QUAD_In_FEM<DT,OT,PT>::getValues(
404 OutputViewType outputValues,
405 const PointViewType inputPoints,
406 const EOperator operatorType,
407 const typename Kokkos::TeamPolicy<typename DT::execution_space>::member_type& team_member,
408 const typename DT::execution_space::scratch_memory_space & scratchStorage,
409 const ordinal_type subcellDim,
410 const ordinal_type subcellOrdinal) const {
411
412 INTREPID2_TEST_FOR_ABORT( !((subcellDim == -1) && (subcellOrdinal == -1)),
413 ">>> ERROR: (Intrepid2::Basis_HCURL_QUAD_In_FEM::getValues), The capability of selecting subsets of basis functions has not been implemented yet.");
414
415 const int numPoints = inputPoints.extent(0);
416 using ScalarType = typename ScalarTraits<typename PointViewType::value_type>::scalar_type;
417 using WorkViewType = Kokkos::DynRankView< ScalarType,typename DT::execution_space::scratch_memory_space,Kokkos::MemoryTraits<Kokkos::Unmanaged> >;
418 ordinal_type sizePerPoint = (2*this->vinvLine_.extent(0)+this->vinvBubble_.extent(0))*get_dimension_scalar(inputPoints);
419 WorkViewType workView(scratchStorage, sizePerPoint*team_member.team_size());
420 using range_type = Kokkos::pair<ordinal_type,ordinal_type>;
421
422 switch(operatorType) {
423 case OPERATOR_VALUE:
424 Kokkos::parallel_for (Kokkos::TeamThreadRange (team_member, numPoints), [=, &vinvLine_ = this->vinvLine_, &vinvBubble_ = this-> vinvBubble_] (ordinal_type& pt) {
425 auto output = Kokkos::subview( outputValues, Kokkos::ALL(), range_type (pt,pt+1), Kokkos::ALL() );
426 const auto input = Kokkos::subview( inputPoints, range_type(pt, pt+1), Kokkos::ALL() );
427 WorkViewType work(workView.data() + sizePerPoint*team_member.team_rank(), sizePerPoint);
428 Impl::Basis_HCURL_QUAD_In_FEM::Serial<OPERATOR_VALUE>::getValues( output, input, work, vinvLine_, vinvBubble_ );
429 });
430 break;
431 case OPERATOR_CURL:
432 Kokkos::parallel_for (Kokkos::TeamThreadRange (team_member, numPoints), [=, &vinvLine_ = this->vinvLine_, &vinvBubble_ = this->vinvBubble_] (ordinal_type& pt) {
433 auto output = Kokkos::subview( outputValues, Kokkos::ALL(), range_type(pt,pt+1), Kokkos::ALL() );
434 const auto input = Kokkos::subview( inputPoints, range_type(pt,pt+1), Kokkos::ALL() );
435 WorkViewType work(workView.data() + sizePerPoint*team_member.team_rank(), sizePerPoint);
436 Impl::Basis_HCURL_QUAD_In_FEM::Serial<OPERATOR_CURL>::getValues( output, input, work, vinvLine_, vinvBubble_ );
437 });
438 break;
439 default: {
440 INTREPID2_TEST_FOR_ABORT( true,
441 ">>> ERROR (Basis_HCURL_QUAD_In_FEM): getValues not implemented for this operator");
442 }
443 }
444 }
445
446} // namespace Intrepid2
447
448#endif
Implementation of the default H(curl)-compatible FEM basis on Quadrilateral cell.
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.