Intrepid2
Intrepid2_HGRAD_TET_Cn_FEM_ORTHDef.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_HGRAD_TET_CN_FEM_ORTH_DEF_HPP__
17#define __INTREPID2_HGRAD_TET_CN_FEM_ORTH_DEF_HPP__
18
19namespace Intrepid2 {
20// -------------------------------------------------------------------------------------
21
22namespace Impl {
23
24template<typename OutputViewType,
25typename inputViewType,
26typename workViewType,
27bool hasDeriv>
28KOKKOS_INLINE_FUNCTION
29void OrthPolynomialTet<OutputViewType,inputViewType,workViewType,hasDeriv,0>::generate(
30 OutputViewType output,
31 const inputViewType input,
32 workViewType /*work*/,
33 const ordinal_type order ) {
34
35 constexpr ordinal_type spaceDim = 3;
36 constexpr ordinal_type maxNumPts = Parameters::MaxNumPtsPerBasisEval;
37
38 typedef typename OutputViewType::value_type value_type;
39
40 auto output0 = (hasDeriv) ? Kokkos::subview(output, Kokkos::ALL(), Kokkos::ALL(),0) : Kokkos::subview(output, Kokkos::ALL(), Kokkos::ALL());
41
42 const ordinal_type
43 npts = input.extent(0);
44
45 const auto z = input;
46
47 // each point needs to be transformed from Pavel's element
48 // z(i,0) --> (2.0 * z(i,0) - 1.0)
49 // z(i,1) --> (2.0 * z(i,1) - 1.0)
50
51 // set D^{0,0,0} = 1.0
52 {
53 const ordinal_type loc = Intrepid2::getPnEnumeration<spaceDim>(0,0,0);
54 for (ordinal_type i=0;i<npts;++i) {
55 output0(loc, i) = 1.0;
56 if(hasDeriv) {
57 output.access(loc,i,1) = 0;
58 output.access(loc,i,2) = 0;
59 output.access(loc,i,3) = 0;
60 }
61 }
62 }
63
64 if (order > 0) {
65 value_type f1[maxNumPts]={},f2[maxNumPts]={}, f3[maxNumPts]={}, f4[maxNumPts]={},f5[maxNumPts]={},
66 df2_1[maxNumPts]={}, df2_2[maxNumPts]={}, df5_2[maxNumPts]={};
67 value_type df1_0, df1_1, df1_2, df3_1, df3_2, df4_2;
68
69 for (int i=0;i<npts;i++) {
70 f1[i] = 2.0*z(i,0) + z(i,1) + z(i,2)- 1.0;
71 f2[i] = pow(z(i,1) + z(i,2) -1.0, 2);
72 f3[i] = 2.0*z(i,1) + z(i,2) -1.0;
73 f4[i] = 1.0 - z(i,2);
74 f5[i] = f4[i] * f4[i];
75 if(hasDeriv) {
76 df2_1[i] = 2*(z(i,1) + z(i,2) -1.0);
77 df2_2[i] = df2_1[i];
78 df5_2[i] = -2*f4[i];
79 }
80 }
81
82 df1_0 = 2.0;
83 df1_1 = 1.0;
84 df1_2 = 1.0;
85 df3_1 = 2;
86 df3_2 = 1;
87 df4_2 = -1;
88
89 // set D^{1,0,0} = f1
90 {
91 const ordinal_type loc = Intrepid2::getPnEnumeration<spaceDim>(1,0,0);
92 for (ordinal_type i=0;i<npts;++i) {
93 output0(loc, i) = f1[i];
94 if(hasDeriv) {
95 output.access(loc,i,1) = df1_0;
96 output.access(loc,i,2) = df1_1;
97 output.access(loc,i,3) = df1_2;
98 }
99 }
100 }
101
102 // recurrence in p
103 // D^{p+1,0,0}
104 for (ordinal_type p=1;p<order;p++) {
105 const ordinal_type
106 loc = Intrepid2::getPnEnumeration<spaceDim>(p,0,0),
107 loc_p1 = Intrepid2::getPnEnumeration<spaceDim>(p+1,0,0),
108 loc_m1 = Intrepid2::getPnEnumeration<spaceDim>(p-1,0,0);
109
110 const value_type
111 a = (2.0*p+1.0)/(1.0+p),
112 b = p / (p+1.0);
113
114 for (ordinal_type i=0;i<npts;++i) {
115 output0(loc_p1,i) = ( a * f1[i] * output0(loc,i) -
116 b * f2[i] * output0(loc_m1,i) );
117 if(hasDeriv) {
118 output.access(loc_p1,i,1) = a * (f1[i] * output.access(loc,i,1) + df1_0 * output0(loc,i)) -
119 b * f2[i] * output.access(loc_m1,i,1) ;
120 output.access(loc_p1,i,2) = a * (f1[i] * output.access(loc,i,2) + df1_1 * output0(loc,i)) -
121 b * (df2_1[i] * output0(loc_m1,i) + f2[i] * output.access(loc_m1,i,2)) ;
122 output.access(loc_p1,i,3) = a * (f1[i] * output.access(loc,i,3) + df1_2 * output0(loc,i)) -
123 b * (df2_2[i] * output0(loc_m1,i) + f2[i] * output.access(loc_m1,i,3)) ;
124 }
125 }
126 }
127
128 // D^{p,1,0}
129 for (ordinal_type p=0;p<order;++p) {
130 const ordinal_type
131 loc_p_0 = Intrepid2::getPnEnumeration<spaceDim>(p,0,0),
132 loc_p_1 = Intrepid2::getPnEnumeration<spaceDim>(p,1,0);
133
134 for (ordinal_type i=0;i<npts;++i) {
135 const value_type coeff = (2.0 * p + 3.0) * z(i,1) + z(i,2)-1.0;
136 output0(loc_p_1,i) = output0(loc_p_0,i)*coeff;
137 if(hasDeriv) {
138 output.access(loc_p_1,i,1) = output.access(loc_p_0,i,1)*coeff;
139 output.access(loc_p_1,i,2) = output.access(loc_p_0,i,2)*coeff + output0(loc_p_0,i)*(2.0 * p + 3.0);
140 output.access(loc_p_1,i,3) = output.access(loc_p_0,i,3)*coeff + output0(loc_p_0,i);
141 }
142 }
143 }
144
145
146 // recurrence in q
147 // D^{p,q+1,0}
148 for (ordinal_type p=0;p<order-1;++p)
149 for (ordinal_type q=1;q<order-p;++q) {
150 const ordinal_type
151 loc_p_qp1 = Intrepid2::getPnEnumeration<spaceDim>(p,q+1,0),
152 loc_p_q = Intrepid2::getPnEnumeration<spaceDim>(p,q,0),
153 loc_p_qm1 = Intrepid2::getPnEnumeration<spaceDim>(p,q-1,0);
154
155 value_type a,b,c, coeff, dcoeff_1, dcoeff_2;
156 Intrepid2::getJacobyRecurrenceCoeffs(a,b,c, 2*p+1,0,q);
157 for (ordinal_type i=0;i<npts;++i) {
158 coeff = a * f3[i] + b * f4[i];
159 dcoeff_1 = a * df3_1;
160 dcoeff_2 = a * df3_2 + b * df4_2;
161 output0(loc_p_qp1,i) = coeff * output0(loc_p_q,i)
162 - c* f5[i] * output0(loc_p_qm1,i) ;
163 if(hasDeriv) {
164 output.access(loc_p_qp1,i,1) = coeff * output.access(loc_p_q,i,1) +
165 - c * f5[i] * output.access(loc_p_qm1,i,1) ;
166 output.access(loc_p_qp1,i,2) = coeff * output.access(loc_p_q,i,2) + dcoeff_1 * output0(loc_p_q,i)
167 - c * f5[i] * output.access(loc_p_qm1,i,2) ;
168 output.access(loc_p_qp1,i,3) = coeff * output.access(loc_p_q,i,3) + dcoeff_2 * output0(loc_p_q,i)
169 - c * f5[i] * output.access(loc_p_qm1,i,3) - c * df5_2[i] * output0(loc_p_qm1,i);
170 }
171 }
172 }
173
174
175 // D^{p,q,1}
176 for (ordinal_type p=0;p<order;++p)
177 for (ordinal_type q=0;q<order-p;++q) {
178
179 const ordinal_type
180 loc_p_q_0 = Intrepid2::getPnEnumeration<spaceDim>(p,q,0),
181 loc_p_q_1 = Intrepid2::getPnEnumeration<spaceDim>(p,q,1);
182
183 for (ordinal_type i=0;i<npts;++i) {
184 const value_type coeff = 2.0 * ( 2.0 + q + p ) * z(i,2) - 1.0;
185 output0(loc_p_q_1,i) = output0(loc_p_q_0,i) * coeff;
186 if(hasDeriv) {
187 output.access(loc_p_q_1,i,1) = output.access(loc_p_q_0,i,1) * coeff;
188 output.access(loc_p_q_1,i,2) = output.access(loc_p_q_0,i,2) * coeff;
189 output.access(loc_p_q_1,i,3) = output.access(loc_p_q_0,i,3) * coeff + 2.0 * ( 2.0 + q + p ) * output0(loc_p_q_0,i);
190 }
191 }
192 }
193
194 // general r recurrence
195 // D^{p,q,r+1}
196 for (ordinal_type p=0;p<order-1;++p)
197 for (ordinal_type q=0;q<order-p-1;++q)
198 for (ordinal_type r=1;r<order-p-q;++r) {
199 const ordinal_type
200 loc_p_q_rp1 = Intrepid2::getPnEnumeration<spaceDim>(p,q,r+1),
201 loc_p_q_r = Intrepid2::getPnEnumeration<spaceDim>(p,q,r),
202 loc_p_q_rm1 = Intrepid2::getPnEnumeration<spaceDim>(p,q,r-1);
203
204 value_type a,b,c, coeff;
205 Intrepid2::getJacobyRecurrenceCoeffs(a,b,c, 2*p+2*q+2,0,r);
206 for (ordinal_type i=0;i<npts;++i) {
207 coeff = 2.0 * a * z(i,2) - a + b;
208 output0(loc_p_q_rp1,i) = coeff * output0(loc_p_q_r,i) - c * output0(loc_p_q_rm1,i) ;
209 if(hasDeriv) {
210 output.access(loc_p_q_rp1,i,1) = coeff * output.access(loc_p_q_r,i,1) - c * output.access(loc_p_q_rm1,i,1);
211 output.access(loc_p_q_rp1,i,2) = coeff * output.access(loc_p_q_r,i,2) - c * output.access(loc_p_q_rm1,i,2);
212 output.access(loc_p_q_rp1,i,3) = coeff * output.access(loc_p_q_r,i,3) + 2 * a * output0(loc_p_q_r,i) - c * output.access(loc_p_q_rm1,i,3);
213 }
214 }
215 }
216
217 }
218
219 // orthogonalize
220 for (ordinal_type p=0;p<=order;++p)
221 for (ordinal_type q=0;q<=order-p;++q)
222 for (ordinal_type r=0;r<=order-p-q;++r) {
223 ordinal_type loc_p_q_r = Intrepid2::getPnEnumeration<spaceDim>(p,q,r);
224 value_type scal = std::sqrt( (p+0.5)*(p+q+1.0)*(p+q+r+1.5) );
225 for (ordinal_type i=0;i<npts;++i) {
226 output0(loc_p_q_r,i) *= scal;
227 if(hasDeriv) {
228 output.access(loc_p_q_r,i,1) *= scal;
229 output.access(loc_p_q_r,i,2) *= scal;
230 output.access(loc_p_q_r,i,3) *= scal;
231 }
232 }
233 }
234}
235
236template<typename OutputViewType,
237typename inputViewType,
238typename workViewType,
239bool hasDeriv>
240KOKKOS_INLINE_FUNCTION
241void OrthPolynomialTet<OutputViewType,inputViewType,workViewType,hasDeriv,1>::generate(
242 OutputViewType output,
243 const inputViewType input,
244 workViewType work,
245 const ordinal_type order ) {
246 constexpr ordinal_type spaceDim = 3;
247 const ordinal_type
248 npts = input.extent(0),
249 card = output.extent(0);
250
251 workViewType dummyView;
252 OrthPolynomialTet<workViewType,inputViewType,workViewType,hasDeriv,0>::generate(work, input, dummyView, order);
253 for (ordinal_type i=0;i<card;++i)
254 for (ordinal_type j=0;j<npts;++j)
255 for (ordinal_type k=0;k<spaceDim;++k)
256 output.access(i,j,k) = work(i,j,k+1);
257}
258
259
260// when n >= 2, use recursion
261template<typename OutputViewType,
262typename inputViewType,
263typename workViewType,
264bool hasDeriv,
265ordinal_type n>
266KOKKOS_INLINE_FUNCTION
267void OrthPolynomialTet<OutputViewType,inputViewType,workViewType,hasDeriv,n>::generate(
268 OutputViewType /* output */,
269 const inputViewType /* input */,
270 workViewType /* work */,
271 const ordinal_type /* order */ ) {
272#if 0 //#ifdef HAVE_INTREPID2_SACADO
273
274constexpr ordinal_type spaceDim = 3;
275constexpr ordinal_type maxCard = Intrepid2::getPnCardinality<spaceDim, Parameters::MaxOrder>();
276
277typedef typename OutputViewType::value_type value_type;
278typedef Sacado::Fad::SFad<value_type,spaceDim> fad_type;
279
280const ordinal_type
281npts = input.extent(0),
282card = output.extent(0);
283
284// use stack buffer
285fad_type inBuf[Parameters::MaxNumPtsPerBasisEval][spaceDim];
286fad_type outBuf[maxCard][Parameters::MaxNumPtsPerBasisEval][n*(n+1)/2];
287
288typedef typename inputViewType::memory_space memory_space;
289typedef typename inputViewType::memory_space memory_space;
290typedef typename Kokkos::View<fad_type***, memory_space> outViewType;
291typedef typename Kokkos::View<fad_type**, memory_space> inViewType;
292
293inViewType in = createMatchingUnmanagedView<inViewType>(input, (value_type*)&inBuf[0][0], npts, spaceDim);
294outViewType out = createMatchingUnmanagedView<outViewType>(input, (value_type*)&outBuf[0][0][0], card, npts, n*(n+1)/2);
295
296for (ordinal_type i=0;i<npts;++i)
297 for (ordinal_type j=0;j<spaceDim;++j) {
298 in(i,j) = input(i,j);
299 in(i,j).diff(j,spaceDim);
300 }
301
302typedef typename Kokkos::DynRankView<fad_type, memory_space> outViewType_;
303outViewType_ workView;
304if (n==2) {
305 //char outBuf[bufSize*sizeof(typename inViewType::value_type)];
306 fad_type outBuf[maxCard][Parameters::MaxNumPtsPerBasisEval][spaceDim+1];
307 workView = createMatchingUnmanagedView<outViewType_>(in, (value_type*)&outBuf[0][0][0], card, npts, spaceDim+1);
308}
309OrthPolynomialTet<outViewType,inViewType,outViewType_,hasDeriv,n-1>::generate(out, in, workView, order);
310
311for (ordinal_type i=0;i<card;++i)
312 for (ordinal_type j=0;j<npts;++j) {
313 for (ordinal_type i_dx = 0; i_dx <= n; ++i_dx)
314 for (ordinal_type i_dy = 0; i_dy <= n-i_dx; ++i_dy) {
315 ordinal_type i_dz = n - i_dx - i_dy;
316 ordinal_type i_Dn = Intrepid2::getDkEnumeration<spaceDim>(i_dx,i_dy,i_dz);
317 if(i_dx > 0) {
318 //n=2: (f_x)_x, (f_y)_x, (f_z)_x
319 //n=3: (f_xx)_x, (f_xy)_x, (f_xz)_x, (f_yy)_x, (f_yz)_x, (f_zz)_x
320 ordinal_type i_Dnm1 = Intrepid2::getDkEnumeration<spaceDim>(i_dx-1, i_dy, i_dz);
321 output.access(i,j,i_Dn) = out(i,j,i_Dnm1).dx(0);
322 }
323 else if (i_dy > 0) {
324 //n=2: (f_y)_y, (f_z)_y
325 //n=3: (f_yy)_y, (f_yz)_y, (f_zz)_y
326 ordinal_type i_Dnm1 = Intrepid2::getDkEnumeration<spaceDim>(i_dx, i_dy-1, i_dz);
327 output.access(i,j,i_Dn) = out(i,j,i_Dnm1).dx(1);
328 }
329 else {
330 //n=2: (f_z)_z;
331 //n=3: (f_zz)_z
332 ordinal_type i_Dnm1 = Intrepid2::getDkEnumeration<spaceDim>(i_dx, i_dy, i_dz-1);
333 output.access(i,j,i_Dn) = out(i,j,i_Dnm1).dx(2);
334 }
335 }
336 }
337#else
338INTREPID2_TEST_FOR_ABORT( true,
339 ">>> ERROR: (Intrepid2::Basis_HGRAD_TRI_Cn_FEM_ORTH::OrthPolynomialTri) Computing of second and higher-order derivatives is not currently supported");
340#endif
341}
342
343
344template<EOperator opType>
345template<typename OutputViewType,
346typename inputViewType,
347typename workViewType>
348KOKKOS_INLINE_FUNCTION
349void
351getValues( OutputViewType output,
352 const inputViewType input,
353 workViewType work,
354 const ordinal_type order) {
355 switch (opType) {
356 case OPERATOR_VALUE: {
357 OrthPolynomialTet<OutputViewType,inputViewType,workViewType,false,0>::generate( output, input, work, order );
358 break;
359 }
360 case OPERATOR_GRAD:
361 case OPERATOR_D1: {
362 OrthPolynomialTet<OutputViewType,inputViewType,workViewType,true,1>::generate( output, input, work, order );
363 break;
364 }
365 case OPERATOR_D2: {
366 OrthPolynomialTet<OutputViewType,inputViewType,workViewType,true,2>::generate( output, input, work, order );
367 break;
368 }
369 default: {
370 INTREPID2_TEST_FOR_ABORT( true,
371 ">>> ERROR: (Intrepid2::Basis_HGRAD_TET_Cn_FEM_ORTH::Serial::getValues) operator is not supported");
372 }
373 }
374}
375
376// -------------------------------------------------------------------------------------
377
378template<typename DT, ordinal_type numPtsPerEval,
379typename outputValueValueType, class ...outputValueProperties,
380typename inputPointValueType, class ...inputPointProperties>
381void
382Basis_HGRAD_TET_Cn_FEM_ORTH::
383getValues(
384 const typename DT::execution_space& space,
385 Kokkos::DynRankView<outputValueValueType,outputValueProperties...> outputValues,
386 const Kokkos::DynRankView<inputPointValueType, inputPointProperties...> inputPoints,
387 const ordinal_type order,
388 const EOperator operatorType ) {
389 typedef Kokkos::DynRankView<outputValueValueType,outputValueProperties...> outputValueViewType;
390 typedef Kokkos::DynRankView<inputPointValueType, inputPointProperties...> inputPointViewType;
391 typedef typename DT::execution_space ExecSpaceType;
392
393 // loopSize corresponds to the # of points
394 const auto loopSizeTmp1 = (inputPoints.extent(0)/numPtsPerEval);
395 const auto loopSizeTmp2 = (inputPoints.extent(0)%numPtsPerEval != 0);
396 const auto loopSize = loopSizeTmp1 + loopSizeTmp2;
397 Kokkos::RangePolicy<ExecSpaceType,Kokkos::Schedule<Kokkos::Static> > policy(space, 0, loopSize);
398
399 const ordinal_type cardinality = outputValues.extent(0);
400 const ordinal_type spaceDim = 3;
401
402 typedef typename DeduceDynRankView<inputPointViewType>::type workViewType;
403
404 switch (operatorType) {
405 case OPERATOR_VALUE: {
406 workViewType dummyWorkView;
408 Kokkos::parallel_for( policy, FunctorType(outputValues, inputPoints, dummyWorkView, order) );
409 break;
410 }
411 case OPERATOR_GRAD:
412 case OPERATOR_D1: {
413 workViewType work = createMatchingView<workViewType>(inputPoints, "Basis_HGRAD_TET_In_FEM_ORTH::getValues::work", cardinality, inputPoints.extent(0), spaceDim+1);
415 Kokkos::parallel_for( policy, FunctorType(outputValues, inputPoints, work, order) );
416 break;
417 }
418 case OPERATOR_D2:{
419 workViewType dummyWorkView;
421 Kokkos::parallel_for( policy, FunctorType(outputValues, inputPoints ,dummyWorkView, order) );
422 break;
423 }
424 default: {
425 INTREPID2_TEST_FOR_EXCEPTION( !Intrepid2::isValidOperator(operatorType), std::invalid_argument,
426 ">>> ERROR (Basis_HGRAD_TET_Cn_FEM_ORTH): invalid operator type");
427 }
428 }
429}
430}
431
432
433// -------------------------------------------------------------------------------------
434template<typename DT, typename OT, typename PT>
436Basis_HGRAD_TET_Cn_FEM_ORTH( const ordinal_type order ) {
437
438 constexpr ordinal_type spaceDim = 3;
440 this->basisDegree_ = order;
441 this->basisCellTopologyKey_ = shards::Tetrahedron<4>::key;
442 this->basisType_ = BASIS_FEM_HIERARCHICAL;
443 this->basisCoordinates_ = COORDINATES_CARTESIAN;
444 this->functionSpace_ = FUNCTION_SPACE_HGRAD;
445
446 // initialize tags
447 {
448 // Basis-dependent initializations
449 constexpr ordinal_type tagSize = 4; // size of DoF tag, i.e., number of fields in the tag
450 const ordinal_type posScDim = 0; // position in the tag, counting from 0, of the subcell dim
451 const ordinal_type posScOrd = 1; // position in the tag, counting from 0, of the subcell ordinal
452 const ordinal_type posDfOrd = 2; // position in the tag, counting from 0, of DoF ordinal relative to the subcell
453
454 constexpr ordinal_type maxCard = Intrepid2::getPnCardinality<spaceDim, Parameters::MaxOrder>();
455 ordinal_type tags[maxCard][tagSize];
456 const ordinal_type card = this->basisCardinality_;
457 for (ordinal_type i=0;i<card;++i) {
458 tags[i][0] = 2; // these are all "internal" i.e. "volume" DoFs
459 tags[i][1] = 0; // there is only one line
460 tags[i][2] = i; // local DoF id
461 tags[i][3] = card; // total number of DoFs
462 }
463
464 OrdinalTypeArray1DHost tagView(&tags[0][0], card*tagSize);
465
466 // Basis-independent function sets tag and enum data in tagToOrdinal_ and ordinalToTag_ arrays:
467 // tags are constructed on host
469 this->ordinalToTag_,
470 tagView,
471 this->basisCardinality_,
472 tagSize,
473 posScDim,
474 posScOrd,
475 posDfOrd);
476 }
477
478 // dof coords is not applicable to hierarchical functions
479}
480
481}
482#endif
KOKKOS_INLINE_FUNCTION void getJacobyRecurrenceCoeffs(value_type &an, value_type &bn, value_type &cn, const ordinal_type alpha, const ordinal_type beta, const ordinal_type n)
function for computing the Jacobi recurrence coefficients so that
KOKKOS_INLINE_FUNCTION ordinal_type getPnCardinality(ordinal_type n)
Returns cardinality of Polynomials of order n (P^n).
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...
Basis_HGRAD_TET_Cn_FEM_ORTH(const ordinal_type order)
Constructor.
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)
Kokkos::View< ordinal_type *, typename ExecutionSpace::array_layout, Kokkos::HostSpace > OrdinalTypeArray1DHost
static constexpr ordinal_type MaxNumPtsPerBasisEval
The maximum number of points to eval in serial mode.