Intrepid2
Intrepid2_HGRAD_HEX_Cn_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_HGRAD_HEX_CN_FEMDEF_HPP__
50#define __INTREPID2_HGRAD_HEX_CN_FEMDEF_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_HGRAD_HEX_Cn_FEM::Serial<opType>::
65 getValues( OutputViewType output,
66 const inputViewType input,
67 workViewType work,
68 const vinvViewType vinv,
69 const ordinal_type operatorDn ) {
70 ordinal_type opDn = operatorDn;
71
72 const ordinal_type cardLine = vinv.extent(0);
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 const auto input_z = Kokkos::subview(input, Kokkos::ALL(), range_type(2,3));
79
80 const ordinal_type dim_s = get_dimension_scalar(work);
81 auto ptr0 = work.data();
82 auto ptr1 = work.data()+cardLine*npts*dim_s;
83 auto ptr2 = work.data()+2*cardLine*npts*dim_s;
84 auto ptr3 = work.data()+3*cardLine*npts*dim_s;
85
86 typedef typename Kokkos::DynRankView<typename workViewType::value_type, typename workViewType::memory_space> viewType;
87 auto vcprop = Kokkos::common_view_alloc_prop(work);
88
89 switch (opType) {
90 case OPERATOR_VALUE: {
91 viewType work_line(Kokkos::view_wrap(ptr0, vcprop), cardLine, npts);
92 viewType output_x(Kokkos::view_wrap(ptr1, vcprop), cardLine, npts);
93 viewType output_y(Kokkos::view_wrap(ptr2, vcprop), cardLine, npts);
94 viewType output_z(Kokkos::view_wrap(ptr3, vcprop), cardLine, npts);
95
96 Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_VALUE>::
97 getValues(output_x, input_x, work_line, vinv);
98
99 Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_VALUE>::
100 getValues(output_y, input_y, work_line, vinv);
101
102 Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_VALUE>::
103 getValues(output_z, input_z, work_line, vinv);
104
105 // tensor product
106 ordinal_type idx = 0;
107 for (ordinal_type k=0;k<cardLine;++k) // z
108 for (ordinal_type j=0;j<cardLine;++j) // y
109 for (ordinal_type i=0;i<cardLine;++i,++idx) // x
110 for (ordinal_type l=0;l<npts;++l)
111 output.access(idx,l) = output_x.access(i,l)*output_y.access(j,l)*output_z.access(k,l);
112 break;
113 }
114 case OPERATOR_GRAD:
115 case OPERATOR_D1:
116 case OPERATOR_D2:
117 case OPERATOR_D3:
118 case OPERATOR_D4:
119 case OPERATOR_D5:
120 case OPERATOR_D6:
121 case OPERATOR_D7:
122 case OPERATOR_D8:
123 case OPERATOR_D9:
124 case OPERATOR_D10:
125 opDn = getOperatorOrder(opType);
126 case OPERATOR_Dn: {
127 const ordinal_type dkcard = opDn + 1;
128
129 ordinal_type d = 0;
130 for (ordinal_type l1=0;l1<dkcard;++l1)
131 for (ordinal_type l0=0;l0<(l1+1);++l0) {
132 const ordinal_type mult_x = (opDn - l1);
133 const ordinal_type mult_y = l1 - l0;
134 const ordinal_type mult_z = l0;
135
136 //std::cout << " l0, l1 = " << l0 << " " << l1 << std::endl;
137 //std::cout << " x , y , z = " << mult_x << " " << mult_y << " " << mult_z << std::endl;
138
139 if (mult_x < 0) {
140 // pass
141 } else {
142 viewType work_line(Kokkos::view_wrap(ptr0, vcprop), cardLine, npts);
143 decltype(work_line) output_x, output_y, output_z;
144
145 if (mult_x) {
146 output_x = viewType(Kokkos::view_wrap(ptr1, vcprop), cardLine, npts, 1);
147 Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_Dn>::
148 getValues(output_x, input_x, work_line, vinv, mult_x);
149 } else {
150 output_x = viewType(Kokkos::view_wrap(ptr1, vcprop), cardLine, npts);
151 Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_VALUE>::
152 getValues(output_x, input_x, work_line, vinv);
153 }
154
155 if (mult_y) {
156 output_y = viewType(Kokkos::view_wrap(ptr2, vcprop), cardLine, npts, 1);
157 Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_Dn>::
158 getValues(output_y, input_y, work_line, vinv, mult_y);
159 } else {
160 output_y = viewType(Kokkos::view_wrap(ptr2, vcprop), cardLine, npts);
161 Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_VALUE>::
162 getValues(output_y, input_y, work_line, vinv);
163 }
164
165 if (mult_z) {
166 output_z = viewType(Kokkos::view_wrap(ptr3, vcprop), cardLine, npts, 1);
167 Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_Dn>::
168 getValues(output_z, input_z, work_line, vinv, mult_z);
169 } else {
170 output_z = viewType(Kokkos::view_wrap(ptr3, vcprop), cardLine, npts);
171 Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_VALUE>::
172 getValues(output_z, input_z, work_line, vinv);
173 }
174
175 // tensor product (extra dimension of ouput x,y and z are ignored)
176 ordinal_type idx = 0;
177 for (ordinal_type k=0;k<cardLine;++k) // z
178 for (ordinal_type j=0;j<cardLine;++j) // y
179 for (ordinal_type i=0;i<cardLine;++i,++idx) // x
180 for (ordinal_type l=0;l<npts;++l)
181 output.access(idx,l,d) = output_x.access(i,l,0)*output_y.access(j,l,0)*output_z.access(k,l,0);
182 ++d;
183 }
184 }
185 break;
186 }
187 default: {
188 INTREPID2_TEST_FOR_ABORT( true ,
189 ">>> ERROR (Basis_HGRAD_HEX_Cn_FEM): Operator type not implemented");
190 break;
191 }
192 }
193 }
194
195 template<typename DT, ordinal_type numPtsPerEval,
196 typename outputValueValueType, class ...outputValueProperties,
197 typename inputPointValueType, class ...inputPointProperties,
198 typename vinvValueType, class ...vinvProperties>
199 void
200 Basis_HGRAD_HEX_Cn_FEM::
201 getValues( Kokkos::DynRankView<outputValueValueType,outputValueProperties...> outputValues,
202 const Kokkos::DynRankView<inputPointValueType, inputPointProperties...> inputPoints,
203 const Kokkos::DynRankView<vinvValueType, vinvProperties...> vinv,
204 const EOperator operatorType ) {
205 typedef Kokkos::DynRankView<outputValueValueType,outputValueProperties...> outputValueViewType;
206 typedef Kokkos::DynRankView<inputPointValueType, inputPointProperties...> inputPointViewType;
207 typedef Kokkos::DynRankView<vinvValueType, vinvProperties...> vinvViewType;
208 typedef typename ExecSpace<typename inputPointViewType::execution_space,typename DT::execution_space>::ExecSpaceType ExecSpaceType;
209
210 // loopSize corresponds to cardinality
211 const auto loopSizeTmp1 = (inputPoints.extent(0)/numPtsPerEval);
212 const auto loopSizeTmp2 = (inputPoints.extent(0)%numPtsPerEval != 0);
213 const auto loopSize = loopSizeTmp1 + loopSizeTmp2;
214 Kokkos::RangePolicy<ExecSpaceType,Kokkos::Schedule<Kokkos::Static> > policy(0, loopSize);
215
216 typedef typename inputPointViewType::value_type inputPointType;
217
218 const ordinal_type cardinality = outputValues.extent(0);
219 const ordinal_type cardLine = std::cbrt(cardinality);
220 const ordinal_type workSize = 4*cardLine;
221
222 auto vcprop = Kokkos::common_view_alloc_prop(inputPoints);
223 typedef typename Kokkos::DynRankView< inputPointType, typename inputPointViewType::memory_space> workViewType;
224 workViewType work(Kokkos::view_alloc("Basis_HGRAD_HEX_Cn_FEM::getValues::work", vcprop), workSize, inputPoints.extent(0));
225
226 switch (operatorType) {
227 case OPERATOR_VALUE: {
228 typedef Functor<outputValueViewType,inputPointViewType,vinvViewType,workViewType,
229 OPERATOR_VALUE,numPtsPerEval> FunctorType;
230 Kokkos::parallel_for( policy, FunctorType(outputValues, inputPoints, vinv, work) );
231 break;
232 }
233 case OPERATOR_CURL: {
234 typedef Functor<outputValueViewType,inputPointViewType,vinvViewType,workViewType,
235 OPERATOR_CURL,numPtsPerEval> FunctorType;
236 Kokkos::parallel_for( policy, FunctorType(outputValues, inputPoints, vinv, work) );
237 break;
238 }
239 case OPERATOR_GRAD:
240 case OPERATOR_D1:
241 case OPERATOR_D2:
242 case OPERATOR_D3:
243 case OPERATOR_D4:
244 case OPERATOR_D5:
245 case OPERATOR_D6:
246 case OPERATOR_D7:
247 case OPERATOR_D8:
248 case OPERATOR_D9:
249 case OPERATOR_D10: {
250 typedef Functor<outputValueViewType,inputPointViewType,vinvViewType,workViewType,
251 OPERATOR_Dn,numPtsPerEval> FunctorType;
252 Kokkos::parallel_for( policy, FunctorType(outputValues, inputPoints, vinv, work,
253 getOperatorOrder(operatorType)) );
254 break;
255 }
256 default: {
257 INTREPID2_TEST_FOR_EXCEPTION( true , std::invalid_argument,
258 ">>> ERROR (Basis_HGRAD_HEX_Cn_FEM): Operator type not implemented" );
259 // break; commented out since exception is thrown
260 }
261 }
262 }
263 }
264
265 // -------------------------------------------------------------------------------------
266 template<typename DT, typename OT, typename PT>
268 Basis_HGRAD_HEX_Cn_FEM( const ordinal_type order,
269 const EPointType pointType ) {
270
271 // this should be in host
272 Basis_HGRAD_LINE_Cn_FEM<DT,OT,PT> lineBasis( order, pointType );
273 const auto cardLine = lineBasis.getCardinality();
274
275 this->vinv_ = Kokkos::DynRankView<typename ScalarViewType::value_type,DT>("Hgrad::HEX::Cn::vinv", cardLine, cardLine);
276 lineBasis.getVandermondeInverse(this->vinv_);
277
278 this->basisCardinality_ = cardLine*cardLine*cardLine;
279 this->basisDegree_ = order;
280 this->basisCellTopology_ = shards::CellTopology(shards::getCellTopologyData<shards::Hexahedron<8> >() );
281 this->basisType_ = BASIS_FEM_LAGRANGIAN;
282 this->basisCoordinates_ = COORDINATES_CARTESIAN;
283 this->functionSpace_ = FUNCTION_SPACE_HGRAD;
284 pointType_ = pointType;
285
286 // initialize tags
287 {
288 // Basis-dependent initializations
289 const ordinal_type tagSize = 4; // size of DoF tag, i.e., number of fields in the tag
290 const ordinal_type posScDim = 0; // position in the tag, counting from 0, of the subcell dim
291 const ordinal_type posScOrd = 1; // position in the tag, counting from 0, of the subcell ordinal
292 const ordinal_type posDfOrd = 2; // position in the tag, counting from 0, of DoF ordinal relative to the subcell
293
294 // 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.
295 // 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.)
296 INTREPID2_TEST_FOR_EXCEPTION( order > Parameters::MaxOrder, std::invalid_argument, "polynomial order exceeds the max supported by this class");
297
298 // An array with local DoF tags assigned to the basis functions, in the order of their local enumeration
299 constexpr ordinal_type maxCardLine = Parameters::MaxOrder + 1;
300 ordinal_type tags[maxCardLine*maxCardLine*maxCardLine][4];
301
302 const ordinal_type vert[2][2][2] = { { {0,1}, {3,2} },
303 { {4,5}, {7,6} } }; //[z][y][x]
304
305 const ordinal_type edge_x[2][2] = { {0, 4}, {2, 6} };
306 const ordinal_type edge_y[2][2] = { {3, 7}, {1, 5} };
307 const ordinal_type edge_z[2][2] = { {8,11}, {9,10} };
308
309 const ordinal_type face_yz[2] = {3, 1};
310 const ordinal_type face_xz[2] = {0, 2};
311 const ordinal_type face_xy[2] = {4, 5};
312
313 {
314 ordinal_type idx = 0;
315 for (auto k=0;k<cardLine;++k) { // z
316 const auto tag_z = lineBasis.getDofTag(k);
317 for (ordinal_type j=0;j<cardLine;++j) { // y
318 const auto tag_y = lineBasis.getDofTag(j);
319 for (ordinal_type i=0;i<cardLine;++i,++idx) { // x
320 const auto tag_x = lineBasis.getDofTag(i);
321
322 if (tag_x(0) == 0 && tag_y(0) == 0 && tag_z(0) == 0) {
323 // vertices
324 tags[idx][0] = 0; // vertex dof
325 tags[idx][1] = vert[tag_z(1)][tag_y(1)][tag_x(1)]; // vertex id
326 tags[idx][2] = 0; // local dof id
327 tags[idx][3] = 1; // total number of dofs in this vertex
328 } else if (tag_x(0) == 1 && tag_y(0) == 0 && tag_z(0) == 0) {
329 // edge, x edge, y vert, z vert,
330 tags[idx][0] = 1; // edge dof
331 tags[idx][1] = edge_x[tag_y(1)][tag_z(1)]; // edge id
332 tags[idx][2] = tag_x(2); // local dof id
333 tags[idx][3] = tag_x(3); // total number of dofs in this edge
334 } else if (tag_x(0) == 0 && tag_y(0) == 1 && tag_z(0) == 0) {
335 // edge, x vert, y edge, z vert,
336 tags[idx][0] = 1; // edge dof
337 tags[idx][1] = edge_y[tag_x(1)][tag_z(1)]; // edge id
338 tags[idx][2] = tag_y(2); // local dof id
339 tags[idx][3] = tag_y(3); // total number of dofs in this edge
340 } else if (tag_x(0) == 0 && tag_y(0) == 0 && tag_z(0) == 1) {
341 // edge, x vert, y vert, z edge,
342 tags[idx][0] = 1; // edge dof
343 tags[idx][1] = edge_z[tag_x(1)][tag_y(1)]; // edge id
344 tags[idx][2] = tag_z(2); // local dof id
345 tags[idx][3] = tag_z(3); // total number of dofs in this edge
346 } else if (tag_x(0) == 0 && tag_y(0) == 1 && tag_z(0) == 1) {
347 // face, x vert, y edge, z edge
348 tags[idx][0] = 2; // face dof
349 tags[idx][1] = face_yz[tag_x(1)]; // face id
350 tags[idx][2] = tag_y(2) + tag_y(3)*tag_z(2); // local dof id
351 tags[idx][3] = tag_y(3)*tag_z(3); // total number of dofs in this vertex
352 } else if (tag_x(0) == 1 && tag_y(0) == 0 && tag_z(0) == 1) {
353 // face, x edge, y vert, z edge
354 tags[idx][0] = 2; // face dof
355 tags[idx][1] = face_xz[tag_y(1)]; // face id
356 tags[idx][2] = tag_x(2) + tag_x(3)*tag_z(2); // local dof id
357 tags[idx][3] = tag_x(3)*tag_z(3); // total number of dofs in this vertex
358 } else if (tag_x(0) == 1 && tag_y(0) == 1 && tag_z(0) == 0) {
359 // face, x edge, y edge, z vert
360 tags[idx][0] = 2; // face dof
361 tags[idx][1] = face_xy[tag_z(1)]; // face id
362 tags[idx][2] = tag_x(2) + tag_x(3)*tag_y(2); // local dof id
363 tags[idx][3] = tag_x(3)*tag_y(3); // total number of dofs in this vertex
364 } else {
365 // interior
366 tags[idx][0] = 3; // interior dof
367 tags[idx][1] = 0;
368 tags[idx][2] = tag_x(2) + tag_x(3)*tag_y(2) + tag_x(3)*tag_y(3)*tag_z(2); // local dof id
369 tags[idx][3] = tag_x(3)*tag_y(3)*tag_z(3); // total number of dofs in this vertex
370 }
371 }
372 }
373 }
374 }
375
376 OrdinalTypeArray1DHost tagView(&tags[0][0], this->basisCardinality_*4);
377
378 // Basis-independent function sets tag and enum data in tagToOrdinal_ and ordinalToTag_ arrays:
379 // tags are constructed on host
380 this->setOrdinalTagData(this->tagToOrdinal_,
381 this->ordinalToTag_,
382 tagView,
383 this->basisCardinality_,
384 tagSize,
385 posScDim,
386 posScOrd,
387 posDfOrd);
388 }
389
390 // dofCoords on host and create its mirror view to device
391 Kokkos::DynRankView<typename ScalarViewType::value_type,typename DT::execution_space::array_layout,Kokkos::HostSpace>
392 dofCoordsHost("dofCoordsHost", this->basisCardinality_, this->basisCellTopology_.getDimension());
393
394 Kokkos::DynRankView<typename ScalarViewType::value_type,DT>
395 dofCoordsLine("dofCoordsLine", cardLine, 1);
396
397 lineBasis.getDofCoords(dofCoordsLine);
398 auto dofCoordsLineHost = Kokkos::create_mirror_view(dofCoordsLine);
399 Kokkos::deep_copy(dofCoordsLineHost, dofCoordsLine);
400 {
401 ordinal_type idx = 0;
402 for (auto k=0;k<cardLine;++k) { // z
403 for (ordinal_type j=0;j<cardLine;++j) { // y
404 for (ordinal_type i=0;i<cardLine;++i,++idx) { // x
405 dofCoordsHost(idx,0) = dofCoordsLineHost(i,0);
406 dofCoordsHost(idx,1) = dofCoordsLineHost(j,0);
407 dofCoordsHost(idx,2) = dofCoordsLineHost(k,0);
408 }
409 }
410 }
411 }
412
413 this->dofCoords_ = Kokkos::create_mirror_view(typename DT::memory_space(), dofCoordsHost);
414 Kokkos::deep_copy(this->dofCoords_, dofCoordsHost);
415 }
416
417}// namespace Intrepid2
418
419#endif
KOKKOS_INLINE_FUNCTION ordinal_type getOperatorOrder(const EOperator operatorType)
Returns order of an operator.
Basis_HGRAD_HEX_Cn_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.
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.