Nektar++
Loading...
Searching...
No Matches
StdPyrExp.cpp
Go to the documentation of this file.
1///////////////////////////////////////////////////////////////////////////////
2//
3// File: StdPyrExp.cpp
4//
5// For more information, please see: http://www.nektar.info
6//
7// The MIT License
8//
9// Copyright (c) 2006 Division of Applied Mathematics, Brown University (USA),
10// Department of Aeronautics, Imperial College London (UK), and Scientific
11// Computing and Imaging Institute, University of Utah (USA).
12//
13// Permission is hereby granted, free of charge, to any person obtaining a
14// copy of this software and associated documentation files (the "Software"),
15// to deal in the Software without restriction, including without limitation
16// the rights to use, copy, modify, merge, publish, distribute, sublicense,
17// and/or sell copies of the Software, and to permit persons to whom the
18// Software is furnished to do so, subject to the following conditions:
19//
20// The above copyright notice and this permission notice shall be included
21// in all copies or substantial portions of the Software.
22//
23// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
24// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
26// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29// DEALINGS IN THE SOFTWARE.
30//
31// Description: pyramidic routines built upon StdExpansion3D
32//
33///////////////////////////////////////////////////////////////////////////////
34
37#include <iomanip>
38
39using namespace std;
43
44namespace Nektar::StdRegions
45{
46// Declaretion of scalar routine
50
52 const LibUtilities::BasisKey &Bb,
53 const LibUtilities::BasisKey &Bc)
54 : StdExpansion(LibUtilities::StdPyrData::getNumberOfCoefficients(
55 Ba.GetNumModes(), Bb.GetNumModes(), Bc.GetNumModes()),
56 3, Ba, Bb, Bc),
57 StdExpansion3D(LibUtilities::StdPyrData::getNumberOfCoefficients(
58 Ba.GetNumModes(), Bb.GetNumModes(), Bc.GetNumModes()),
59 Ba, Bb, Bc)
60{
61
62 ASSERTL0(Ba.GetNumModes() <= Bc.GetNumModes(),
63 "order in 'a' direction is higher "
64 "than order in 'c' direction");
65 ASSERTL0(Bb.GetNumModes() <= Bc.GetNumModes(),
66 "order in 'b' direction is higher "
67 "than order in 'c' direction");
70 "Expected basis type in 'c' direction to be ModifiedPyr_C or "
71 "OrthoPyr_C");
72
73 // cache integration weights for future use
74 m_weights.push_back(m_base[0]->GetW());
75 m_weights.push_back(m_base[1]->GetW());
76
77 StdFacKey w2key(eWeights2, Bc);
78 // get weights[2] from manager where points are rescaled
79 m_weights.push_back(GetStdFac(w2key));
80}
81
82//---------------------------------------
83// Differentiation/integration Methods
84//---------------------------------------
85/**
86 * \brief Calculate the derivative of the physical points
87 *
88 * The derivative is evaluated at the nodal physical points.
89 * Derivatives with respect to the local Cartesian coordinates.
90 *
91 * \f$\begin{Bmatrix} \frac {\partial} {\partial \xi_1} \\ \frac
92 * {\partial} {\partial \xi_2} \\ \frac {\partial} {\partial \xi_3}
93 * \end{Bmatrix} = \begin{Bmatrix} \frac 2 {(1-\eta_3)} \frac \partial
94 * {\partial \bar \eta_1} \\ \frac {\partial} {\partial \xi_2} \ \
95 * \frac {(1 + \bar \eta_1)} {(1 - \eta_3)} \frac \partial {\partial
96 * \bar \eta_1} + \frac {\partial} {\partial \eta_3} \end{Bmatrix}\f$
97 */
99 Array<OneD, NekDouble> &out_dxi1,
100 Array<OneD, NekDouble> &out_dxi2,
101 Array<OneD, NekDouble> &out_dxi3)
102{
103 // PhysDerivative implementation based on Spen's book page 152.
104 int Qx = m_base[0]->GetNumPoints();
105 int Qy = m_base[1]->GetNumPoints();
106 int Qz = m_base[2]->GetNumPoints();
107
108 Array<OneD, NekDouble> dEta_bar1(Qx * Qy * Qz, 0.0);
109 Array<OneD, NekDouble> dXi2(Qx * Qy * Qz, 0.0);
110 Array<OneD, NekDouble> dEta3(Qx * Qy * Qz, 0.0);
111 PhysTensorDeriv(u_physical, dEta_bar1, dXi2, dEta3);
112
113 Array<OneD, const NekDouble> eta_x, eta_y, eta_z;
114 eta_x = m_base[0]->GetZ();
115 eta_y = m_base[1]->GetZ();
116 eta_z = m_base[2]->GetZ();
117
118 int i, j, k, n;
119
120 if (out_dxi1.size() > 0)
121 {
122 for (k = 0, n = 0; k < Qz; ++k)
123 {
124 NekDouble fac = 2.0 / (1.0 - eta_z[k]);
125 for (j = 0; j < Qy; ++j)
126 {
127 for (i = 0; i < Qx; ++i, ++n)
128 {
129 out_dxi1[n] = fac * dEta_bar1[n];
130 }
131 }
132 }
133 }
134
135 if (out_dxi2.size() > 0)
136 {
137 for (k = 0, n = 0; k < Qz; ++k)
138 {
139 NekDouble fac = 2.0 / (1.0 - eta_z[k]);
140 for (j = 0; j < Qy; ++j)
141 {
142 for (i = 0; i < Qx; ++i, ++n)
143 {
144 out_dxi2[n] = fac * dXi2[n];
145 }
146 }
147 }
148 }
149
150 if (out_dxi3.size() > 0)
151 {
152 for (k = 0, n = 0; k < Qz; ++k)
153 {
154 NekDouble fac = 1.0 / (1.0 - eta_z[k]);
155 for (j = 0; j < Qy; ++j)
156 {
157 NekDouble fac1 = (1.0 + eta_y[j]);
158 for (i = 0; i < Qx; ++i, ++n)
159 {
160 out_dxi3[n] = (1.0 + eta_x[i]) * fac * dEta_bar1[n] +
161 fac1 * fac * dXi2[n] + dEta3[n];
162 }
163 }
164 }
165 }
166}
167
168//---------------------------------------
169// Transforms
170//---------------------------------------
171
172/**
173 * \brief Backward transformation is evaluated at the quadrature
174 * points.
175 *
176 * \f$ u^{\delta} (\xi_{1i}, \xi_{2j}, \xi_{3k}) = \sum_{m(pqr)} \hat
177 * u_{pqr} \phi_{pqr} (\xi_{1i}, \xi_{2j}, \xi_{3k})\f$
178 *
179 * Backward transformation is three dimensional tensorial expansion
180 *
181 * \f$ u (\xi_{1i}, \xi_{2j}, \xi_{3k}) = \sum_{p=0}^{Q_x} \psi_p^a
182 * (\xi_{1i}) \lbrace { \sum_{q=0}^{Q_y} \psi_{q}^a (\xi_{2j})
183 * \lbrace { \sum_{r=0}^{Q_z} \hat u_{pqr} \psi_{pqr}^c (\xi_{3k})
184 * \rbrace} \rbrace}. \f$
185 *
186 * And sumfactorizing step of the form is as:\ \ \f$ f_{pqr}
187 * (\xi_{3k}) = \sum_{r=0}^{Q_z} \hat u_{pqr} \psi_{pqr}^c
188 * (\xi_{3k}),\\ g_{p} (\xi_{2j}, \xi_{3k}) = \sum_{r=0}^{Q_y}
189 * \psi_{p}^a (\xi_{2j}) f_{pqr} (\xi_{3k}),\\ u(\xi_{1i}, \xi_{2j},
190 * \xi_{3k}) = \sum_{p=0}^{Q_x} \psi_{p}^a (\xi_{1i}) g_{p}
191 * (\xi_{2j}, \xi_{3k}). \f$
192 **/
194 Array<OneD, NekDouble> &outarray)
195{
196 const Array<OneD, const NekDouble> base0 = m_base[0]->GetBdata();
197 const Array<OneD, const NekDouble> base1 = m_base[1]->GetBdata();
198 const Array<OneD, const NekDouble> base2 = m_base[2]->GetBdata();
199
200 int nquad0 = m_base[0]->GetNumPoints();
201 int nquad1 = m_base[1]->GetNumPoints();
202 int nquad2 = m_base[2]->GetNumPoints();
203
204 int nmodes0 = m_base[0]->GetNumModes();
205 int nmodes1 = m_base[1]->GetNumModes();
206 int nmodes2 = m_base[2]->GetNumModes();
207
208 bool isModified = (m_base[0]->GetBasisType() == LibUtilities::eModified_A);
209
210 std::vector<vec_t, tinysimd::allocator<vec_t>> wsp0(nmodes0 * nmodes1),
211 wsp1(nmodes0);
212
213 // Switch statment using boost_pp and macros. This unfolls intwo a
214 // nested swtich statement where the outer swtich statement runs
215 // from SMIN to SMAX for modal order and the inner switch
216 // statemets run from the outer value of the case to 2*SMAX for
217 // the quadrature order. If you want to see it unwrapped compile
218 // in verbose mode and add --preprocess to the c++ command.
219 // Default case
220#undef BWDTRANS_DEF
221#define BWDTRANS_DEF \
222 BwdTransPyrKernel(nmodes0, nmodes1, nmodes2, nquad0, nquad1, nquad2, \
223 isModified, (const vec_t *)base0.data(), \
224 (const vec_t *)base1.data(), \
225 (const vec_t *)base2.data(), wsp0.data(), wsp1.data(), \
226 (const vec_t *)inarray.data(), (vec_t *)outarray.data())
227
228 // Inner loop case over quarature points
229#undef BWDTRANS_Q
230#define BWDTRANS_Q(r, i) \
231 case NQ(i): \
232 BwdTransPyrKernel( \
233 NM(i), NM(i), NM(i), NQ(i), NQ(i), NQ_M1(i), isModified, \
234 (const vec_t *)base0.data(), (const vec_t *)base1.data(), \
235 (const vec_t *)base2.data(), wsp0.data(), wsp1.data(), \
236 (const vec_t *)inarray.data(), (vec_t *)outarray.data()); \
237 break;
238
239 // outer loop case over modes
240#undef BWDTRANS_M
241#define BWDTRANS_M(r, i) \
242 case NM(i): \
243 { \
244 switch (nquad0) \
245 { \
246 BOOST_PP_FOR_##r((NM(i), NM_P1(i), BOOST_PP_MUL(2, NM(i))), \
247 STDLEV2TEST1, STDLEV2UPDATE1, BWDTRANS_Q) default \
248 : BWDTRANS_DEF; \
249 break; \
250 } \
251 } \
252 break;
253
254 // templated cases on equi-ordered modes and standard quad
255 // usage where quad order goes from mode order to 2(*mode
256 // order)
257 if ((nmodes0 == nmodes1) && (nmodes1 == nmodes2) && (nquad0 == nquad1) &&
258 (nquad1 == nquad2 + 1))
259 {
260 switch (nmodes0)
261 {
262 BOOST_PP_FOR((SMIN, 0, SMAX), STDLEV2TEST, STDLEV2UPDATE,
264 default:
266 break;
267 }
268 }
269 else
270 {
272 }
273}
274
275//---------------------------------------
276// Inner product functions
277//---------------------------------------
278/** \brief Inner product of \a inarray over region with respect to the
279 * expansion basis (this)->m_base[0] and return in \a outarray
280 *
281 * @param base0 - An array containing the values of the basis in the
282 * 0-direction at the quarature poitns
283 * @param base1 - An array containing the values of the basis in the
284 * 1-direction at the quarature poitns
285 * @param base2 - An array containing the values of the basis in the
286 * 2-direction at the quarature poitns
287 * @param inarray - Array of values evaluated at the physical
288 * quadrature points
289 * @param outarray the values of the inner product with respect to
290 * each basis over region will be stored in the array \a outarray as
291 * output of the function
292 * @param jac - An array of size 1 if not deformed or the number of
293 * quadrature points if deformed holding the values of the jacobian
294 * @param Deformed - a bool identifying if the inner product is to be
295 * treated as a deformed or regular integration which just relates to
296 * how the \param jac array is treated
297 */
299 const Array<OneD, const NekDouble> &base0,
300 const Array<OneD, const NekDouble> &base1,
301 const Array<OneD, const NekDouble> &base2,
302 const Array<OneD, const NekDouble> &inarray,
304 const bool Deformed, [[maybe_unused]] bool CollDir0,
305 [[maybe_unused]] bool CollDir1, [[maybe_unused]] bool CollDir2)
306{
307 int nquad0 = m_base[0]->GetNumPoints();
308 int nquad1 = m_base[1]->GetNumPoints();
309 int nquad2 = m_base[2]->GetNumPoints();
310
311 int order0 = m_base[0]->GetNumModes();
312 int order1 = m_base[1]->GetNumModes();
313 int order2 = m_base[2]->GetNumModes();
314
315 const bool isModified =
316 (m_base[0]->GetBasisType() == LibUtilities::eModified_A);
317
318 std::vector<vec_t, tinysimd::allocator<vec_t>> wsp0(nquad1 * nquad2),
319 wsp1(nquad2);
320
321 // Swith statment using boost_pp and macros. This unfolls intwo a
322 // nested swtich statement where the outer swtich statement runs
323 // from SMIN to SMAX for modal order and the inner switch
324 // statemets run from the outer value of the case to 2*SMAX for
325 // the quadrature order. If you want to see it unwrapped compile
326 // in verbose mode and add --preprocess to the c++ command.
327 if (Deformed)
328 {
329 // Default case
330#undef IPRODUCTWRTBASE_DEF
331#define IPRODUCTWRTBASE_DEF \
332 IProductPyrKernel<false, false, true>( \
333 order0, order1, order2, nquad0, nquad1, nquad2, isModified, \
334 (const vec_t *)inarray.data(), (const vec_t *)base0.data(), \
335 (const vec_t *)base1.data(), (const vec_t *)base2.data(), \
336 (const vec_t *)m_weights[0].data(), \
337 (const vec_t *)m_weights[1].data(), \
338 (const vec_t *)m_weights[2].data(), (const vec_t *)jac.data(), \
339 (vec_t *)wsp0.data(), (vec_t *)wsp1.data(), (vec_t *)outarray.data())
340
341 // Inner loop case over quarature points
342#undef IPRODUCTWRTBASE_Q
343#define IPRODUCTWRTBASE_Q(r, i) \
344 case NQ(i): \
345 IProductPyrKernel<false, false, true>( \
346 NM(i), NM(i), NM(i), NQ(i), NQ(i), NQ_M1(i), isModified, \
347 (const vec_t *)inarray.data(), (const vec_t *)base0.data(), \
348 (const vec_t *)base1.data(), (const vec_t *)base2.data(), \
349 (const vec_t *)m_weights[0].data(), \
350 (const vec_t *)m_weights[1].data(), \
351 (const vec_t *)m_weights[2].data(), (const vec_t *)jac.data(), \
352 (vec_t *)wsp0.data(), (vec_t *)wsp1.data(), \
353 (vec_t *)outarray.data()); \
354 break;
355
356 // outer loop case over modes
357#undef IPRODUCTWRTBASE_M
358#define IPRODUCTWRTBASE_M(r, i) \
359 case NM(i): \
360 { \
361 switch (nquad0) \
362 { \
363 BOOST_PP_FOR_##r((NM(i), NM_P1(i), BOOST_PP_MUL(2, NM(i))), \
364 STDLEV2TEST1, STDLEV2UPDATE1, \
365 IPRODUCTWRTBASE_Q) default : IPRODUCTWRTBASE_DEF; \
366 break; \
367 } \
368 } \
369 break;
370
371 // templated cases on equi-ordered modes and standard quad usage
372 // where quad order goes from mode order to 2(*mode order)
373 if ((order0 == order1) && (order1 == order2) && (nquad0 == nquad1) &&
374 (nquad1 == nquad2 + 1))
375 {
376 switch (order0)
377 {
378 BOOST_PP_FOR((SMIN, 0, SMAX), STDLEV2TEST, STDLEV2UPDATE,
380 default:
382 break;
383 }
384 }
385 else
386 {
388 }
389 }
390 else // non-deformed case
391 {
392 // Default case
393#undef IPRODUCTWRTBASE_DEF
394#define IPRODUCTWRTBASE_DEF \
395 IProductPyrKernel<false, false, false>( \
396 order0, order1, order2, nquad0, nquad1, nquad2, isModified, \
397 (const vec_t *)inarray.data(), (const vec_t *)base0.data(), \
398 (const vec_t *)base1.data(), (const vec_t *)base2.data(), \
399 (const vec_t *)m_weights[0].data(), \
400 (const vec_t *)m_weights[1].data(), \
401 (const vec_t *)m_weights[2].data(), (const vec_t *)jac.data(), \
402 (vec_t *)wsp0.data(), (vec_t *)wsp1.data(), (vec_t *)outarray.data())
403
404 // Inner loop case over quarature points
405#undef IPRODUCTWRTBASE_Q
406#define IPRODUCTWRTBASE_Q(r, i) \
407 case NQ(i): \
408 IProductPyrKernel<false, false, false>( \
409 NM(i), NM(i), NM(i), NQ(i), NQ(i), NQ_M1(i), isModified, \
410 (const vec_t *)inarray.data(), (const vec_t *)base0.data(), \
411 (const vec_t *)base1.data(), (const vec_t *)base2.data(), \
412 (const vec_t *)m_weights[0].data(), \
413 (const vec_t *)m_weights[1].data(), \
414 (const vec_t *)m_weights[2].data(), (const vec_t *)jac.data(), \
415 (vec_t *)wsp0.data(), (vec_t *)wsp1.data(), \
416 (vec_t *)outarray.data()); \
417 break;
418
419 // outer loop case over modes
420#undef IPRODUCTWRTBASE_M
421#define IPRODUCTWRTBASE_M(r, i) \
422 case NM(i): \
423 { \
424 switch (nquad0) \
425 { \
426 BOOST_PP_FOR_##r((NM(i), NM_P1(i), BOOST_PP_MUL(2, NM(i))), \
427 STDLEV2TEST1, STDLEV2UPDATE1, \
428 IPRODUCTWRTBASE_Q) default : IPRODUCTWRTBASE_DEF; \
429 break; \
430 } \
431 } \
432 break;
433
434 // templated cases on equi-ordered modes and standard quad usage
435 // where quad order goes from mode order to 2(*mode order)
436 if ((order0 == order1) && (order1 == order2) && (nquad0 == nquad1) &&
437 (nquad1 == nquad2 + 1))
438 {
439 switch (order0)
440 {
441 BOOST_PP_FOR((SMIN, 0, SMAX), STDLEV2TEST, STDLEV2UPDATE,
443 default:
445 break;
446 }
447 }
448 else
449 {
451 }
452 }
453}
454
456 const int dir, const Array<OneD, const NekDouble> &inarray,
457 Array<OneD, NekDouble> &outarray)
458{
459 int nquad0 = m_base[0]->GetNumPoints();
460 int nquad1 = m_base[1]->GetNumPoints();
461 int nquad2 = m_base[2]->GetNumPoints();
462
463 StdFacKey fackey2(eTwoOverOneMinusZ2, m_base[2]->GetBasisKey());
465
466 Array<OneD, NekDouble> tmp0(nquad0 * nquad1 * nquad2);
467
468 // Derivative in first/second direction is always scaled as follows
469 const int nq01 = nquad0 * nquad1;
470 for (int i = 0; i < nquad2; ++i)
471 {
472 Vmath::Smul(nq01, gfac2[i], &inarray[0] + i * nq01, 1,
473 &tmp0[0] + i * nq01, 1);
474 }
475
476 const Array<OneD, const NekDouble> one(1, 1.0);
477
478 switch (dir)
479 {
480 case 0:
481 {
483 m_base[0]->GetDbdata(), m_base[1]->GetBdata(),
484 m_base[2]->GetBdata(), tmp0, outarray, one, false);
485 }
486 break;
487 case 1:
488 {
490 m_base[0]->GetBdata(), m_base[1]->GetDbdata(),
491 m_base[2]->GetBdata(), tmp0, outarray, one, false);
492 }
493 break;
494 case 2:
495 {
496 StdFacKey fackey0(eHalfMultOnePlusZ0, m_base[0]->GetBasisKey());
498 StdFacKey fackey1(eHalfMultOnePlusZ1, m_base[1]->GetBasisKey());
500
503
504 // Scale eta_1 derivative by gfac0
505 for (int i = 0; i < nquad1 * nquad2; ++i)
506 {
507 Vmath::Vmul(nquad0, tmp0.data() + i * nquad0, 1, gfac0.data(),
508 1, tmp0.data() + i * nquad0, 1);
509 }
511 m_base[0]->GetDbdata(), m_base[1]->GetBdata(),
512 m_base[2]->GetBdata(), tmp0, tmp3, one, false);
513
514 // Scale eta_2 derivative by gfac1*gfac2
515 for (int i = 0; i < nquad2; ++i)
516 {
517 Vmath::Smul(nq01, gfac2[i], &inarray[0] + i * nq01, 1,
518 &tmp0[0] + i * nq01, 1);
519 }
520
521 for (int i = 0; i < nquad1 * nquad2; ++i)
522 {
523 Vmath::Smul(nquad0, gfac1[i % nquad1], &tmp0[0] + i * nquad0, 1,
524 &tmp0[0] + i * nquad0, 1);
525 }
526
528 m_base[0]->GetBdata(), m_base[1]->GetDbdata(),
529 m_base[2]->GetBdata(), tmp0, tmp4, one, false);
530
532 m_base[0]->GetBdata(), m_base[1]->GetBdata(),
533 m_base[2]->GetDbdata(), inarray, outarray, one, false);
534
535 Vmath::Vadd(m_ncoeffs, &tmp3[0], 1, &outarray[0], 1, &outarray[0],
536 1);
537 Vmath::Vadd(m_ncoeffs, &tmp4[0], 1, &outarray[0], 1, &outarray[0],
538 1);
539 break;
540 }
541 default:
542 {
543 ASSERTL1(false, "input dir is out of range");
544 break;
545 }
546 }
547}
548
549//---------------------------------------
550// Evaluation functions
551//---------------------------------------
552
555{
556 NekDouble d2 = 1.0 - xi[2];
557 if (fabs(d2) < NekConstants::kNekZeroTol)
558 {
559 if (d2 >= 0.)
560 {
562 }
563 else
564 {
566 }
567 }
568 eta[2] = xi[2]; // eta_z = xi_z
569 eta[1] = 2.0 * (1.0 + xi[1]) / d2 - 1.0;
570 eta[0] = 2.0 * (1.0 + xi[0]) / d2 - 1.0;
571}
572
575{
576 xi[0] = (1.0 + eta[0]) * (1.0 - eta[2]) * 0.5 - 1.0;
577 xi[1] = (1.0 + eta[1]) * (1.0 - eta[2]) * 0.5 - 1.0;
578 xi[2] = eta[2];
579}
580
584{
585 Array<OneD, const NekDouble> etaBar_x = m_base[0]->GetZ();
586 Array<OneD, const NekDouble> eta_y = m_base[1]->GetZ();
587 Array<OneD, const NekDouble> eta_z = m_base[2]->GetZ();
588 int Qx = GetNumPoints(0);
589 int Qy = GetNumPoints(1);
590 int Qz = GetNumPoints(2);
591
592 // Convert collapsed coordinates into cartesian coordinates: eta --> xi
593 for (int k = 0; k < Qz; ++k)
594 {
595 for (int j = 0; j < Qy; ++j)
596 {
597 for (int i = 0; i < Qx; ++i)
598 {
599 int s = i + Qx * (j + Qy * k);
600
601 xi_z[s] = eta_z[k];
602 xi_y[s] = (1.0 + eta_y[j]) * (1.0 - eta_z[k]) / 2.0 - 1.0;
603 xi_x[s] = (1.0 + etaBar_x[i]) * (1.0 - eta_z[k]) / 2.0 - 1.0;
604 }
605 }
606 }
607}
608
610 const Array<OneD, const NekDouble> &coords, int mode)
611{
613 LocCoordToLocCollapsed(coords, coll);
614
615 const int nm0 = m_base[0]->GetNumModes();
616 const int nm1 = m_base[1]->GetNumModes();
617 const int nm2 = m_base[2]->GetNumModes();
618
619 int mode0 = 0, mode1 = 0, mode2 = 0, cnt = 0;
620
621 bool found = false;
622 for (mode0 = 0; mode0 < nm0; ++mode0)
623 {
624 for (mode1 = 0; mode1 < nm1; ++mode1)
625 {
626 int maxpq = max(mode0, mode1);
627 for (mode2 = 0; mode2 < nm2 - maxpq; ++mode2, ++cnt)
628 {
629 if (cnt == mode)
630 {
631 found = true;
632 break;
633 }
634 }
635
636 if (found)
637 {
638 break;
639 }
640 }
641
642 if (found)
643 {
644 break;
645 }
646
647 for (int j = nm1; j < nm2; ++j)
648 {
649 int ijmax = max(mode0, j);
650 mode2 += nm2 - ijmax;
651 }
652 }
653
654 if (mode == 1 && m_base[0]->GetBasisType() == LibUtilities::eModified_A)
655 {
656 return StdExpansion::BaryEvaluateBasis<2>(coll[2], 1);
657 }
658 else
659 {
660 return StdExpansion::BaryEvaluateBasis<0>(coll[0], mode0) *
661 StdExpansion::BaryEvaluateBasis<1>(coll[1], mode1) *
662 StdExpansion::BaryEvaluateBasis<2>(coll[2], mode2);
663 }
664}
665
667 const Array<OneD, NekDouble> &coord,
668 const Array<OneD, const NekDouble> &inarray,
669 std::array<NekDouble, 3> &firstOrderDerivs)
670{
671 // Collapse coordinates
672 Array<OneD, NekDouble> coll(3, 0.0);
673 LocCoordToLocCollapsed(coord, coll);
674
675 // If near singularity do the old interpolation matrix method
676 if ((1 - coll[2]) < 1e-5)
677 {
678 int totPoints = GetTotPoints();
679 Array<OneD, NekDouble> EphysDeriv0(totPoints), EphysDeriv1(totPoints),
680 EphysDeriv2(totPoints);
681 v_PhysDeriv(inarray, EphysDeriv0, EphysDeriv1, EphysDeriv2);
682
684 I[0] = GetBase()[0]->GetI(coll);
685 I[1] = GetBase()[1]->GetI(coll + 1);
686 I[2] = GetBase()[2]->GetI(coll + 2);
687
688 firstOrderDerivs[0] = PhysEvaluate(I, EphysDeriv0);
689 firstOrderDerivs[1] = PhysEvaluate(I, EphysDeriv1);
690 firstOrderDerivs[2] = PhysEvaluate(I, EphysDeriv2);
691 return PhysEvaluate(I, inarray);
692 }
693
694 std::array<NekDouble, 3> interDeriv;
695 NekDouble val = StdExpansion3D::BaryTensorDeriv(coll, inarray, interDeriv);
696
697 NekDouble fac = 2.0 / (1.0 - coll[2]);
698
699 firstOrderDerivs[0] = fac * interDeriv[0];
700 firstOrderDerivs[1] = fac * interDeriv[1];
701 firstOrderDerivs[2] = ((1.0 + coll[0]) / (1.0 - coll[2])) * interDeriv[0] +
702 ((1.0 + coll[1]) / (1.0 - coll[2])) * interDeriv[1] +
703 interDeriv[2];
704
705 return val;
706}
707
708void StdPyrExp::v_FillMode(const int mode, Array<OneD, NekDouble> &outarray)
709{
711 tmp[mode] = 1.0;
712 v_BwdTrans(tmp, outarray);
713}
714
715void StdPyrExp::v_GetTraceNumModes(const int fid, int &numModes0,
716 int &numModes1, Orientation faceOrient)
717{
718 int nummodes[3] = {m_base[0]->GetNumModes(), m_base[1]->GetNumModes(),
719 m_base[2]->GetNumModes()};
720 switch (fid)
721 {
722 // quad
723 case 0:
724 {
725 numModes0 = nummodes[0];
726 numModes1 = nummodes[1];
727 }
728 break;
729 case 1:
730 case 3:
731 {
732 numModes0 = nummodes[0];
733 numModes1 = nummodes[2];
734 }
735 break;
736 case 2:
737 case 4:
738 {
739 numModes0 = nummodes[1];
740 numModes1 = nummodes[2];
741 }
742 break;
743 }
744
745 if (faceOrient >= 9)
746 {
747 std::swap(numModes0, numModes1);
748 }
749}
750
751//---------------------------------------
752// Helper functions
753//---------------------------------------
754
756{
757 return 5;
758}
759
761{
762 return 8;
763}
764
766{
767 return 5;
768}
769
774
776{
779 "BasisType is not a boundary interior form");
782 "BasisType is not a boundary interior form");
785 "BasisType is not a boundary interior form");
786
787 int P = m_base[0]->GetNumModes();
788 int Q = m_base[1]->GetNumModes();
789 int R = m_base[2]->GetNumModes();
790
792}
793
795{
798 "BasisType is not a boundary interior form");
801 "BasisType is not a boundary interior form");
804 "BasisType is not a boundary interior form");
805
806 int P = m_base[0]->GetNumModes() - 1;
807 int Q = m_base[1]->GetNumModes() - 1;
808 int R = m_base[2]->GetNumModes() - 1;
809
810 return (P + 1) * (Q + 1) // 1 rect. face on base
811 + 2 * (R + 1) + P * (1 + 2 * R - P) // 2 tri. (P,R) faces
812 + 2 * (R + 1) + Q * (1 + 2 * R - Q); // 2 tri. (Q,R) faces
813}
814
815int StdPyrExp::v_GetTraceNcoeffs(const int i) const
816{
817 ASSERTL2(i >= 0 && i <= 4, "face id is out of range");
818
819 if (i == 0)
820 {
821 return GetBasisNumModes(0) * GetBasisNumModes(1);
822 }
823 else if (i == 1 || i == 3)
824 {
825 int P = GetBasisNumModes(0) - 1, Q = GetBasisNumModes(2) - 1;
826 return Q + 1 + (P * (1 + 2 * Q - P)) / 2;
827 }
828 else
829 {
830 int P = GetBasisNumModes(1) - 1, Q = GetBasisNumModes(2) - 1;
831 return Q + 1 + (P * (1 + 2 * Q - P)) / 2;
832 }
833}
834
836{
837 ASSERTL2(i >= 0 && i <= 4, "face id is out of range");
838
839 int P = m_base[0]->GetNumModes() - 1;
840 int Q = m_base[1]->GetNumModes() - 1;
841 int R = m_base[2]->GetNumModes() - 1;
842
843 if (i == 0)
844 {
845 return (P - 1) * (Q - 1);
846 }
847 else if (i == 1 || i == 3)
848 {
849 return (P - 1) * (2 * (R - 1) - (P - 1) - 1) / 2;
850 }
851 else
852 {
853 return (Q - 1) * (2 * (R - 1) - (Q - 1) - 1) / 2;
854 }
855}
856
857int StdPyrExp::v_GetTraceNumPoints(const int i) const
858{
859 ASSERTL2(i >= 0 && i <= 4, "face id is out of range");
860
861 if (i == 0)
862 {
863 return m_base[0]->GetNumPoints() * m_base[1]->GetNumPoints();
864 }
865 else if (i == 1 || i == 3)
866 {
867 return m_base[0]->GetNumPoints() * m_base[2]->GetNumPoints();
868 }
869 else
870 {
871 return m_base[1]->GetNumPoints() * m_base[2]->GetNumPoints();
872 }
873}
874
875int StdPyrExp::v_GetEdgeNcoeffs(const int i) const
876{
877 ASSERTL2(i >= 0 && i <= 7, "edge id is out of range");
878
879 if (i == 0 || i == 2)
880 {
881 return GetBasisNumModes(0);
882 }
883 else if (i == 1 || i == 3)
884 {
885 return GetBasisNumModes(1);
886 }
887 else
888 {
889 return GetBasisNumModes(2);
890 }
891}
892
894 const int k,
895 bool UseGLL) const
896{
897 ASSERTL2(i >= 0 && i <= 4, "face id is out of range");
898 ASSERTL2(k >= 0 && k <= 1, "basis key id is out of range");
899
900 switch (i)
901 {
902 case 0:
903 {
904 return EvaluateQuadFaceBasisKey(k, m_base[k]);
905 }
906 case 1:
907 case 3:
908 {
909 return EvaluateTriFaceBasisKey(k, m_base[2 * k], UseGLL);
910 }
911 case 2:
912 case 4:
913 {
914 return EvaluateTriFaceBasisKey(k, m_base[k + 1], UseGLL);
915 }
916 }
917
918 // Should never get here.
920}
921
923 const std::vector<unsigned int> &nummodes, int &modes_offset)
924{
926 nummodes[modes_offset], nummodes[modes_offset + 1],
927 nummodes[modes_offset + 2]);
928
929 modes_offset += 3;
930 return nmodes;
931}
932
933int StdPyrExp::v_GetVertexMap(int vId, bool useCoeffPacking)
934{
938 "Mapping not defined for this type of basis");
939
940 int l = 0;
941
942 if (useCoeffPacking == true) // follow packing of coefficients i.e q,r,p
943 {
944 switch (vId)
945 {
946 case 0:
947 l = GetMode(0, 0, 0);
948 break;
949 case 1:
950 l = GetMode(0, 0, 1);
951 break;
952 case 2:
953 l = GetMode(0, 1, 0);
954 break;
955 case 3:
956 l = GetMode(1, 0, 0);
957 break;
958 case 4:
959 l = GetMode(1, 1, 0);
960 break;
961 default:
962 ASSERTL0(false, "local vertex id must be between 0 and 4");
963 }
964 }
965 else
966 {
967 switch (vId)
968 {
969 case 0:
970 l = GetMode(0, 0, 0);
971 break;
972 case 1:
973 l = GetMode(1, 0, 0);
974 break;
975 case 2:
976 l = GetMode(1, 1, 0);
977 break;
978 case 3:
979 l = GetMode(0, 1, 0);
980 break;
981 case 4:
982 l = GetMode(0, 0, 1);
983 break;
984 default:
985 ASSERTL0(false, "local vertex id must be between 0 and 4");
986 }
987 }
988
989 return l;
990}
991
993{
996 "BasisType is not a boundary interior form");
999 "BasisType is not a boundary interior form");
1002 "BasisType is not a boundary interior form");
1003
1004 int P = m_base[0]->GetNumModes() - 1, p;
1005 int Q = m_base[1]->GetNumModes() - 1, q;
1006 int R = m_base[2]->GetNumModes() - 1, r;
1007
1008 int nIntCoeffs = m_ncoeffs - NumBndryCoeffs();
1009
1010 if (outarray.size() != nIntCoeffs)
1011 {
1012 outarray = Array<OneD, unsigned int>(nIntCoeffs);
1013 }
1014
1015 int idx = 0;
1016
1017 // Loop over all interior modes.
1018 for (p = 2; p <= P; ++p)
1019 {
1020 for (q = 2; q <= Q; ++q)
1021 {
1022 int maxpq = max(p, q);
1023 for (r = 1; r <= R - maxpq; ++r)
1024 {
1025 outarray[idx++] = GetMode(p, q, r);
1026 }
1027 }
1028 }
1029}
1030
1032{
1035 "BasisType is not a boundary interior form");
1038 "BasisType is not a boundary interior form");
1041 "BasisType is not a boundary interior form");
1042
1043 int P = m_base[0]->GetNumModes() - 1, p;
1044 int Q = m_base[1]->GetNumModes() - 1, q;
1045 int R = m_base[2]->GetNumModes() - 1, r;
1046 int idx = 0;
1047
1048 int nBnd = NumBndryCoeffs();
1049
1050 if (maparray.size() != nBnd)
1051 {
1052 maparray = Array<OneD, unsigned int>(nBnd);
1053 }
1054
1055 // Loop over all boundary modes (in ascending order).
1056 for (p = 0; p <= P; ++p)
1057 {
1058 // First two q-r planes are entirely boundary modes.
1059 if (p <= 1)
1060 {
1061 for (q = 0; q <= Q; ++q)
1062 {
1063 int maxpq = max(p, q);
1064 for (r = 0; r <= R - maxpq; ++r)
1065 {
1066 maparray[idx++] = GetMode(p, q, r);
1067 }
1068 }
1069 }
1070 else
1071 {
1072 // Remaining q-r planes contain boundary modes on the two
1073 // front and back sides and edges 0 2.
1074 for (q = 0; q <= Q; ++q)
1075 {
1076 if (q <= 1)
1077 {
1078 for (r = 0; r <= R - p; ++r)
1079 {
1080 maparray[idx++] = GetMode(p, q, r);
1081 }
1082 }
1083 else
1084 {
1085 maparray[idx++] = GetMode(p, q, 0);
1086 }
1087 }
1088 }
1089 }
1090}
1091
1092void StdPyrExp::v_GetTraceCoeffMap(const unsigned int fid,
1093 Array<OneD, unsigned int> &maparray)
1094{
1096 "Method only implemented if BasisType is identical"
1097 "in x and y directions");
1100 "Method only implemented for Modified_A BasisType"
1101 "(x and y direction) and ModifiedPyr_C BasisType (z "
1102 "direction)");
1103
1104 int p, q, r, P = 0, Q = 0, idx = 0;
1105
1106 int order0 = m_base[0]->GetNumModes();
1107 int order1 = m_base[1]->GetNumModes();
1108 int order2 = m_base[2]->GetNumModes();
1109
1110 switch (fid)
1111 {
1112 case 0:
1113 P = order0;
1114 Q = order1;
1115 break;
1116 case 1:
1117 case 3:
1118 P = order0;
1119 Q = order2;
1120 break;
1121 case 2:
1122 case 4:
1123 P = order1;
1124 Q = order2;
1125 break;
1126 default:
1127 ASSERTL0(false, "fid must be between 0 and 4");
1128 }
1129
1130 if (maparray.size() != P * Q)
1131 {
1132 maparray = Array<OneD, unsigned int>(P * Q);
1133 }
1134
1135 // Set up ordering inside each 2D face. Also for triangular faces,
1136 // populate signarray.
1137 switch (fid)
1138 {
1139 case 0: // Bottom quad
1140
1141 for (q = 0; q < Q; ++q)
1142 {
1143 for (p = 0; p < P; ++p)
1144 {
1145 maparray[q * P + p] = GetMode(p, q, 0);
1146 }
1147 }
1148 break;
1149
1150 case 1: // Front triangle
1151 for (p = 0; p < P; ++p)
1152 {
1153 for (r = 0; r < Q - p; ++r)
1154 {
1155 maparray[idx++] = GetMode(p, 0, r);
1156 }
1157 }
1158 break;
1159
1160 case 2: // Right triangle
1161 maparray[idx++] = GetMode(1, 0, 0);
1162 maparray[idx++] = GetMode(0, 0, 1);
1163 for (r = 1; r < Q - 1; ++r)
1164 {
1165 maparray[idx++] = GetMode(1, 0, r);
1166 }
1167
1168 for (q = 1; q < P; ++q)
1169 {
1170 for (r = 0; r < Q - q; ++r)
1171 {
1172 maparray[idx++] = GetMode(1, q, r);
1173 }
1174 }
1175 break;
1176
1177 case 3: // Rear triangle
1178 maparray[idx++] = GetMode(0, 1, 0);
1179 maparray[idx++] = GetMode(0, 0, 1);
1180 for (r = 1; r < Q - 1; ++r)
1181 {
1182 maparray[idx++] = GetMode(0, 1, r);
1183 }
1184
1185 for (p = 1; p < P; ++p)
1186 {
1187 for (r = 0; r < Q - p; ++r)
1188 {
1189 maparray[idx++] = GetMode(p, 1, r);
1190 }
1191 }
1192 break;
1193
1194 case 4: // Left triangle
1195 for (q = 0; q < P; ++q)
1196 {
1197 for (r = 0; r < Q - q; ++r)
1198 {
1199 maparray[idx++] = GetMode(0, q, r);
1200 }
1201 }
1202 break;
1203
1204 default:
1205 ASSERTL0(false, "Face to element map unavailable.");
1206 }
1207}
1208
1209void StdPyrExp::v_GetElmtTraceToTraceMap(const unsigned int fid,
1210 Array<OneD, unsigned int> &maparray,
1211 Array<OneD, int> &signarray,
1212 Orientation faceOrient, int P, int Q)
1213{
1215 "Method only implemented if BasisType is identical"
1216 "in x and y directions");
1219 "Method only implemented for Modified_A BasisType"
1220 "(x and y direction) and ModifiedPyr_C BasisType (z "
1221 "direction)");
1222
1223 int i, j, k, p, r, nFaceCoeffs;
1224 int nummodesA = 0, nummodesB = 0;
1225
1226 int order0 = m_base[0]->GetNumModes();
1227 int order1 = m_base[1]->GetNumModes();
1228 int order2 = m_base[2]->GetNumModes();
1229
1230 switch (fid)
1231 {
1232 case 0:
1233 nummodesA = order0;
1234 nummodesB = order1;
1235 break;
1236 case 1:
1237 case 3:
1238 nummodesA = order0;
1239 nummodesB = order2;
1240 break;
1241 case 2:
1242 case 4:
1243 nummodesA = order1;
1244 nummodesB = order2;
1245 break;
1246 default:
1247 ASSERTL0(false, "fid must be between 0 and 4");
1248 }
1249
1250 if (P == -1)
1251 {
1252 P = nummodesA;
1253 Q = nummodesB;
1254 nFaceCoeffs = GetTraceNcoeffs(fid);
1255 }
1256 else if (fid > 0)
1257 {
1258 nFaceCoeffs = P * (2 * Q - P + 1) / 2;
1259 }
1260 else
1261 {
1262 nFaceCoeffs = P * Q;
1263 }
1264
1265 // Allocate the map array and sign array; set sign array to ones (+)
1266 if (maparray.size() != nFaceCoeffs)
1267 {
1268 maparray = Array<OneD, unsigned int>(nFaceCoeffs);
1269 }
1270
1271 if (signarray.size() != nFaceCoeffs)
1272 {
1273 signarray = Array<OneD, int>(nFaceCoeffs, 1);
1274 }
1275 else
1276 {
1277 fill(signarray.data(), signarray.data() + nFaceCoeffs, 1);
1278 }
1279
1280 // triangular faces
1281 if (fid > 0)
1282 {
1283 // zero signmap and set maparray to zero if elemental
1284 // modes are not as large as face modesl
1285 int idx = 0;
1286 int cnt = 0;
1287 int minPA = min(nummodesA, P);
1288 int minQB = min(nummodesB, Q);
1289
1290 for (j = 0; j < minPA; ++j)
1291 {
1292 // set maparray
1293 for (k = 0; k < minQB - j; ++k, ++cnt)
1294 {
1295 maparray[idx++] = cnt;
1296 }
1297
1298 cnt += nummodesB - minQB;
1299
1300 for (k = nummodesB - j; k < Q - j; ++k)
1301 {
1302 signarray[idx] = 0.0;
1303 maparray[idx++] = maparray[0];
1304 }
1305 }
1306 for (j = nummodesA; j < P; ++j)
1307 {
1308 for (k = 0; k < Q - j; ++k)
1309 {
1310 signarray[idx] = 0.0;
1311 maparray[idx++] = maparray[0];
1312 }
1313 }
1314
1315 // Triangles only have one possible orientation (base
1316 // direction reversed); swap edge modes.
1317 if (faceOrient == eDir1BwdDir1_Dir2FwdDir2)
1318 {
1319 swap(maparray[0], maparray[Q]);
1320 for (i = 1; i < Q - 1; ++i)
1321 {
1322 swap(maparray[i + 1], maparray[Q + i]);
1323 }
1324
1325 idx = 0;
1326 for (p = 0; p < P; ++p)
1327 {
1328 for (r = 0; r < Q - p; ++r, idx++)
1329 {
1330 if (p > 1)
1331 {
1332 signarray[idx] = p % 2 ? -1 : 1;
1333 }
1334 }
1335 }
1336 }
1337 }
1338 else
1339 {
1340
1341 // Set up an array indexing for quads, since the ordering may need
1342 // to be transposed.
1343 Array<OneD, int> arrayindx(nFaceCoeffs, -1);
1344
1345 for (i = 0; i < Q; i++)
1346 {
1347 for (j = 0; j < P; j++)
1348 {
1349 if (faceOrient < eDir1FwdDir2_Dir2FwdDir1)
1350 {
1351 arrayindx[i * P + j] = i * P + j;
1352 }
1353 else
1354 {
1355 arrayindx[i * P + j] = j * Q + i;
1356 }
1357 }
1358 }
1359
1360 // zero signmap and set maparray to zero if elemental
1361 // modes are not as large as face modesl
1362 for (j = 0; j < P; ++j)
1363 {
1364 // set up default maparray
1365 for (k = 0; k < Q; k++)
1366 {
1367 maparray[arrayindx[j + k * P]] = j + k * nummodesA;
1368 }
1369
1370 for (k = nummodesB; k < Q; ++k)
1371 {
1372 signarray[arrayindx[j + k * P]] = 0.0;
1373 maparray[arrayindx[j + k * P]] = maparray[0];
1374 }
1375 }
1376
1377 for (j = nummodesA; j < P; ++j)
1378 {
1379 for (k = 0; k < Q; ++k)
1380 {
1381 signarray[arrayindx[j + k * P]] = 0.0;
1382 maparray[arrayindx[j + k * P]] = maparray[0];
1383 }
1384 }
1385
1386 // The code below is exactly the same as that taken from
1387 // StdHexExp and reverses the 'b' and 'a' directions as
1388 // appropriate (1st and 2nd if statements respectively) in
1389 // quadrilateral faces.
1390 if (faceOrient == eDir1FwdDir1_Dir2BwdDir2 ||
1391 faceOrient == eDir1BwdDir1_Dir2BwdDir2 ||
1392 faceOrient == eDir1BwdDir2_Dir2FwdDir1 ||
1393 faceOrient == eDir1BwdDir2_Dir2BwdDir1)
1394 {
1395 if (faceOrient < eDir1FwdDir2_Dir2FwdDir1)
1396 {
1397 for (i = 3; i < Q; i += 2)
1398 {
1399 for (j = 0; j < P; j++)
1400 {
1401 signarray[arrayindx[i * P + j]] *= -1;
1402 }
1403 }
1404
1405 for (i = 0; i < P; i++)
1406 {
1407 swap(maparray[i], maparray[i + P]);
1408 swap(signarray[i], signarray[i + P]);
1409 }
1410 }
1411 else
1412 {
1413 for (i = 0; i < Q; i++)
1414 {
1415 for (j = 3; j < P; j += 2)
1416 {
1417 signarray[arrayindx[i * P + j]] *= -1;
1418 }
1419 }
1420
1421 for (i = 0; i < Q; i++)
1422 {
1423 swap(maparray[i], maparray[i + Q]);
1424 swap(signarray[i], signarray[i + Q]);
1425 }
1426 }
1427 }
1428
1429 if (faceOrient == eDir1BwdDir1_Dir2FwdDir2 ||
1430 faceOrient == eDir1BwdDir1_Dir2BwdDir2 ||
1431 faceOrient == eDir1FwdDir2_Dir2BwdDir1 ||
1432 faceOrient == eDir1BwdDir2_Dir2BwdDir1)
1433 {
1434 if (faceOrient < eDir1FwdDir2_Dir2FwdDir1)
1435 {
1436 for (i = 0; i < Q; i++)
1437 {
1438 for (j = 3; j < P; j += 2)
1439 {
1440 signarray[arrayindx[i * P + j]] *= -1;
1441 }
1442 }
1443
1444 for (i = 0; i < Q; i++)
1445 {
1446 swap(maparray[i * P], maparray[i * P + 1]);
1447 swap(signarray[i * P], signarray[i * P + 1]);
1448 }
1449 }
1450 else
1451 {
1452 for (i = 3; i < Q; i += 2)
1453 {
1454 for (j = 0; j < P; j++)
1455 {
1456 signarray[arrayindx[i * P + j]] *= -1;
1457 }
1458 }
1459
1460 for (i = 0; i < P; i++)
1461 {
1462 swap(maparray[i * Q], maparray[i * Q + 1]);
1463 swap(signarray[i * Q], signarray[i * Q + 1]);
1464 }
1465 }
1466 }
1467 }
1468}
1469
1471 const int eid, Array<OneD, unsigned int> &maparray,
1472 Array<OneD, int> &signarray, const Orientation edgeOrient)
1473{
1474 int i;
1475 bool signChange;
1476 const int P = m_base[0]->GetNumModes() - 1;
1477 const int Q = m_base[1]->GetNumModes() - 1;
1478 const int R = m_base[2]->GetNumModes() - 1;
1479 const int nEdgeIntCoeffs = v_GetEdgeNcoeffs(eid) - 2;
1480
1481 if (maparray.size() != nEdgeIntCoeffs)
1482 {
1483 maparray = Array<OneD, unsigned int>(nEdgeIntCoeffs);
1484 }
1485
1486 if (signarray.size() != nEdgeIntCoeffs)
1487 {
1488 signarray = Array<OneD, int>(nEdgeIntCoeffs, 1);
1489 }
1490 else
1491 {
1492 fill(signarray.data(), signarray.data() + nEdgeIntCoeffs, 1);
1493 }
1494
1495 // If edge is oriented backwards, change sign of modes which have
1496 // degree 2n+1, n >= 1.
1497 signChange = edgeOrient == eBackwards;
1498
1499 switch (eid)
1500 {
1501 case 0:
1502 for (i = 2; i <= P; ++i)
1503 {
1504 maparray[i - 2] = GetMode(i, 0, 0);
1505 }
1506 break;
1507
1508 case 1:
1509 for (i = 2; i <= Q; ++i)
1510 {
1511 maparray[i - 2] = GetMode(1, i, 0);
1512 }
1513 break;
1514 case 2:
1515 for (i = 2; i <= P; ++i)
1516 {
1517 maparray[i - 2] = GetMode(i, 1, 0);
1518 }
1519 break;
1520
1521 case 3:
1522 for (i = 2; i <= Q; ++i)
1523 {
1524 maparray[i - 2] = GetMode(0, i, 0);
1525 }
1526 break;
1527 case 4:
1528 for (i = 2; i <= R; ++i)
1529 {
1530 maparray[i - 2] = GetMode(0, 0, i);
1531 }
1532 break;
1533
1534 case 5:
1535 for (i = 1; i <= R - 1; ++i)
1536 {
1537 maparray[i - 1] = GetMode(1, 0, i);
1538 }
1539 break;
1540 case 6:
1541 for (i = 1; i <= R - 1; ++i)
1542 {
1543 maparray[i - 1] = GetMode(1, 1, i);
1544 }
1545 break;
1546
1547 case 7:
1548 for (i = 1; i <= R - 1; ++i)
1549 {
1550 maparray[i - 1] = GetMode(0, 1, i);
1551 }
1552 break;
1553 default:
1554 ASSERTL0(false, "Edge not defined.");
1555 break;
1556 }
1557
1558 if (signChange)
1559 {
1560 for (i = 1; i < nEdgeIntCoeffs; i += 2)
1561 {
1562 signarray[i] = -1;
1563 }
1564 }
1565}
1566
1568 const int fid, Array<OneD, unsigned int> &maparray,
1569 Array<OneD, int> &signarray, const Orientation faceOrient)
1570{
1571 const int P = m_base[0]->GetNumModes() - 1;
1572 const int Q = m_base[1]->GetNumModes() - 1;
1573 const int R = m_base[2]->GetNumModes() - 1;
1574 const int nFaceIntCoeffs = v_GetTraceIntNcoeffs(fid);
1575 int p, q, r, idx = 0;
1576 int nummodesA = 0;
1577 int nummodesB = 0;
1578 int i, j;
1579
1580 if (maparray.size() != nFaceIntCoeffs)
1581 {
1582 maparray = Array<OneD, unsigned int>(nFaceIntCoeffs);
1583 }
1584
1585 if (signarray.size() != nFaceIntCoeffs)
1586 {
1587 signarray = Array<OneD, int>(nFaceIntCoeffs, 1);
1588 }
1589 else
1590 {
1591 fill(signarray.data(), signarray.data() + nFaceIntCoeffs, 1);
1592 }
1593
1594 // Set up an array indexing for quad faces, since the ordering may
1595 // need to be transposed depending on orientation.
1596 Array<OneD, int> arrayindx(nFaceIntCoeffs);
1597 if (fid == 0)
1598 {
1599 nummodesA = P - 1;
1600 nummodesB = Q - 1;
1601
1602 for (i = 0; i < nummodesB; i++)
1603 {
1604 for (j = 0; j < nummodesA; j++)
1605 {
1606 if (faceOrient < 9)
1607 {
1608 arrayindx[i * nummodesA + j] = i * nummodesA + j;
1609 }
1610 else
1611 {
1612 arrayindx[i * nummodesA + j] = j * nummodesB + i;
1613 }
1614 }
1615 }
1616 }
1617
1618 switch (fid)
1619 {
1620 case 0: // Bottom quad
1621 for (q = 2; q <= Q; ++q)
1622 {
1623 for (p = 2; p <= P; ++p)
1624 {
1625 maparray[arrayindx[(q - 2) * nummodesA + (p - 2)]] =
1626 GetMode(p, q, 0);
1627 }
1628 }
1629 break;
1630 case 1: // Front triangle
1631 for (p = 2; p <= P; ++p)
1632 {
1633 for (r = 1; r <= R - p; ++r)
1634 {
1635 if ((int)faceOrient == 7)
1636 {
1637 signarray[idx] = p % 2 ? -1 : 1;
1638 }
1639 maparray[idx++] = GetMode(p, 0, r);
1640 }
1641 }
1642 break;
1643 case 2: // Right triangle
1644 for (q = 2; q <= Q; ++q)
1645 {
1646 for (r = 1; r <= R - q; ++r)
1647 {
1648 if ((int)faceOrient == 7)
1649 {
1650 signarray[idx] = q % 2 ? -1 : 1;
1651 }
1652 maparray[idx++] = GetMode(1, q, r);
1653 }
1654 }
1655 break;
1656
1657 case 3: // Rear triangle
1658 for (p = 2; p <= P; ++p)
1659 {
1660 for (r = 1; r <= R - p; ++r)
1661 {
1662 if ((int)faceOrient == 7)
1663 {
1664 signarray[idx] = p % 2 ? -1 : 1;
1665 }
1666 maparray[idx++] = GetMode(p, 1, r);
1667 }
1668 }
1669 break;
1670
1671 case 4: // Left triangle
1672 for (q = 2; q <= Q; ++q)
1673 {
1674 for (r = 1; r <= R - q; ++r)
1675 {
1676 if ((int)faceOrient == 7)
1677 {
1678 signarray[idx] = q % 2 ? -1 : 1;
1679 }
1680 maparray[idx++] = GetMode(0, q, r);
1681 }
1682 }
1683 break;
1684 default:
1685 ASSERTL0(false, "Face interior map not available.");
1686 }
1687
1688 // Triangular faces are processed in the above switch loop; for
1689 // remaining quad faces, set up orientation if necessary.
1690 if (fid > 0)
1691 {
1692 return;
1693 }
1694
1695 if (faceOrient == 6 || faceOrient == 8 || faceOrient == 11 ||
1696 faceOrient == 12)
1697 {
1698 if (faceOrient < 9)
1699 {
1700 for (i = 1; i < nummodesB; i += 2)
1701 {
1702 for (j = 0; j < nummodesA; j++)
1703 {
1704 signarray[arrayindx[i * nummodesA + j]] *= -1;
1705 }
1706 }
1707 }
1708 else
1709 {
1710 for (i = 0; i < nummodesB; i++)
1711 {
1712 for (j = 1; j < nummodesA; j += 2)
1713 {
1714 signarray[arrayindx[i * nummodesA + j]] *= -1;
1715 }
1716 }
1717 }
1718 }
1719
1720 if (faceOrient == 7 || faceOrient == 8 || faceOrient == 10 ||
1721 faceOrient == 12)
1722 {
1723 if (faceOrient < 9)
1724 {
1725 for (i = 0; i < nummodesB; i++)
1726 {
1727 for (j = 1; j < nummodesA; j += 2)
1728 {
1729 signarray[arrayindx[i * nummodesA + j]] *= -1;
1730 }
1731 }
1732 }
1733 else
1734 {
1735 for (i = 1; i < nummodesB; i += 2)
1736 {
1737 for (j = 0; j < nummodesA; j++)
1738 {
1739 signarray[arrayindx[i * nummodesA + j]] *= -1;
1740 }
1741 }
1742 }
1743 }
1744}
1745
1746//---------------------------------------
1747// Wrapper functions
1748//---------------------------------------
1749
1754
1756{
1757 return v_GenMatrix(mkey);
1758}
1759
1760/**
1761 * @brief Compute the mode number in the expansion for a
1762 * particular tensorial combination.
1763 *
1764 * Modes are numbered with the r index travelling fastest,
1765 * followed by q and then p, and each q-r plane is of size
1766 *
1767 * (R+1-p)*(Q+1) - l(l+1)/2 where l = max(0,Q-p)
1768 *
1769 * For example, when P=2, Q=3 and R=4 the indexing inside each
1770 * q-r plane (with r increasing upwards and q to the right)
1771 * is:
1772 *
1773 * p = 0: p = 1: p = 2:
1774 * ----------------------------------
1775 * 4
1776 * 3 8 17 21
1777 * 2 7 11 16 20 24 29 32 35
1778 * 1 6 10 13 15 19 23 26 28 31 34 37
1779 * 0 5 9 12 14 18 22 25 27 30 33 36
1780 *
1781 * Note that in this element, we must have that \f$ P,Q \leq
1782 * R\f$.
1783 */
1784int StdPyrExp::GetMode(const int I, const int J, const int K)
1785{
1786 const int Q = m_base[1]->GetNumModes() - 1;
1787 const int R = m_base[2]->GetNumModes() - 1;
1788
1789 int i, l;
1790 int cnt = 0;
1791
1792 // Traverse to q-r plane number I
1793 for (i = 0; i < I; ++i)
1794 {
1795 // Size of triangle part
1796 l = max(0, Q - i);
1797
1798 // Size of rectangle part
1799 cnt += (R + 1 - i) * (Q + 1) - l * (l + 1) / 2;
1800 }
1801
1802 // Traverse to q column J (Pretend this is a face of width J)
1803 l = max(0, J - 1 - I);
1804 cnt += (R + 1 - I) * J - l * (l + 1) / 2;
1805
1806 // Traverse up stacks to K
1807 cnt += K;
1808
1809 return cnt;
1810}
1811
1813 const StdMatrixKey &mkey)
1814{
1815 // Generate an orthonogal expansion
1816 int qa = m_base[0]->GetNumPoints();
1817 int qb = m_base[1]->GetNumPoints();
1818 int qc = m_base[2]->GetNumPoints();
1819 int nmodes_a = m_base[0]->GetNumModes();
1820 int nmodes_b = m_base[1]->GetNumModes();
1821 int nmodes_c = m_base[2]->GetNumModes();
1822 // Declare orthogonal basis.
1826
1830 StdPyrExp OrthoExp(Ba, Bb, Bc);
1831
1832 Array<OneD, NekDouble> orthocoeffs(OrthoExp.GetNcoeffs());
1833 int i, j, k, cnt = 0;
1834
1835 // project onto modal space.
1836 OrthoExp.FwdTrans(array, orthocoeffs);
1837
1839 {
1840 // Rodrigo's power kernel
1842 NekDouble SvvDiffCoeff =
1845
1846 for (i = 0; i < nmodes_a; ++i)
1847 {
1848 for (j = 0; j < nmodes_b; ++j)
1849 {
1850 int maxij = max(i, j);
1851 NekDouble fac1 = std::max(
1852 pow((1.0 * i) / (nmodes_a - 1), cutoff * nmodes_a),
1853 pow((1.0 * j) / (nmodes_b - 1), cutoff * nmodes_b));
1854
1855 for (k = 0; k < nmodes_c - maxij; ++k)
1856 {
1857 NekDouble fac =
1858 std::max(fac1, pow((1.0 * k) / (nmodes_c - 1),
1859 cutoff * nmodes_c));
1860
1861 orthocoeffs[cnt] *= SvvDiffCoeff * fac;
1862 cnt++;
1863 }
1864 }
1865 }
1866 }
1867 else if (mkey.ConstFactorExists(
1868 eFactorSVVDGKerDiffCoeff)) // Rodrigo/Mansoor's DG Kernel
1869 {
1872
1873 int max_abc = max(nmodes_a - kSVVDGFiltermodesmin,
1874 nmodes_b - kSVVDGFiltermodesmin);
1875 max_abc = max(max_abc, nmodes_c - kSVVDGFiltermodesmin);
1876 // clamp max_abc
1877 max_abc = max(max_abc, 0);
1878 max_abc = min(max_abc, kSVVDGFiltermodesmax - kSVVDGFiltermodesmin);
1879
1880 for (i = 0; i < nmodes_a; ++i)
1881 {
1882 for (j = 0; j < nmodes_b; ++j)
1883 {
1884 int maxij = max(i, j);
1885
1886 for (k = 0; k < nmodes_c - maxij; ++k)
1887 {
1888 int maxijk = max(maxij, k);
1889 maxijk = min(maxijk, kSVVDGFiltermodesmax - 1);
1890
1891 orthocoeffs[cnt] *=
1892 SvvDiffCoeff * kSVVDGFilter[max_abc][maxijk];
1893 cnt++;
1894 }
1895 }
1896 }
1897 }
1898 else
1899 {
1900 // SVV filter paramaters (how much added diffusion relative
1901 // to physical one and fraction of modes from which you
1902 // start applying this added diffusion)
1903 //
1904 NekDouble SvvDiffCoeff =
1906 NekDouble SVVCutOff =
1908
1909 // Defining the cut of mode
1910 int cutoff_a = (int)(SVVCutOff * nmodes_a);
1911 int cutoff_b = (int)(SVVCutOff * nmodes_b);
1912 int cutoff_c = (int)(SVVCutOff * nmodes_c);
1913 // To avoid the fac[j] from blowing up
1914 NekDouble epsilon = 1;
1915
1916 int nmodes = min(min(nmodes_a, nmodes_b), nmodes_c);
1917 NekDouble cutoff = min(min(cutoff_a, cutoff_b), cutoff_c);
1918
1919 for (i = 0; i < nmodes_a; ++i) // P
1920 {
1921 for (j = 0; j < nmodes_b; ++j) // Q
1922 {
1923 int maxij = max(i, j);
1924 for (k = 0; k < nmodes_c - maxij; ++k) // R
1925 {
1926 if (j + k >= cutoff || i + k >= cutoff)
1927 {
1928 orthocoeffs[cnt] *=
1929 (SvvDiffCoeff *
1930 exp(-(i + k - nmodes) * (i + k - nmodes) /
1931 ((NekDouble)((i + k - cutoff + epsilon) *
1932 (i + k - cutoff + epsilon)))) *
1933 exp(-(j - nmodes) * (j - nmodes) /
1934 ((NekDouble)((j - cutoff + epsilon) *
1935 (j - cutoff + epsilon)))));
1936 }
1937 else
1938 {
1939 orthocoeffs[cnt] *= 0.0;
1940 }
1941 cnt++;
1942 }
1943 }
1944 }
1945 }
1946
1947 // backward transform to physical space
1948 OrthoExp.BwdTrans(orthocoeffs, array);
1949}
1950
1952 const Array<OneD, const NekDouble> &inarray,
1953 Array<OneD, NekDouble> &outarray)
1954{
1955 int nquad0 = m_base[0]->GetNumPoints();
1956 int nquad1 = m_base[1]->GetNumPoints();
1957 int nquad2 = m_base[2]->GetNumPoints();
1958 int nqtot = nquad0 * nquad1 * nquad2;
1959 int nmodes0 = m_base[0]->GetNumModes();
1960 int nmodes1 = m_base[1]->GetNumModes();
1961 int nmodes2 = m_base[2]->GetNumModes();
1962 int numMax = nmodes0;
1963
1965 Array<OneD, NekDouble> coeff_tmp1(m_ncoeffs, 0.0);
1966 Array<OneD, NekDouble> phys_tmp(nqtot, 0.0);
1967 Array<OneD, NekDouble> tmp, tmp2, tmp3, tmp4;
1968
1969 const LibUtilities::PointsKey Pkey0 = m_base[0]->GetPointsKey();
1970 const LibUtilities::PointsKey Pkey1 = m_base[1]->GetPointsKey();
1971 const LibUtilities::PointsKey Pkey2 = m_base[2]->GetPointsKey();
1972
1973 LibUtilities::BasisKey bortho0(LibUtilities::eOrtho_A, nmodes0, Pkey0);
1974 LibUtilities::BasisKey bortho1(LibUtilities::eOrtho_A, nmodes1, Pkey1);
1975 LibUtilities::BasisKey bortho2(LibUtilities::eOrthoPyr_C, nmodes2, Pkey2);
1976
1977 int cnt = 0;
1978 int u = 0;
1979 int i = 0;
1981
1983 bortho0, bortho1, bortho2);
1984
1985 BwdTrans(inarray, phys_tmp);
1986 OrthoPyrExp->FwdTrans(phys_tmp, coeff);
1987
1988 // filtering
1989 for (u = 0; u < numMin; ++u)
1990 {
1991 for (i = 0; i < numMin; ++i)
1992 {
1993
1994 int maxui = max(u, i);
1995 Vmath::Vcopy(numMin - maxui, tmp = coeff + cnt, 1,
1996 tmp2 = coeff_tmp1 + cnt, 1);
1997 cnt += nmodes2 - maxui;
1998 }
1999
2000 for (i = numMin; i < nmodes1; ++i)
2001 {
2002 int maxui = max(u, i);
2003 cnt += numMax - maxui;
2004 }
2005 }
2006
2007 OrthoPyrExp->BwdTrans(coeff_tmp1, phys_tmp);
2008 StdPyrExp::FwdTrans(phys_tmp, outarray);
2009}
2010
2011} // namespace Nektar::StdRegions
#define ASSERTL0(condition, msg)
#define ASSERTL1(condition, msg)
Assert Level 1 – Debugging which is used whether in FULLDEBUG or DEBUG compilation mode....
#define ASSERTL2(condition, msg)
Assert Level 2 – Debugging which is used FULLDEBUG compilation mode. This level assert is designed to...
#define BWDTRANS_M(r, i)
#define IPRODUCTWRTBASE_DEF
#define BWDTRANS_DEF
#define IPRODUCTWRTBASE_M(r, i)
#define STDLEV2TEST(r, state)
#define STDLEV2UPDATE(r, state)
Describes the specification for a Basis.
Definition Basis.h:45
BasisType GetBasisType() const
Return type of expansion basis.
Definition Basis.h:131
int GetNumModes() const
Returns the order of the basis.
Definition Basis.h:74
Defines a specification for a set of points.
Definition Points.h:50
static std::shared_ptr< DataType > AllocateSharedPtr(const Args &...args)
Allocate a shared pointer from the memory pool.
NekDouble BaryTensorDeriv(const Array< OneD, NekDouble > &coord, const Array< OneD, const NekDouble > &inarray, std::array< NekDouble, 3 > &firstOrderDerivs)
void PhysTensorDeriv(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &out_d0, Array< OneD, NekDouble > &out_d1, Array< OneD, NekDouble > &out_d2)
Calculate the 3D derivative in the local tensor/collapsed coordinate at the physical points.
void v_PhysDeriv(const int dir, const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray) override
Calculate the derivative of the physical points in a given direction.
The base class for all shapes.
int GetNcoeffs(void) const
This function returns the total number of coefficients used in the expansion.
int GetTotPoints() const
This function returns the total number of quadrature points used in the element.
LibUtilities::BasisType GetBasisType(const int dir) const
This function returns the type of basis used in the dir direction.
void LocCoordToLocCollapsed(const Array< OneD, const NekDouble > &xi, Array< OneD, NekDouble > &eta)
Convert local cartesian coordinate xi into local collapsed coordinates eta.
const Array< OneD, const LibUtilities::BasisSharedPtr > & GetBase() const
This function gets the shared point to basis.
DNekMatSharedPtr CreateGeneralMatrix(const StdMatrixKey &mkey)
this function generates the mass matrix
NekDouble PhysEvaluate(const Array< OneD, const NekDouble > &coords, const Array< OneD, const NekDouble > &physvals)
This function evaluates the expansion at a single (arbitrary) point of the domain.
void BwdTrans(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray)
This function performs the Backward transformation from coefficient space to physical space.
int GetTraceNcoeffs(const int i) const
This function returns the number of expansion coefficients belonging to the i-th trace.
LibUtilities::PointsType GetPointsType(const int dir) const
This function returns the type of quadrature points used in the dir direction.
void FwdTrans(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray)
int GetNumPoints(const int dir) const
This function returns the number of quadrature points in the dir direction.
Array< OneD, const NekDouble > GetStdFac(const StdFacKey &mkey)
int GetBasisNumModes(const int dir) const
This function returns the number of expansion modes in the dir direction.
Array< OneD, LibUtilities::BasisSharedPtr > m_base
std::vector< Array< OneD, const NekDouble > > m_weights
NekDouble GetConstFactor(const ConstFactorType &factor) const
bool ConstFactorExists(const ConstFactorType &factor) const
DNekMatSharedPtr v_GenMatrix(const StdMatrixKey &mkey) override
int v_NumBndryCoeffs() const override
NekDouble v_PhysEvaluateBasis(const Array< OneD, const NekDouble > &coords, int mode) final
void v_ReduceOrderCoeffs(int numMin, const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray) override
int v_NumDGBndryCoeffs() const override
void v_IProductWRTBaseKernel(const Array< OneD, const NekDouble > &base0, const Array< OneD, const NekDouble > &base1, const Array< OneD, const NekDouble > &base2, const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray, const Array< OneD, NekDouble > &jac, const bool Deformed, bool CollDir0=false, bool CollDir1=false, bool CollDir2=false) override
Inner product of inarray over region with respect to the expansion basis (this)->m_base[0] and return...
void v_GetElmtTraceToTraceMap(const unsigned int fid, Array< OneD, unsigned int > &maparray, Array< OneD, int > &signarray, Orientation faceOrient, int P, int Q) override
int v_GetTraceNcoeffs(const int i) const override
void v_LocCollapsedToLocCoord(const Array< OneD, const NekDouble > &eta, Array< OneD, NekDouble > &xi) override
void v_SVVLaplacianFilter(Array< OneD, NekDouble > &array, const StdMatrixKey &mkey) override
int v_GetEdgeNcoeffs(const int i) const override
int v_GetNtraces() const override
void v_IProductWRTDerivBase(const int dir, const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray) override
void v_FillMode(const int mode, Array< OneD, NekDouble > &outarray) override
int v_GetNedges() const override
int v_CalcNumberOfCoefficients(const std::vector< unsigned int > &nummodes, int &modes_offset) override
int GetMode(int I, int J, int K)
Compute the mode number in the expansion for a particular tensorial combination.
int v_GetVertexMap(int localVertexId, bool useCoeffPacking=false) override
int v_GetTraceNumPoints(const int i) const override
void v_BwdTrans(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray) override
Backward transformation is evaluated at the quadrature points.
void v_GetBoundaryMap(Array< OneD, unsigned int > &outarray) override
void v_GetInteriorMap(Array< OneD, unsigned int > &outarray) override
void v_GetEdgeInteriorToElementMap(const int tid, Array< OneD, unsigned int > &maparray, Array< OneD, int > &signarray, const Orientation traceOrient=eDir1FwdDir1_Dir2FwdDir2) override
void v_LocCoordToLocCollapsed(const Array< OneD, const NekDouble > &xi, Array< OneD, NekDouble > &eta) override
DNekMatSharedPtr v_CreateStdMatrix(const StdMatrixKey &mkey) override
int v_GetNverts() const override
void v_GetTraceInteriorToElementMap(const int tid, Array< OneD, unsigned int > &maparray, Array< OneD, int > &signarray, const Orientation traceOrient=eDir1FwdDir1_Dir2FwdDir2) override
void v_StdPhysDeriv(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &out_d0, Array< OneD, NekDouble > &out_d1, Array< OneD, NekDouble > &out_d2) override
Calculate the derivative of the physical points.
Definition StdPyrExp.cpp:98
LibUtilities::ShapeType v_DetShapeType() const override
void v_GetTraceNumModes(const int fid, int &numModes0, int &numModes1, Orientation faceOrient=eDir1FwdDir1_Dir2FwdDir2) override
void v_GetTraceCoeffMap(const unsigned int fid, Array< OneD, unsigned int > &maparray) override
NekDouble v_PhysEvalFirstDeriv(const Array< OneD, NekDouble > &coord, const Array< OneD, const NekDouble > &inarray, std::array< NekDouble, 3 > &firstOrderDerivs) override
void v_GetCoords(Array< OneD, NekDouble > &xi_x, Array< OneD, NekDouble > &xi_y, Array< OneD, NekDouble > &xi_z) override
const LibUtilities::BasisKey v_GetTraceBasisKey(const int i, const int k, bool UseGLL=false) const override
int v_GetTraceIntNcoeffs(const int i) const override
constexpr int getNumberOfBndCoefficients(int Na, int Nb, int Nc)
constexpr int getNumberOfCoefficients(int Na, int Nb, int Nc)
static const BasisKey NullBasisKey(eNoBasisType, 0, NullPointsKey)
Defines a null basis with no type or points.
@ eOrtho_A
Principle Orthogonal Functions .
Definition BasisType.h:42
@ eGLL_Lagrange
Lagrange for SEM basis .
Definition BasisType.h:56
@ eModifiedPyr_C
Principle Modified Functions.
Definition BasisType.h:53
@ eModified_A
Principle Modified Functions .
Definition BasisType.h:48
@ eOrthoPyr_C
Principle Orthogonal Functions .
Definition BasisType.h:51
static const NekDouble kNekZeroTol
LibUtilities::BasisKey EvaluateQuadFaceBasisKey(const int facedir, const LibUtilities::BasisSharedPtr &faceDirBasis)
LibUtilities::BasisKey EvaluateTriFaceBasisKey(const int facedir, const LibUtilities::BasisSharedPtr &faceDirBasis, bool UseGLL)
const int kSVVDGFiltermodesmin
tinysimd::scalarT< double > vec_t
std::shared_ptr< StdPyrExp > StdPyrExpSharedPtr
Definition StdPyrExp.h:178
const int kSVVDGFiltermodesmax
const NekDouble kSVVDGFilter[9][11]
std::shared_ptr< DNekMat > DNekMatSharedPtr
void Vmul(int n, const T *x, const int incx, const T *y, const int incy, T *z, const int incz)
Multiply vector z = x*y.
Definition Vmath.hpp:72
void Vadd(int n, const T *x, const int incx, const T *y, const int incy, T *z, const int incz)
Add vector z = x+y.
Definition Vmath.hpp:180
void Smul(int n, const T alpha, const T *x, const int incx, T *y, const int incy)
Scalar multiply y = alpha*x.
Definition Vmath.hpp:100
void Vcopy(int n, const T *x, const int incx, T *y, const int incy)
Definition Vmath.hpp:825
STL namespace.
scalarT< T > max(scalarT< T > lhs, scalarT< T > rhs)
Definition scalar.hpp:305
scalarT< T > min(scalarT< T > lhs, scalarT< T > rhs)
Definition scalar.hpp:300