Intrepid2
Intrepid2_HGRAD_QUAD_Cn_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
15
16#ifndef __INTREPID2_HGRAD_QUAD_CN_FEM_DEF_HPP__
17#define __INTREPID2_HGRAD_QUAD_CN_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
32 getValues( OutputViewType output,
33 const InputViewType input,
34 WorkViewType work,
35 const VinvViewType vinv,
36 const ordinal_type operatorDn ) {
37 ordinal_type opDn = operatorDn;
38
39 const ordinal_type cardLine = vinv.extent(0);
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
53 switch (OpType) {
54 case OPERATOR_VALUE: {
55 ViewType work_line = createMatchingUnmanagedView<ViewType>(input, ptr0, cardLine, npts);
56 ViewType output_x = createMatchingUnmanagedView<ViewType>(input, ptr1, cardLine, npts);
57 ViewType output_y = createMatchingUnmanagedView<ViewType>(input, ptr2, cardLine, npts);
58
59 Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_VALUE>::
60 getValues(output_x, input_x, work_line, vinv);
61
62 Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_VALUE>::
63 getValues(output_y, input_y, work_line, vinv);
64
65 // tensor product
66 ordinal_type idx = 0;
67 for (ordinal_type j=0;j<cardLine;++j) // y
68 for (ordinal_type i=0;i<cardLine;++i,++idx) // x
69 for (ordinal_type k=0;k<npts;++k)
70 output.access(idx,k) = output_x.access(i,k)*output_y.access(j,k);
71 break;
72 }
73 case OPERATOR_CURL: {
74 for (auto l=0;l<2;++l) {
75 ViewType work_line = createMatchingUnmanagedView<ViewType>(input, ptr0, cardLine, npts);
76
77 ViewType output_x, output_y;
78
79 typename WorkViewType::value_type s = 0.0;
80 if (l) {
81 // l = 1
82 output_x = createMatchingUnmanagedView<ViewType>(input, ptr1, cardLine, npts, 1);
83 Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_Dn>::
84 getValues(output_x, input_x, work_line, vinv, 1);
85
86 output_y = createMatchingUnmanagedView<ViewType>(input, ptr2, cardLine, npts);
87 Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_VALUE>::
88 getValues(output_y, input_y, work_line, vinv);
89
90 s = -1.0;
91 } else {
92 // l = 0
93 output_x = createMatchingUnmanagedView<ViewType>(input, ptr1, cardLine, npts);
94 Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_VALUE>::
95 getValues(output_x, input_x, work_line, vinv);
96
97 output_y = createMatchingUnmanagedView<ViewType>(input, ptr2, cardLine, npts, 1);
98 Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_Dn>::
99 getValues(output_y, input_y, work_line, vinv, 1);
100
101 s = 1.0;
102 }
103
104 // tensor product (extra dimension of ouput x and y are ignored)
105 ordinal_type idx = 0;
106 for (ordinal_type j=0;j<cardLine;++j) // y
107 for (ordinal_type i=0;i<cardLine;++i,++idx) // x
108 for (ordinal_type k=0;k<npts;++k)
109 output.access(idx,k,l) = s*output_x.access(i,k,0)*output_y.access(j,k,0);
110 }
111 break;
112 }
113 case OPERATOR_GRAD:
114 case OPERATOR_D1:
115 case OPERATOR_D2:
116 case OPERATOR_D3:
117 case OPERATOR_D4:
118 case OPERATOR_D5:
119 case OPERATOR_D6:
120 case OPERATOR_D7:
121 case OPERATOR_D8:
122 case OPERATOR_D9:
123 case OPERATOR_D10:
124 opDn = getOperatorOrder(OpType);
125 case OPERATOR_Dn: {
126 const auto dkcard = opDn + 1;
127 for (auto l=0;l<dkcard;++l) {
128 ViewType work_line = createMatchingUnmanagedView<ViewType>(input, ptr0, cardLine, npts);
129
130 ViewType output_x, output_y;
131
132 const auto mult_x = opDn - l;
133 const auto mult_y = l;
134
135 if (mult_x) {
136 output_x = createMatchingUnmanagedView<ViewType>(input, ptr1, cardLine, npts, 1);
137 Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_Dn>::
138 getValues(output_x, input_x, work_line, vinv, mult_x);
139 } else {
140 output_x = createMatchingUnmanagedView<ViewType>(input, ptr1, cardLine, npts);
141 Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_VALUE>::
142 getValues(output_x, input_x, work_line, vinv);
143 }
144
145 if (mult_y) {
146 output_y = createMatchingUnmanagedView<ViewType>(input, ptr2, cardLine, npts, 1);
147 Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_Dn>::
148 getValues(output_y, input_y, work_line, vinv, mult_y);
149 } else {
150 output_y = createMatchingUnmanagedView<ViewType>(input, ptr2, cardLine, npts);
151 Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_VALUE>::
152 getValues(output_y, input_y, work_line, vinv);
153 }
154
155 // tensor product (extra dimension of ouput x and y are ignored)
156 ordinal_type idx = 0;
157 for (ordinal_type j=0;j<cardLine;++j) // y
158 for (ordinal_type i=0;i<cardLine;++i,++idx) // x
159 for (ordinal_type k=0;k<npts;++k)
160 output.access(idx,k,l) = output_x.access(i,k,0)*output_y.access(j,k,0);
161 }
162 break;
163 }
164 default: {
165 INTREPID2_TEST_FOR_ABORT( true,
166 ">>> ERROR: (Intrepid2::Basis_HGRAD_QUAD_Cn_FEM::Serial::getValues) operator is not supported" );
167 }
168 }
169 }
170
171 template<typename DT, ordinal_type numPtsPerEval,
172 typename outputValueValueType, class ...outputValueProperties,
173 typename inputPointValueType, class ...inputPointProperties,
174 typename vinvValueType, class ...vinvProperties>
175 void
176 Basis_HGRAD_QUAD_Cn_FEM::
177 getValues( const typename DT::execution_space& space,
178 Kokkos::DynRankView<outputValueValueType,outputValueProperties...> outputValues,
179 const Kokkos::DynRankView<inputPointValueType, inputPointProperties...> inputPoints,
180 const Kokkos::DynRankView<vinvValueType, vinvProperties...> vinv,
181 const EOperator operatorType ) {
182 typedef Kokkos::DynRankView<outputValueValueType,outputValueProperties...> outputValueViewType;
183 typedef Kokkos::DynRankView<inputPointValueType, inputPointProperties...> inputPointViewType;
184 typedef Kokkos::DynRankView<vinvValueType, vinvProperties...> vinvViewType;
185 typedef typename ExecSpace<typename inputPointViewType::execution_space,typename DT::execution_space>::ExecSpaceType ExecSpaceType;
186
187 // loopSize corresponds to cardinality
188 const auto loopSizeTmp1 = (inputPoints.extent(0)/numPtsPerEval);
189 const auto loopSizeTmp2 = (inputPoints.extent(0)%numPtsPerEval != 0);
190 const auto loopSize = loopSizeTmp1 + loopSizeTmp2;
191 Kokkos::RangePolicy<ExecSpaceType,Kokkos::Schedule<Kokkos::Static> > policy(space, 0, loopSize);
192
193 //typedef typename inputPointViewType::value_type inputPointType;
194
195 const ordinal_type cardinality = outputValues.extent(0);
196 const ordinal_type cardLine = std::sqrt(cardinality);
197 const ordinal_type workSize = 3*cardLine;
198
199 auto work = createMatchingDynRankView(inputPoints, "Basis_HGRAD_QUAD_Cn_FEM::getValues::work", workSize, inputPoints.extent(0));
200
201 switch (operatorType) {
202 case OPERATOR_VALUE: {
203 typedef Functor<outputValueViewType,inputPointViewType,vinvViewType,decltype(work),
204 OPERATOR_VALUE,numPtsPerEval> FunctorType;
205 Kokkos::parallel_for( policy, FunctorType(outputValues, inputPoints, vinv, work) );
206 break;
207 }
208 case OPERATOR_CURL: {
209 typedef Functor<outputValueViewType,inputPointViewType,vinvViewType,decltype(work),
210 OPERATOR_CURL,numPtsPerEval> FunctorType;
211 Kokkos::parallel_for( policy, FunctorType(outputValues, inputPoints, vinv, work) );
212 break;
213 }
214 case OPERATOR_GRAD:
215 case OPERATOR_D1:
216 case OPERATOR_D2:
217 case OPERATOR_D3:
218 case OPERATOR_D4:
219 case OPERATOR_D5:
220 case OPERATOR_D6:
221 case OPERATOR_D7:
222 case OPERATOR_D8:
223 case OPERATOR_D9:
224 case OPERATOR_D10: {
225 typedef Functor<outputValueViewType,inputPointViewType,vinvViewType,decltype(work),
226 OPERATOR_Dn,numPtsPerEval> FunctorType;
227 Kokkos::parallel_for( policy, FunctorType(outputValues, inputPoints, vinv, work,
228 getOperatorOrder(operatorType)) );
229 break;
230 }
231 default: {
232 INTREPID2_TEST_FOR_EXCEPTION( true , std::invalid_argument,
233 ">>> ERROR (Basis_HGRAD_QUAD_Cn_FEM): Operator type not implemented" );
234 // break;commented out because exception
235 }
236 }
237 }
238 }
239
240 // -------------------------------------------------------------------------------------
241 template<typename DT, typename OT, typename PT>
243 Basis_HGRAD_QUAD_Cn_FEM( const ordinal_type order,
244 const EPointType pointType ) {
245 // INTREPID2_TEST_FOR_EXCEPTION( !(pointType == POINTTYPE_EQUISPACED ||
246 // pointType == POINTTYPE_WARPBLEND), std::invalid_argument,
247 // ">>> ERROR (Basis_HGRAD_QUAD_Cn_FEM): pointType must be either equispaced or warpblend." );
248
249 // this should be in host
250 Basis_HGRAD_LINE_Cn_FEM<DT,OT,PT> lineBasis( order, pointType );
251 const auto cardLine = lineBasis.getCardinality();
252
253 this->vinv_ = Kokkos::DynRankView<typename ScalarViewType::value_type,DT>("Hgrad::Quad::Cn::vinv", cardLine, cardLine);
254 lineBasis.getVandermondeInverse(this->vinv_);
255
256 const ordinal_type spaceDim = 2;
257 this->basisCardinality_ = cardLine*cardLine;
258 this->basisDegree_ = order;
259 this->basisCellTopologyKey_ = shards::Quadrilateral<4>::key;
260 this->basisType_ = BASIS_FEM_LAGRANGIAN;
261 this->basisCoordinates_ = COORDINATES_CARTESIAN;
262 this->functionSpace_ = FUNCTION_SPACE_HGRAD;
263 pointType_ = pointType;
264
265 // initialize tags
266 {
267 // Basis-dependent initializations
268 const ordinal_type tagSize = 4; // size of DoF tag, i.e., number of fields in the tag
269 const ordinal_type posScDim = 0; // position in the tag, counting from 0, of the subcell dim
270 const ordinal_type posScOrd = 1; // position in the tag, counting from 0, of the subcell ordinal
271 const ordinal_type posDfOrd = 2; // position in the tag, counting from 0, of DoF ordinal relative to the subcell
272
273 // 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.
274 // 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.)
275 INTREPID2_TEST_FOR_EXCEPTION( order > Parameters::MaxOrder, std::invalid_argument, "polynomial order exceeds the max supported by this class");
276 // An array with local DoF tags assigned to the basis functions, in the order of their local enumeration
277 constexpr ordinal_type maxCardLine = Parameters::MaxOrder + 1;
278 ordinal_type tags[maxCardLine*maxCardLine][4];
279
280 const ordinal_type vert[2][2] = { {0,1}, {3,2} }; //[y][x]
281
282 const ordinal_type edge_x[2] = {0,2};
283 const ordinal_type edge_y[2] = {3,1};
284 {
285 ordinal_type idx = 0;
286 for (ordinal_type j=0;j<cardLine;++j) { // y
287 const auto tag_y = lineBasis.getDofTag(j);
288 for (ordinal_type i=0;i<cardLine;++i,++idx) { // x
289 const auto tag_x = lineBasis.getDofTag(i);
290
291 if (tag_x(0) == 0 && tag_y(0) == 0) {
292 // vertices
293 tags[idx][0] = 0; // vertex dof
294 tags[idx][1] = vert[tag_y(1)][tag_x(1)]; // vertex id
295 tags[idx][2] = 0; // local dof id
296 tags[idx][3] = 1; // total number of dofs in this vertex
297 } else if (tag_x(0) == 1 && tag_y(0) == 0) {
298 // edge: x edge, y vert
299 tags[idx][0] = 1; // edge dof
300 tags[idx][1] = edge_x[tag_y(1)];
301 tags[idx][2] = tag_x(2); // local dof id
302 tags[idx][3] = tag_x(3); // total number of dofs in this vertex
303 } else if (tag_x(0) == 0 && tag_y(0) == 1) {
304 // edge: x vert, y edge
305 tags[idx][0] = 1; // edge dof
306 tags[idx][1] = edge_y[tag_x(1)];
307 tags[idx][2] = tag_y(2); // local dof id
308 tags[idx][3] = tag_y(3); // total number of dofs in this vertex
309 } else {
310 // interior
311 tags[idx][0] = 2; // interior dof
312 tags[idx][1] = 0;
313 tags[idx][2] = tag_x(2) + tag_x(3)*tag_y(2); // local dof id
314 tags[idx][3] = tag_x(3)*tag_y(3); // total number of dofs in this vertex
315 }
316 }
317 }
318 }
319
320 OrdinalTypeArray1DHost tagView(&tags[0][0], this->basisCardinality_*4);
321
322 // Basis-independent function sets tag and enum data in tagToOrdinal_ and ordinalToTag_ arrays:
323 // tags are constructed on host
325 this->ordinalToTag_,
326 tagView,
327 this->basisCardinality_,
328 tagSize,
329 posScDim,
330 posScOrd,
331 posDfOrd);
332 }
333
334 // dofCoords on host and create its mirror view to device
335 Kokkos::DynRankView<typename ScalarViewType::value_type,typename DT::execution_space::array_layout,Kokkos::HostSpace>
336 dofCoordsHost("dofCoordsHost", this->basisCardinality_, spaceDim);
337
338 Kokkos::DynRankView<typename ScalarViewType::value_type,DT>
339 dofCoordsLine("dofCoordsLine", cardLine, 1);
340
341 lineBasis.getDofCoords(dofCoordsLine);
342 auto dofCoordsLineHost = Kokkos::create_mirror_view(dofCoordsLine);
343 Kokkos::deep_copy(dofCoordsLineHost, dofCoordsLine);
344 {
345 ordinal_type idx = 0;
346 for (ordinal_type j=0;j<cardLine;++j) { // y
347 for (ordinal_type i=0;i<cardLine;++i,++idx) { // x
348 dofCoordsHost(idx,0) = dofCoordsLineHost(i,0);
349 dofCoordsHost(idx,1) = dofCoordsLineHost(j,0);
350 }
351 }
352 }
353
354 this->dofCoords_ = Kokkos::create_mirror_view(typename DT::memory_space(), dofCoordsHost);
355 Kokkos::deep_copy(this->dofCoords_, dofCoordsHost);
356 }
357
358 template<typename DT, typename OT, typename PT>
359 void
360 Basis_HGRAD_QUAD_Cn_FEM<DT,OT,PT>::getScratchSpaceSize(
361 ordinal_type& perTeamSpaceSize,
362 ordinal_type& perThreadSpaceSize,
363 const PointViewType inputPoints,
364 const EOperator operatorType) const {
365 perTeamSpaceSize = 0;
366 perThreadSpaceSize = 3*this->vinv_.extent(0)*get_dimension_scalar(inputPoints)*sizeof(typename BasisBase::scalarType);
367 }
368
369 template<typename DT, typename OT, typename PT>
370 KOKKOS_INLINE_FUNCTION
371 void
372 Basis_HGRAD_QUAD_Cn_FEM<DT,OT,PT>::getValues(
373 OutputViewType outputValues,
374 const PointViewType inputPoints,
375 const EOperator operatorType,
376 const typename Kokkos::TeamPolicy<typename DT::execution_space>::member_type& team_member,
377 const typename DT::execution_space::scratch_memory_space & scratchStorage,
378 const ordinal_type subcellDim,
379 const ordinal_type subcellOrdinal) const {
380
381 INTREPID2_TEST_FOR_ABORT( !((subcellDim == -1) && (subcellOrdinal == -1)),
382 ">>> ERROR: (Intrepid2::Basis_HGRAD_QUAD_Cn_FEM::getValues), The capability of selecting subsets of basis functions has not been implemented yet.");
383
384 const int numPoints = inputPoints.extent(0);
385 using ScalarType = typename ScalarTraits<typename PointViewType::value_type>::scalar_type;
386 using WorkViewType = Kokkos::DynRankView< ScalarType,typename DT::execution_space::scratch_memory_space,Kokkos::MemoryTraits<Kokkos::Unmanaged> >;
387 ordinal_type sizePerPoint = 3*this->vinv_.extent(0)*get_dimension_scalar(inputPoints);
388 WorkViewType workView(scratchStorage, sizePerPoint*team_member.team_size());
389 using range_type = Kokkos::pair<ordinal_type,ordinal_type>;
390
391 switch(operatorType) {
392 case OPERATOR_VALUE:
393 Kokkos::parallel_for (Kokkos::TeamThreadRange (team_member, numPoints), [=, &vinv_ = this->vinv_] (ordinal_type& pt) {
394 auto output = Kokkos::subview( outputValues, Kokkos::ALL(), range_type (pt,pt+1), Kokkos::ALL() );
395 const auto input = Kokkos::subview( inputPoints, range_type(pt, pt+1), Kokkos::ALL() );
396 WorkViewType work(workView.data() + sizePerPoint*team_member.team_rank(), sizePerPoint);
397 Impl::Basis_HGRAD_QUAD_Cn_FEM::Serial<OPERATOR_VALUE>::getValues( output, input, work, vinv_ );
398 });
399 break;
400 case OPERATOR_GRAD:
401 Kokkos::parallel_for (Kokkos::TeamThreadRange (team_member, numPoints), [=, &vinv_ = this->vinv_] (ordinal_type& pt) {
402 auto output = Kokkos::subview( outputValues, Kokkos::ALL(), range_type(pt,pt+1), Kokkos::ALL() );
403 const auto input = Kokkos::subview( inputPoints, range_type(pt,pt+1), Kokkos::ALL() );
404 WorkViewType work(workView.data() + sizePerPoint*team_member.team_rank(), sizePerPoint);
405 Impl::Basis_HGRAD_QUAD_Cn_FEM::Serial<OPERATOR_GRAD>::getValues( output, input, work, vinv_ );
406 });
407 break;
408 case OPERATOR_CURL:
409 Kokkos::parallel_for (Kokkos::TeamThreadRange (team_member, numPoints), [=, &vinv_ = this->vinv_] (ordinal_type& pt) {
410 auto output = Kokkos::subview( outputValues, Kokkos::ALL(), range_type(pt,pt+1), Kokkos::ALL() );
411 const auto input = Kokkos::subview( inputPoints, range_type(pt,pt+1), Kokkos::ALL() );
412 WorkViewType work(workView.data() + sizePerPoint*team_member.team_rank(), sizePerPoint);
413 Impl::Basis_HGRAD_QUAD_Cn_FEM::Serial<OPERATOR_CURL>::getValues( output, input, work, vinv_ );
414 });
415 break;
416 default: {
417 INTREPID2_TEST_FOR_ABORT( true,
418 ">>> ERROR (Basis_HGRAD_QUAD_Cn_FEM): getValues not implemented for this operator");
419 }
420 }
421 }
422
423} // namespace Intrepid2
424
425#endif
KOKKOS_INLINE_FUNCTION ordinal_type getOperatorOrder(const EOperator operatorType)
Returns order of an operator.
KOKKOS_INLINE_FUNCTION std::enable_if< std::is_pointer_v< CtorProp > &&!std::is_convertible_v< CtorProp, constchar * >, OutViewType >::type createMatchingUnmanagedView(const InViewType &view, const CtorProp &data, const Dims... dims)
Creates an unmanaged view that matches the value_type of the provided view The type of the output vie...
DeduceDynRankView< InViewType >::type createMatchingDynRankView(const InViewType &view, const CtorProp &prop, const Dims... dims)
Creates and returns a view that matches the value_type of the provided view The output view type is d...
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.
EPointType pointType_
type of lattice used for creating the DoF coordinates
Basis_HGRAD_QUAD_Cn_FEM(const ordinal_type order, const EPointType pointType=POINTTYPE_EQUISPACED)
Constructor.
Kokkos::DynRankView< typename ScalarViewType::value_type, DeviceType > vinv_
inverse of Generalized Vandermonde matrix (isotropic order)
const OrdinalTypeArrayStride1DHost getDofTag(const ordinal_type dofOrd) const
DoF ordinal to DoF tag lookup.
void setOrdinalTagData(OrdinalTypeView3D &tagToOrdinal, OrdinalTypeView2D &ordinalToTag, const OrdinalTypeView1D tags, const ordinal_type basisCard, const ordinal_type tagSize, const ordinal_type posScDim, const ordinal_type posScOrd, const ordinal_type posDfOrd)
ordinal_type getCardinality() const
Returns cardinality of the basis.
Kokkos::DynRankView< scalarType, DeviceType > dofCoords_
Kokkos::View< ordinal_type *, typename ExecutionSpace::array_layout, Kokkos::HostSpace > OrdinalTypeArray1DHost
static constexpr ordinal_type MaxOrder
The maximum reconstruction order.
See Intrepid2::Basis_HGRAD_QUAD_Cn_FEM work is a rank 1 view having the same value_type of inputPoint...