Nektar++
Loading...
Searching...
No Matches
StdPrismExp.cpp
Go to the documentation of this file.
1///////////////////////////////////////////////////////////////////////////////
2//
3// File: StdPrismExp.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: Prismatic routines built upon StdExpansion3D
32//
33///////////////////////////////////////////////////////////////////////////////
34
37
38using namespace std;
39
40namespace Nektar::StdRegions
41{
42
44 const LibUtilities::BasisKey &Bb,
45 const LibUtilities::BasisKey &Bc)
46 : StdExpansion(LibUtilities::StdPrismData::getNumberOfCoefficients(
47 Ba.GetNumModes(), Bb.GetNumModes(), Bc.GetNumModes()),
48 3, Ba, Bb, Bc),
49 StdExpansion3D(LibUtilities::StdPrismData::getNumberOfCoefficients(
50 Ba.GetNumModes(), Bb.GetNumModes(), Bc.GetNumModes()),
51 Ba, Bb, Bc)
52{
53 ASSERTL0(Ba.GetNumModes() <= Bc.GetNumModes(),
54 "order in 'a' direction is higher than order in 'c' direction");
55}
56
57//---------------------------------------
58// Differentiation Methods
59//---------------------------------------
60
61/**
62 * \brief Calculate the derivative of the physical points
63 *
64 * The derivative is evaluated at the nodal physical points.
65 * Derivatives with respect to the local Cartesian coordinates.
66 *
67 * \f$\begin{Bmatrix} \frac {\partial} {\partial \xi_1} \\ \frac
68 * {\partial} {\partial \xi_2} \\ \frac {\partial} {\partial \xi_3}
69 * \end{Bmatrix} = \begin{Bmatrix} \frac 2 {(1-\eta_3)} \frac \partial
70 * {\partial \bar \eta_1} \\ \frac {\partial} {\partial \xi_2} \ \
71 * \frac {(1 + \bar \eta_1)} {(1 - \eta_3)} \frac \partial {\partial
72 * \bar \eta_1} + \frac {\partial} {\partial \eta_3} \end{Bmatrix}\f$
73 */
74
76 Array<OneD, NekDouble> &out_dxi1,
77 Array<OneD, NekDouble> &out_dxi2,
78 Array<OneD, NekDouble> &out_dxi3)
79{
80 int Qx = m_base[0]->GetNumPoints();
81 int Qy = m_base[1]->GetNumPoints();
82 int Qz = m_base[2]->GetNumPoints();
83 int Qtot = Qx * Qy * Qz;
84
85 Array<OneD, NekDouble> dEta_bar1(Qtot, 0.0);
86
88 eta_x = m_base[0]->GetZ();
89 eta_z = m_base[2]->GetZ();
90
91 int i, k;
92
93 bool Do_1 = (out_dxi1.size() > 0) ? true : false;
94 bool Do_3 = (out_dxi3.size() > 0) ? true : false;
95
96 // out_dXi2 is just a tensor derivative so is just passed through
97 if (Do_3)
98 {
99 PhysTensorDeriv(u_physical, dEta_bar1, out_dxi2, out_dxi3);
100 }
101 else if (Do_1)
102 {
103 PhysTensorDeriv(u_physical, dEta_bar1, out_dxi2, NullNekDouble1DArray);
104 }
105 else // case if just require 2nd direction
106 {
107 PhysTensorDeriv(u_physical, NullNekDouble1DArray, out_dxi2,
109 }
110
111 if (Do_1)
112 {
113 for (k = 0; k < Qz; ++k)
114 {
115 Vmath::Smul(Qx * Qy, 2.0 / (1.0 - eta_z[k]),
116 &dEta_bar1[0] + k * Qx * Qy, 1,
117 &out_dxi1[0] + k * Qx * Qy, 1);
118 }
119 }
120
121 if (Do_3)
122 {
123 // divide dEta_Bar1 by (1-eta_z)
124 for (k = 0; k < Qz; ++k)
125 {
126 Vmath::Smul(Qx * Qy, 1.0 / (1.0 - eta_z[k]),
127 &dEta_bar1[0] + k * Qx * Qy, 1,
128 &dEta_bar1[0] + k * Qx * Qy, 1);
129 }
130
131 // Multiply dEta_Bar1 by (1+eta_x) and add ot out_dxi3
132 for (i = 0; i < Qx; ++i)
133 {
134 Vmath::Svtvp(Qz * Qy, 1.0 + eta_x[i], &dEta_bar1[0] + i, Qx,
135 &out_dxi3[0] + i, Qx, &out_dxi3[0] + i, Qx);
136 }
137 }
138}
139
140void StdPrismExp::v_PhysDeriv(const int dir,
141 const Array<OneD, const NekDouble> &inarray,
142 Array<OneD, NekDouble> &outarray)
143{
144 switch (dir)
145 {
146 case 0:
147 {
148 v_PhysDeriv(inarray, outarray, NullNekDouble1DArray,
150 break;
151 }
152
153 case 1:
154 {
155 v_PhysDeriv(inarray, NullNekDouble1DArray, outarray,
157 break;
158 }
159
160 case 2:
161 {
163 outarray);
164 break;
165 }
166
167 default:
168 {
169 ASSERTL1(false, "input dir is out of range");
170 }
171 break;
172 }
173}
174
179{
180 StdPrismExp::v_PhysDeriv(inarray, out_d0, out_d1, out_d2);
181}
182
183//---------------------------------------
184// Transforms
185//---------------------------------------
186
187/**
188 * @note 'r' (base[2]) runs fastest in this element.
189 *
190 * Perform backwards transformation at the quadrature points:
191 *
192 * \f$ u^{\delta} (\xi_{1i}, \xi_{2j}, \xi_{3k}) = \sum_{m(pqr)} \hat
193 * u_{pqr} \phi_{pqr} (\xi_{1i}, \xi_{2j}, \xi_{3k})\f$
194 *
195 * In the prism this expansion becomes:
196 *
197 * \f$ u (\xi_{1i}, \xi_{2j}, \xi_{3k}) = \sum_{p=0}^{Q_x} \psi_p^a
198 * (\xi_{1i}) \lbrace { \sum_{q=0}^{Q_y} \psi_{q}^a (\xi_{2j})
199 * \lbrace { \sum_{r=0}^{Q_z} \hat u_{pqr} \psi_{pr}^b (\xi_{3k})
200 * \rbrace} \rbrace}. \f$
201 *
202 * And sumfactorizing step of the form is as:\\
203 *
204 * \f$ f_{pr} (\xi_{3k}) = \sum_{r=0}^{Q_z} \hat u_{pqr} \psi_{pr}^b
205 * (\xi_{3k}),\\
206 *
207 * g_{p} (\xi_{2j}, \xi_{3k}) = \sum_{r=0}^{Q_y} \psi_{p}^a (\xi_{2j})
208 * f_{pr} (\xi_{3k}),\ \
209 *
210 * u(\xi_{1i}, \xi_{2j}, \xi_{3k}) = \sum_{p=0}^{Q_x} \psi_{p}^a
211 * (\xi_{1i}) g_{p} (\xi_{2j}, \xi_{3k}). \f$
212 */
214 Array<OneD, NekDouble> &outarray)
215{
218 "Basis[1] is not a general tensor type");
219
222 "Basis[2] is not a general tensor type");
223
224 if (m_base[0]->Collocation() && m_base[1]->Collocation() &&
225 m_base[2]->Collocation())
226 {
228 m_base[2]->GetNumPoints(),
229 inarray, 1, outarray, 1);
230 }
231 else
232 {
233 StdPrismExp::v_BwdTrans_SumFac(inarray, outarray);
234 }
235}
236
238 Array<OneD, NekDouble> &outarray)
239{
240 int nquad1 = m_base[1]->GetNumPoints();
241 int nquad2 = m_base[2]->GetNumPoints();
242 int order0 = m_base[0]->GetNumModes();
243 int order1 = m_base[1]->GetNumModes();
244
245 Array<OneD, NekDouble> wsp(nquad2 * order1 * order0 +
246 nquad1 * nquad2 * order0);
247
248 BwdTrans_SumFacKernel(m_base[0]->GetBdata(), m_base[1]->GetBdata(),
249 m_base[2]->GetBdata(), inarray, outarray, wsp, true,
250 true, true);
251}
252
254 const Array<OneD, const NekDouble> &base0,
255 const Array<OneD, const NekDouble> &base1,
256 const Array<OneD, const NekDouble> &base2,
257 const Array<OneD, const NekDouble> &inarray,
259 [[maybe_unused]] bool doCheckCollDir0,
260 [[maybe_unused]] bool doCheckCollDir1,
261 [[maybe_unused]] bool doCheckCollDir2)
262{
263 int i, mode;
264 int nquad0 = m_base[0]->GetNumPoints();
265 int nquad1 = m_base[1]->GetNumPoints();
266 int nquad2 = m_base[2]->GetNumPoints();
267 int nummodes0 = m_base[0]->GetNumModes();
268 int nummodes1 = m_base[1]->GetNumModes();
269 int nummodes2 = m_base[2]->GetNumModes();
270 Array<OneD, NekDouble> tmp0 = wsp;
271 Array<OneD, NekDouble> tmp1 = tmp0 + nquad2 * nummodes1 * nummodes0;
272
273 for (i = mode = 0; i < nummodes0; ++i)
274 {
275 Blas::Dgemm('N', 'N', nquad2, nummodes1, nummodes2 - i, 1.0,
276 base2.data() + mode * nquad2, nquad2,
277 inarray.data() + mode * nummodes1, nummodes2 - i, 0.0,
278 tmp0.data() + i * nquad2 * nummodes1, nquad2);
279 mode += nummodes2 - i;
280 }
281
283 {
284 for (i = 0; i < nummodes1; i++)
285 {
286 Blas::Daxpy(nquad2, inarray[1 + i * nummodes2],
287 base2.data() + nquad2, 1,
288 tmp0.data() + nquad2 * (nummodes1 + i), 1);
289 }
290 }
291
292 for (i = 0; i < nummodes0; i++)
293 {
294 Blas::Dgemm('N', 'T', nquad1, nquad2, nummodes1, 1.0, base1.data(),
295 nquad1, tmp0.data() + i * nquad2 * nummodes1, nquad2, 0.0,
296 tmp1.data() + i * nquad2 * nquad1, nquad1);
297 }
298
299 Blas::Dgemm('N', 'T', nquad0, nquad2 * nquad1, nummodes0, 1.0, base0.data(),
300 nquad0, tmp1.data(), nquad2 * nquad1, 0.0, outarray.data(),
301 nquad0);
302}
303
304/**
305 * \brief Forward transform from physical quadrature space stored in
306 * \a inarray and evaluate the expansion coefficients and store in \a
307 * outarray
308 *
309 * Inputs:\n
310 * - \a inarray: array of physical quadrature points to be transformed
311 *
312 * Outputs:\n
313 * - \a outarray: updated array of expansion coefficients.
314 */
316 Array<OneD, NekDouble> &outarray)
317{
318 v_IProductWRTBase(inarray, outarray);
319
320 // Get Mass matrix inverse
321 StdMatrixKey masskey(eInvMass, DetShapeType(), *this);
322 DNekMatSharedPtr matsys = GetStdMatrix(masskey);
323
324 // copy inarray in case inarray == outarray
325 DNekVec in(m_ncoeffs, outarray);
326 DNekVec out(m_ncoeffs, outarray, eWrapper);
327
328 out = (*matsys) * in;
329}
330
331//---------------------------------------
332// Inner product functions
333//---------------------------------------
334
335/**
336 * \brief Calculate the inner product of inarray with respect to the
337 * basis B=base0*base1*base2 and put into outarray:
338 *
339 * \f$ \begin{array}{rcl} I_{pqr} = (\phi_{pqr}, u)_{\delta} & = &
340 * \sum_{i=0}^{nq_0} \sum_{j=0}^{nq_1} \sum_{k=0}^{nq_2} \psi_{p}^{a}
341 * (\bar \eta_{1i}) \psi_{q}^{a} (\xi_{2j}) \psi_{pr}^{b} (\xi_{3k})
342 * w_i w_j w_k u(\bar \eta_{1,i} \xi_{2,j} \xi_{3,k}) J_{i,j,k}\\ & =
343 * & \sum_{i=0}^{nq_0} \psi_p^a(\bar \eta_{1,i}) \sum_{j=0}^{nq_1}
344 * \psi_{q}^a(\xi_{2,j}) \sum_{k=0}^{nq_2} \psi_{pr}^b u(\bar
345 * \eta_{1i},\xi_{2j},\xi_{3k}) J_{i,j,k} \end{array} \f$ \n
346 *
347 * where
348 *
349 * \f$ \phi_{pqr} (\xi_1 , \xi_2 , \xi_3) = \psi_p^a (\bar \eta_1)
350 * \psi_{q}^a (\xi_2) \psi_{pr}^b (\xi_3) \f$ \n
351 *
352 * which can be implemented as \n
353 *
354 * \f$f_{pr} (\xi_{3k}) = \sum_{k=0}^{nq_3} \psi_{pr}^b u(\bar
355 * \eta_{1i},\xi_{2j},\xi_{3k}) J_{i,j,k} = {\bf B_3 U} \f$ \n \f$
356 * g_{q} (\xi_{3k}) = \sum_{j=0}^{nq_1} \psi_{q}^a (\xi_{2j}) f_{pr}
357 * (\xi_{3k}) = {\bf B_2 F} \f$ \n \f$ (\phi_{pqr}, u)_{\delta} =
358 * \sum_{k=0}^{nq_0} \psi_{p}^a (\xi_{3k}) g_{q} (\xi_{3k}) = {\bf B_1
359 * G} \f$
360 */
362 Array<OneD, NekDouble> &outarray)
363{
366 "Basis[1] is not a general tensor type");
367
370 "Basis[2] is not a general tensor type");
371
372 if (m_base[0]->Collocation() && m_base[1]->Collocation())
373 {
374 MultiplyByQuadratureMetric(inarray, outarray);
375 }
376 else
377 {
378 StdPrismExp::v_IProductWRTBase_SumFac(inarray, outarray);
379 }
380}
381
383 const Array<OneD, const NekDouble> &inarray,
384 Array<OneD, NekDouble> &outarray, bool multiplybyweights)
385{
386 int nquad1 = m_base[1]->GetNumPoints();
387 int nquad2 = m_base[2]->GetNumPoints();
388 int order0 = m_base[0]->GetNumModes();
389 int order1 = m_base[1]->GetNumModes();
390
391 Array<OneD, NekDouble> wsp(order0 * nquad2 * (nquad1 + order1));
392
393 if (multiplybyweights)
394 {
395 Array<OneD, NekDouble> tmp(inarray.size());
396
397 MultiplyByQuadratureMetric(inarray, tmp);
399 m_base[0]->GetBdata(), m_base[1]->GetBdata(), m_base[2]->GetBdata(),
400 tmp, outarray, wsp, true, true, true);
401 }
402 else
403 {
405 m_base[0]->GetBdata(), m_base[1]->GetBdata(), m_base[2]->GetBdata(),
406 inarray, outarray, wsp, true, true, true);
407 }
408}
409
411 const Array<OneD, const NekDouble> &base0,
412 const Array<OneD, const NekDouble> &base1,
413 const Array<OneD, const NekDouble> &base2,
414 const Array<OneD, const NekDouble> &inarray,
416 [[maybe_unused]] bool doCheckCollDir0,
417 [[maybe_unused]] bool doCheckCollDir1,
418 [[maybe_unused]] bool doCheckCollDir2)
419{
420 // Interior prism implementation based on Spen's book page
421 // 119. and 608.
422 const int nquad0 = m_base[0]->GetNumPoints();
423 const int nquad1 = m_base[1]->GetNumPoints();
424 const int nquad2 = m_base[2]->GetNumPoints();
425 const int order0 = m_base[0]->GetNumModes();
426 const int order1 = m_base[1]->GetNumModes();
427 const int order2 = m_base[2]->GetNumModes();
428
429 int i, mode;
430
431 ASSERTL1(wsp.size() >= nquad1 * nquad2 * order0 + nquad2 * order0 * order1,
432 "Insufficient workspace size");
433
434 Array<OneD, NekDouble> tmp0 = wsp;
435 Array<OneD, NekDouble> tmp1 = wsp + nquad1 * nquad2 * order0;
436
437 // Inner product with respect to the '0' direction
438 Blas::Dgemm('T', 'N', nquad1 * nquad2, order0, nquad0, 1.0, inarray.data(),
439 nquad0, base0.data(), nquad0, 0.0, tmp0.data(),
440 nquad1 * nquad2);
441
442 // Inner product with respect to the '1' direction
443 Blas::Dgemm('T', 'N', nquad2 * order0, order1, nquad1, 1.0, tmp0.data(),
444 nquad1, base1.data(), nquad1, 0.0, tmp1.data(),
445 nquad2 * order0);
446
447 // Inner product with respect to the '2' direction
448 for (mode = i = 0; i < order0; ++i)
449 {
450 Blas::Dgemm('T', 'N', order2 - i, order1, nquad2, 1.0,
451 base2.data() + mode * nquad2, nquad2,
452 tmp1.data() + i * nquad2, nquad2 * order0, 0.0,
453 outarray.data() + mode * order1, order2 - i);
454 mode += order2 - i;
455 }
456
457 // Fix top singular vertices; performs phi_{0,q,1} +=
458 // phi_1(xi_1)*phi_q(xi_2)*phi_{01}*phi_r(xi_2).
460 {
461 for (i = 0; i < order1; ++i)
462 {
463 mode = GetMode(0, i, 1);
464 outarray[mode] +=
465 Blas::Ddot(nquad2, base2.data() + nquad2, 1,
466 tmp1.data() + i * order0 * nquad2 + nquad2, 1);
467 }
468 }
469}
470
471/**
472 * \brief Inner product of \a inarray over region with respect to the
473 * object's default expansion basis; output in \a outarray.
474 */
476 const int dir, const Array<OneD, const NekDouble> &inarray,
477 Array<OneD, NekDouble> &outarray)
478{
479 v_IProductWRTDerivBase_SumFac(dir, inarray, outarray);
480}
481
483 const int dir, const Array<OneD, const NekDouble> &inarray,
484 Array<OneD, NekDouble> &outarray)
485{
486 ASSERTL0(dir >= 0 && dir <= 2, "input dir is out of range");
487
488 int i;
489 int order0 = m_base[0]->GetNumModes();
490 int order1 = m_base[1]->GetNumModes();
491 int nquad0 = m_base[0]->GetNumPoints();
492 int nquad1 = m_base[1]->GetNumPoints();
493 int nquad2 = m_base[2]->GetNumPoints();
494
495 const Array<OneD, const NekDouble> &z0 = m_base[0]->GetZ();
496 const Array<OneD, const NekDouble> &z2 = m_base[2]->GetZ();
497 Array<OneD, NekDouble> gfac0(nquad0);
498 Array<OneD, NekDouble> gfac2(nquad2);
499 Array<OneD, NekDouble> tmp0(nquad0 * nquad1 * nquad2);
500 Array<OneD, NekDouble> wsp(order0 * nquad2 * (nquad1 + order1));
501
502 // set up geometric factor: (1+z0)/2
503 for (i = 0; i < nquad0; ++i)
504 {
505 gfac0[i] = 0.5 * (1 + z0[i]);
506 }
507
508 // Set up geometric factor: 2/(1-z2)
509 for (i = 0; i < nquad2; ++i)
510 {
511 gfac2[i] = 2.0 / (1 - z2[i]);
512 }
513
514 // Scale first derivative term by gfac2.
515 if (dir != 1)
516 {
517 for (i = 0; i < nquad2; ++i)
518 {
519 Vmath::Smul(nquad0 * nquad1, gfac2[i],
520 &inarray[0] + i * nquad0 * nquad1, 1,
521 &tmp0[0] + i * nquad0 * nquad1, 1);
522 }
523 MultiplyByQuadratureMetric(tmp0, tmp0);
524 }
525
526 switch (dir)
527 {
528 case 0:
529 {
531 m_base[0]->GetDbdata(), m_base[1]->GetBdata(),
532 m_base[2]->GetBdata(), tmp0, outarray, wsp, true, true, true);
533 break;
534 }
535 case 1:
536 {
537 MultiplyByQuadratureMetric(inarray, tmp0);
539 m_base[0]->GetBdata(), m_base[1]->GetDbdata(),
540 m_base[2]->GetBdata(), tmp0, outarray, wsp, true, true, true);
541 break;
542 }
543
544 case 2:
545 {
547
548 // Scale eta_1 derivative with gfac0.
549 for (i = 0; i < nquad1 * nquad2; ++i)
550 {
551 Vmath::Vmul(nquad0, &gfac0[0], 1, &tmp0[0] + i * nquad0, 1,
552 &tmp0[0] + i * nquad0, 1);
553 }
554
556 m_base[0]->GetDbdata(), m_base[1]->GetBdata(),
557 m_base[2]->GetBdata(), tmp0, tmp1, wsp, true, true, true);
558
559 MultiplyByQuadratureMetric(inarray, tmp0);
561 m_base[0]->GetBdata(), m_base[1]->GetBdata(),
562 m_base[2]->GetDbdata(), tmp0, outarray, wsp, true, true, true);
563
564 Vmath::Vadd(m_ncoeffs, &tmp1[0], 1, &outarray[0], 1, &outarray[0],
565 1);
566 break;
567 }
568 }
569}
570
571//---------------------------------------
572// Evaluation functions
573//---------------------------------------
574
577{
578 NekDouble d2 = 1.0 - xi[2];
579 if (fabs(d2) < NekConstants::kNekZeroTol)
580 {
581 if (d2 >= 0.)
582 {
584 }
585 else
586 {
588 }
589 }
590 eta[2] = xi[2]; // eta_z = xi_z
591 eta[1] = xi[1]; // eta_y = xi_y
592 eta[0] = 2.0 * (1.0 + xi[0]) / d2 - 1.0;
593}
594
597{
598 xi[0] = (1.0 + eta[0]) * (1.0 - eta[2]) * 0.5 - 1.0;
599 xi[1] = eta[1];
600 xi[2] = eta[2];
601}
602
606{
607 Array<OneD, const NekDouble> etaBar_x = m_base[0]->GetZ();
608 Array<OneD, const NekDouble> eta_y = m_base[1]->GetZ();
609 Array<OneD, const NekDouble> eta_z = m_base[2]->GetZ();
610 int Qx = GetNumPoints(0);
611 int Qy = GetNumPoints(1);
612 int Qz = GetNumPoints(2);
613
614 // Convert collapsed coordinates into cartesian coordinates: eta --> xi
615 for (int k = 0; k < Qz; ++k)
616 {
617 for (int j = 0; j < Qy; ++j)
618 {
619 for (int i = 0; i < Qx; ++i)
620 {
621 int s = i + Qx * (j + Qy * k);
622 xi_x[s] = (1.0 - eta_z[k]) * (1.0 + etaBar_x[i]) / 2.0 - 1.0;
623 xi_y[s] = eta_y[j];
624 xi_z[s] = eta_z[k];
625 }
626 }
627 }
628}
629
631 const Array<OneD, const NekDouble> &coords, int mode)
632{
634 LocCoordToLocCollapsed(coords, coll);
635
636 const int nm1 = m_base[1]->GetNumModes();
637 const int nm2 = m_base[2]->GetNumModes();
638 const int b = 2 * nm2 + 1;
639
640 const int mode0 = floor(0.5 * (b - sqrt(b * b - 8.0 * mode / nm1)));
641 const int tmp =
642 mode - nm1 * (mode0 * (nm2 - 1) + 1 - (mode0 - 2) * (mode0 - 1) / 2);
643 const int mode1 = tmp / (nm2 - mode0);
644 const int mode2 = tmp % (nm2 - mode0);
645
646 if (mode0 == 0 && mode2 == 1 &&
648 {
649 // handle collapsed top edge to remove mode0 terms
650 return StdExpansion::BaryEvaluateBasis<1>(coll[1], mode1) *
651 StdExpansion::BaryEvaluateBasis<2>(coll[2], mode2);
652 }
653 else
654 {
655 return StdExpansion::BaryEvaluateBasis<0>(coll[0], mode0) *
656 StdExpansion::BaryEvaluateBasis<1>(coll[1], mode1) *
657 StdExpansion::BaryEvaluateBasis<2>(coll[2], mode2);
658 }
659}
660
662 const Array<OneD, NekDouble> &coord,
663 const Array<OneD, const NekDouble> &inarray,
664 std::array<NekDouble, 3> &firstOrderDerivs)
665{
666 // Collapse coordinates
667 Array<OneD, NekDouble> coll(3, 0.0);
668 LocCoordToLocCollapsed(coord, coll);
669
670 // If near singularity do the old interpolation matrix method
671 // @TODO: Dave thinks there might be a way in the Barycentric to
672 // mathematically remove this singularity?
673 if ((1 - coll[2]) < 1e-5)
674 {
675 int totPoints = GetTotPoints();
676 Array<OneD, NekDouble> EphysDeriv0(totPoints), EphysDeriv1(totPoints),
677 EphysDeriv2(totPoints);
678 PhysDeriv(inarray, EphysDeriv0, EphysDeriv1, EphysDeriv2);
679
681 I[0] = GetBase()[0]->GetI(coll);
682 I[1] = GetBase()[1]->GetI(coll + 1);
683 I[2] = GetBase()[2]->GetI(coll + 2);
684
685 firstOrderDerivs[0] = PhysEvaluate(I, EphysDeriv0);
686 firstOrderDerivs[1] = PhysEvaluate(I, EphysDeriv1);
687 firstOrderDerivs[2] = PhysEvaluate(I, EphysDeriv2);
688 return PhysEvaluate(I, inarray);
689 }
690
691 NekDouble val = BaryTensorDeriv(coll, inarray, firstOrderDerivs);
692
693 NekDouble dEta_bar1 = firstOrderDerivs[0];
694
695 NekDouble fac = 2.0 / (1.0 - coll[2]);
696 firstOrderDerivs[0] = fac * dEta_bar1;
697
698 // divide dEta_Bar1 by (1-eta_z)
699 fac = 1.0 / (1.0 - coll[2]);
700 dEta_bar1 = fac * dEta_bar1;
701
702 // Multiply dEta_Bar1 by (1+eta_x) and add ot out_dxi3
703 fac = 1.0 + coll[0];
704 firstOrderDerivs[2] += fac * dEta_bar1;
705
706 return val;
707}
708
709void StdPrismExp::v_FillMode(const int mode, Array<OneD, NekDouble> &outarray)
710{
712 tmp[mode] = 1.0;
713 StdPrismExp::v_BwdTrans(tmp, outarray);
714}
715
716void StdPrismExp::v_GetTraceNumModes(const int fid, int &numModes0,
717 int &numModes1, Orientation faceOrient)
718{
719 int nummodes[3] = {m_base[0]->GetNumModes(), m_base[1]->GetNumModes(),
720 m_base[2]->GetNumModes()};
721 switch (fid)
722 {
723 // base quad
724 case 0:
725 {
726 numModes0 = nummodes[0];
727 numModes1 = nummodes[1];
728 }
729 break;
730 // front and back quad
731 case 2:
732 case 4:
733 {
734 numModes0 = nummodes[1];
735 numModes1 = nummodes[2];
736 }
737 break;
738 // triangles
739 case 1:
740 case 3:
741 {
742 numModes0 = nummodes[0];
743 numModes1 = nummodes[2];
744 }
745 break;
746 }
747
748 if (faceOrient >= eDir1FwdDir2_Dir2FwdDir1)
749 {
750 std::swap(numModes0, numModes1);
751 }
752}
753
754int StdPrismExp::v_GetEdgeNcoeffs(const int i) const
755{
756 ASSERTL2(i >= 0 && i <= 8, "edge id is out of range");
757
758 if (i == 0 || i == 2)
759 {
760 return GetBasisNumModes(0);
761 }
762 else if (i == 1 || i == 3 || i == 8)
763 {
764 return GetBasisNumModes(1);
765 }
766 else
767 {
768 return GetBasisNumModes(2);
769 }
770}
771
772//---------------------------------------
773// Helper functions
774//---------------------------------------
775
777{
778 return 6;
779}
780
782{
783 return 9;
784}
785
787{
788 return 5;
789}
790
791/**
792 * \brief Return Shape of region, using ShapeType enum list;
793 * i.e. prism.
794 */
799
801{
804 "BasisType is not a boundary interior form");
807 "BasisType is not a boundary interior form");
810 "BasisType is not a boundary interior form");
811
812 int P = m_base[0]->GetNumModes();
813 int Q = m_base[1]->GetNumModes();
814 int R = m_base[2]->GetNumModes();
815
817}
818
820{
823 "BasisType is not a boundary interior form");
826 "BasisType is not a boundary interior form");
829 "BasisType is not a boundary interior form");
830
831 int P = m_base[0]->GetNumModes() - 1;
832 int Q = m_base[1]->GetNumModes() - 1;
833 int R = m_base[2]->GetNumModes() - 1;
834
835 return (P + 1) * (Q + 1) // 1 rect. face on base
836 + 2 * (Q + 1) * (R + 1) // other 2 rect. faces
837 + 2 * (R + 1) + P * (1 + 2 * R - P); // 2 tri. faces
838}
839
840int StdPrismExp::v_GetTraceNcoeffs(const int i) const
841{
842 ASSERTL2(i >= 0 && i <= 4, "face id is out of range");
843 if (i == 0)
844 {
845 return GetBasisNumModes(0) * GetBasisNumModes(1);
846 }
847 else if (i == 1 || i == 3)
848 {
849 int P = GetBasisNumModes(0) - 1, Q = GetBasisNumModes(2) - 1;
850 return Q + 1 + (P * (1 + 2 * Q - P)) / 2;
851 }
852 else
853 {
854 return GetBasisNumModes(1) * GetBasisNumModes(2);
855 }
856}
857
859{
860 ASSERTL2(i >= 0 && i <= 4, "face id is out of range");
861
862 int Pi = GetBasisNumModes(0) - 2;
863 int Qi = GetBasisNumModes(1) - 2;
864 int Ri = GetBasisNumModes(2) - 2;
865
866 if (i == 0)
867 {
868 return Pi * Qi;
869 }
870 else if (i == 1 || i == 3)
871 {
872 return Pi * (2 * Ri - Pi - 1) / 2;
873 }
874 else
875 {
876 return Qi * Ri;
877 }
878}
879
881{
882 ASSERTL2(i >= 0 && i <= 4, "face id is out of range");
883
884 if (i == 0)
885 {
886 return m_base[0]->GetNumPoints() * m_base[1]->GetNumPoints();
887 }
888 else if (i == 1 || i == 3)
889 {
890 return m_base[0]->GetNumPoints() * m_base[2]->GetNumPoints();
891 }
892 else
893 {
894 return m_base[1]->GetNumPoints() * m_base[2]->GetNumPoints();
895 }
896}
897
899 const int j) const
900{
901 ASSERTL2(i >= 0 && i <= 4, "face id is out of range");
902 ASSERTL2(j == 0 || j == 1, "face direction is out of range");
903
904 if (i == 0)
905 {
906 return m_base[j]->GetPointsKey();
907 }
908 else if (i == 1 || i == 3)
909 {
910 return m_base[2 * j]->GetPointsKey();
911 }
912 else
913 {
914 return m_base[j + 1]->GetPointsKey();
915 }
916}
917
919 const int k,
920 bool UseGLL) const
921{
922 ASSERTL2(i >= 0 && i <= 4, "face id is out of range");
923 ASSERTL2(k >= 0 && k <= 1, "basis key id is out of range");
924
925 switch (i)
926 {
927 case 0:
928 {
929 return EvaluateQuadFaceBasisKey(k, m_base[k]);
930 }
931 case 2:
932 case 4:
933 {
934 return EvaluateQuadFaceBasisKey(k, m_base[k + 1]);
935 }
936 case 1:
937 case 3:
938 {
939 return EvaluateTriFaceBasisKey(k, m_base[2 * k], UseGLL);
940 }
941 break;
942 }
943
944 // Should never get here.
946}
947
949 const std::vector<unsigned int> &nummodes, int &modes_offset)
950{
952 nummodes[modes_offset], nummodes[modes_offset + 1],
953 nummodes[modes_offset + 2]);
954
955 modes_offset += 3;
956 return nmodes;
957}
958
965
966//---------------------------------------
967// Mappings
968//---------------------------------------
969
970int StdPrismExp::v_GetVertexMap(const int vId, bool useCoeffPacking)
971{
975 "Mapping not defined for this type of basis");
976
977 int l = 0;
978
979 if (useCoeffPacking == true) // follow packing of coefficients i.e q,r,p
980 {
981 switch (vId)
982 {
983 case 0:
984 l = GetMode(0, 0, 0);
985 break;
986 case 1:
987 l = GetMode(0, 0, 1);
988 break;
989 case 2:
990 l = GetMode(0, 1, 0);
991 break;
992 case 3:
993 l = GetMode(0, 1, 1);
994 break;
995 case 4:
996 l = GetMode(1, 0, 0);
997 break;
998 case 5:
999 l = GetMode(1, 1, 0);
1000 break;
1001 default:
1002 ASSERTL0(false, "local vertex id must be between 0 and 5");
1003 }
1004 }
1005 else
1006 {
1007 switch (vId)
1008 {
1009 case 0:
1010 l = GetMode(0, 0, 0);
1011 break;
1012 case 1:
1013 l = GetMode(1, 0, 0);
1014 break;
1015 case 2:
1016 l = GetMode(1, 1, 0);
1017 break;
1018 case 3:
1019 l = GetMode(0, 1, 0);
1020 break;
1021 case 4:
1022 l = GetMode(0, 0, 1);
1023 break;
1024 case 5:
1025 l = GetMode(0, 1, 1);
1026 break;
1027 default:
1028 ASSERTL0(false, "local vertex id must be between 0 and 5");
1029 }
1030 }
1031
1032 return l;
1033}
1034
1036{
1039 "BasisType is not a boundary interior form");
1042 "BasisType is not a boundary interior form");
1045 "BasisType is not a boundary interior form");
1046
1047 int P = m_base[0]->GetNumModes() - 1, p;
1048 int Q = m_base[1]->GetNumModes() - 1, q;
1049 int R = m_base[2]->GetNumModes() - 1, r;
1050
1051 int nIntCoeffs = m_ncoeffs - NumBndryCoeffs();
1052
1053 if (outarray.size() != nIntCoeffs)
1054 {
1055 outarray = Array<OneD, unsigned int>(nIntCoeffs);
1056 }
1057
1058 int idx = 0;
1059
1060 // Loop over all interior modes.
1061 for (p = 2; p <= P; ++p)
1062 {
1063 for (q = 2; q <= Q; ++q)
1064 {
1065 for (r = 1; r <= R - p; ++r)
1066 {
1067 outarray[idx++] = GetMode(p, q, r);
1068 }
1069 }
1070 }
1071}
1072
1074{
1077 "BasisType is not a boundary interior form");
1080 "BasisType is not a boundary interior form");
1083 "BasisType is not a boundary interior form");
1084
1085 int P = m_base[0]->GetNumModes() - 1, p;
1086 int Q = m_base[1]->GetNumModes() - 1, q;
1087 int R = m_base[2]->GetNumModes() - 1, r;
1088 int idx = 0;
1089
1090 int nBnd = NumBndryCoeffs();
1091
1092 if (maparray.size() != nBnd)
1093 {
1094 maparray = Array<OneD, unsigned int>(nBnd);
1095 }
1096
1097 // Loop over all boundary modes (in ascending order).
1098 for (p = 0; p <= P; ++p)
1099 {
1100 // First two q-r planes are entirely boundary modes.
1101 if (p <= 1)
1102 {
1103 for (q = 0; q <= Q; ++q)
1104 {
1105 for (r = 0; r <= R - p; ++r)
1106 {
1107 maparray[idx++] = GetMode(p, q, r);
1108 }
1109 }
1110 }
1111 else
1112 {
1113 // Remaining q-r planes contain boundary modes on the two
1114 // left-hand sides and bottom edge.
1115 for (q = 0; q <= Q; ++q)
1116 {
1117 if (q <= 1)
1118 {
1119 for (r = 0; r <= R - p; ++r)
1120 {
1121 maparray[idx++] = GetMode(p, q, r);
1122 }
1123 }
1124 else
1125 {
1126 maparray[idx++] = GetMode(p, q, 0);
1127 }
1128 }
1129 }
1130 }
1131}
1132
1133void StdPrismExp::v_GetTraceCoeffMap(const unsigned int fid,
1134 Array<OneD, unsigned int> &maparray)
1135{
1137 "Method only implemented if BasisType is identical"
1138 "in x and y directions");
1141 "Method only implemented for Modified_A BasisType"
1142 "(x and y direction) and Modified_B BasisType (z "
1143 "direction)");
1144 int p, q, r, idx = 0;
1145 int P = 0, Q = 0;
1146
1147 switch (fid)
1148 {
1149 case 0:
1150 P = m_base[0]->GetNumModes();
1151 Q = m_base[1]->GetNumModes();
1152 break;
1153 case 1:
1154 case 3:
1155 P = m_base[0]->GetNumModes();
1156 Q = m_base[2]->GetNumModes();
1157 break;
1158 case 2:
1159 case 4:
1160 P = m_base[1]->GetNumModes();
1161 Q = m_base[2]->GetNumModes();
1162 break;
1163 default:
1164 ASSERTL0(false, "fid must be between 0 and 4");
1165 }
1166
1167 if (maparray.size() != P * Q)
1168 {
1169 maparray = Array<OneD, unsigned int>(P * Q);
1170 }
1171
1172 // Set up ordering inside each 2D face. Also for triangular faces,
1173 // populate signarray.
1174 switch (fid)
1175 {
1176 case 0: // Bottom quad
1177 for (q = 0; q < Q; ++q)
1178 {
1179 for (p = 0; p < P; ++p)
1180 {
1181 maparray[q * P + p] = GetMode(p, q, 0);
1182 }
1183 }
1184 break;
1185 case 1: // Left triangle
1186 for (p = 0; p < P; ++p)
1187 {
1188 for (r = 0; r < Q - p; ++r)
1189 {
1190 maparray[idx++] = GetMode(p, 0, r);
1191 }
1192 }
1193 break;
1194 case 2: // Slanted quad
1195 for (q = 0; q < P; ++q)
1196 {
1197 maparray[q] = GetMode(1, q, 0);
1198 }
1199 for (q = 0; q < P; ++q)
1200 {
1201 maparray[P + q] = GetMode(0, q, 1);
1202 }
1203 for (r = 1; r < Q - 1; ++r)
1204 {
1205 for (q = 0; q < P; ++q)
1206 {
1207 maparray[(r + 1) * P + q] = GetMode(1, q, r);
1208 }
1209 }
1210 break;
1211 case 3: // Right triangle
1212 for (p = 0; p < P; ++p)
1213 {
1214 for (r = 0; r < Q - p; ++r)
1215 {
1216 maparray[idx++] = GetMode(p, 1, r);
1217 }
1218 }
1219 break;
1220 case 4: // Rear quad
1221 for (r = 0; r < Q; ++r)
1222 {
1223 for (q = 0; q < P; ++q)
1224 {
1225 maparray[r * P + q] = GetMode(0, q, r);
1226 }
1227 }
1228 break;
1229 default:
1230 ASSERTL0(false, "Face to element map unavailable.");
1231 }
1232}
1233
1234void StdPrismExp::v_GetElmtTraceToTraceMap(const unsigned int fid,
1235 Array<OneD, unsigned int> &maparray,
1236 Array<OneD, int> &signarray,
1237 Orientation faceOrient, int P, int Q)
1238{
1240 "Method only implemented if BasisType is identical"
1241 "in x and y directions");
1244 "Method only implemented for Modified_A BasisType"
1245 "(x and y direction) and Modified_B BasisType (z "
1246 "direction)");
1247
1248 int i, j, k, p, r, nFaceCoeffs, idx = 0;
1249 int nummodesA = 0, nummodesB = 0;
1250
1251 switch (fid)
1252 {
1253 case 0:
1254 nummodesA = m_base[0]->GetNumModes();
1255 nummodesB = m_base[1]->GetNumModes();
1256 break;
1257 case 1:
1258 case 3:
1259 nummodesA = m_base[0]->GetNumModes();
1260 nummodesB = m_base[2]->GetNumModes();
1261 break;
1262 case 2:
1263 case 4:
1264 nummodesA = m_base[1]->GetNumModes();
1265 nummodesB = m_base[2]->GetNumModes();
1266 break;
1267 default:
1268 ASSERTL0(false, "fid must be between 0 and 4");
1269 }
1270
1271 if (P == -1)
1272 {
1273 P = nummodesA;
1274 Q = nummodesB;
1275 nFaceCoeffs = GetTraceNcoeffs(fid);
1276 }
1277 else if (fid == 1 || fid == 3)
1278 {
1279 nFaceCoeffs = P * (2 * Q - P + 1) / 2;
1280 }
1281 else
1282 {
1283 nFaceCoeffs = P * Q;
1284 }
1285
1286 // Allocate the map array and sign array; set sign array to ones (+)
1287 if (maparray.size() != nFaceCoeffs)
1288 {
1289 maparray = Array<OneD, unsigned int>(nFaceCoeffs);
1290 }
1291
1292 if (signarray.size() != nFaceCoeffs)
1293 {
1294 signarray = Array<OneD, int>(nFaceCoeffs, 1);
1295 }
1296 else
1297 {
1298 fill(signarray.data(), signarray.data() + nFaceCoeffs, 1);
1299 }
1300
1301 int minPA = min(nummodesA, P);
1302 int minQB = min(nummodesB, Q);
1303 // triangular faces
1304 if (fid == 1 || fid == 3)
1305 {
1306 // zero signmap and set maparray to zero if elemental
1307 // modes are not as large as face modesl
1308 idx = 0;
1309 int cnt = 0;
1310
1311 for (j = 0; j < minPA; ++j)
1312 {
1313 // set maparray
1314 for (k = 0; k < minQB - j; ++k, ++cnt)
1315 {
1316 maparray[idx++] = cnt;
1317 }
1318
1319 cnt += nummodesB - minQB;
1320
1321 // idx += nummodesB-j;
1322 for (k = nummodesB - j; k < Q - j; ++k)
1323 {
1324 signarray[idx] = 0.0;
1325 maparray[idx++] = maparray[0];
1326 }
1327 }
1328#if 0 // no required?
1329 for (j = minPA; j < nummodesA; ++j)
1330 {
1331 // set maparray
1332 for (k = 0; k < minQB-j; ++k, ++cnt)
1333 {
1334 maparray[idx++] = cnt;
1335 }
1336
1337 cnt += nummodesB-minQB;
1338
1339 //idx += nummodesB-j;
1340 for (k = nummodesB-j; k < Q-j; ++k)
1341 {
1342 signarray[idx] = 0.0;
1343 maparray[idx++] = maparray[0];
1344 }
1345 }
1346#endif
1347 for (j = nummodesA; j < P; ++j)
1348 {
1349 for (k = 0; k < Q - j; ++k)
1350 {
1351 signarray[idx] = 0.0;
1352 maparray[idx++] = maparray[0];
1353 }
1354 }
1355
1356 // Triangles only have one possible orientation (base
1357 // direction reversed); swap edge modes.
1358 if (faceOrient == eDir1BwdDir1_Dir2FwdDir2)
1359 {
1360 idx = 0;
1361 for (p = 0; p < P; ++p)
1362 {
1363 for (r = 0; r < Q - p; ++r, idx++)
1364 {
1365 if (p > 1)
1366 {
1367 signarray[idx] = p % 2 ? -1 : 1;
1368 }
1369 }
1370 }
1371
1372 swap(maparray[0], maparray[Q]);
1373 for (i = 1; i < Q - 1; ++i)
1374 {
1375 swap(maparray[i + 1], maparray[Q + i]);
1376 }
1377 }
1378 }
1379 else
1380 {
1381 // Set up an array indexing for quads, since the
1382 // ordering may need to be transposed.
1383 Array<OneD, int> arrayindx(nFaceCoeffs, -1);
1384
1385 for (i = 0; i < Q; i++)
1386 {
1387 for (j = 0; j < P; j++)
1388 {
1389 if (faceOrient < eDir1FwdDir2_Dir2FwdDir1)
1390 {
1391 arrayindx[i * P + j] = i * P + j;
1392 }
1393 else
1394 {
1395 arrayindx[i * P + j] = j * Q + i;
1396 }
1397 }
1398 }
1399
1400 // zero signmap and set maparray to zero if elemental
1401 // modes are not as large as face modesl
1402 for (j = 0; j < P; ++j)
1403 {
1404 // set up default maparray
1405 for (k = 0; k < Q; k++)
1406 {
1407 maparray[arrayindx[j + k * P]] = j + k * nummodesA;
1408 }
1409
1410 for (k = nummodesB; k < Q; ++k)
1411 {
1412 signarray[arrayindx[j + k * P]] = 0.0;
1413 maparray[arrayindx[j + k * P]] = maparray[0];
1414 }
1415 }
1416
1417 for (j = nummodesA; j < P; ++j)
1418 {
1419 for (k = 0; k < Q; ++k)
1420 {
1421 signarray[arrayindx[j + k * P]] = 0.0;
1422 maparray[arrayindx[j + k * P]] = maparray[0];
1423 }
1424 }
1425
1426 // The code below is exactly the same as that taken from
1427 // StdHexExp and reverses the 'b' and 'a' directions as
1428 // appropriate (1st and 2nd if statements respectively) in
1429 // quadrilateral faces.
1430 if (faceOrient == eDir1FwdDir1_Dir2BwdDir2 ||
1431 faceOrient == eDir1BwdDir1_Dir2BwdDir2 ||
1432 faceOrient == eDir1BwdDir2_Dir2FwdDir1 ||
1433 faceOrient == eDir1BwdDir2_Dir2BwdDir1)
1434 {
1435 if (faceOrient < eDir1FwdDir2_Dir2FwdDir1)
1436 {
1437 for (i = 3; i < Q; i += 2)
1438 {
1439 for (j = 0; j < P; j++)
1440 {
1441 signarray[arrayindx[i * P + j]] *= -1;
1442 }
1443 }
1444
1445 for (i = 0; i < P; i++)
1446 {
1447 swap(maparray[i], maparray[i + P]);
1448 swap(signarray[i], signarray[i + P]);
1449 }
1450 }
1451 else
1452 {
1453 for (i = 0; i < Q; i++)
1454 {
1455 for (j = 3; j < P; j += 2)
1456 {
1457 signarray[arrayindx[i * P + j]] *= -1;
1458 }
1459 }
1460
1461 for (i = 0; i < Q; i++)
1462 {
1463 swap(maparray[i], maparray[i + Q]);
1464 swap(signarray[i], signarray[i + Q]);
1465 }
1466 }
1467 }
1468
1469 if (faceOrient == eDir1BwdDir1_Dir2FwdDir2 ||
1470 faceOrient == eDir1BwdDir1_Dir2BwdDir2 ||
1471 faceOrient == eDir1FwdDir2_Dir2BwdDir1 ||
1472 faceOrient == eDir1BwdDir2_Dir2BwdDir1)
1473 {
1474 if (faceOrient < eDir1FwdDir2_Dir2FwdDir1)
1475 {
1476 for (i = 0; i < Q; i++)
1477 {
1478 for (j = 3; j < P; j += 2)
1479 {
1480 signarray[arrayindx[i * P + j]] *= -1;
1481 }
1482 }
1483
1484 for (i = 0; i < Q; i++)
1485 {
1486 swap(maparray[i * P], maparray[i * P + 1]);
1487 swap(signarray[i * P], signarray[i * P + 1]);
1488 }
1489 }
1490 else
1491 {
1492 for (i = 3; i < Q; i += 2)
1493 {
1494 for (j = 0; j < P; j++)
1495 {
1496 signarray[arrayindx[i * P + j]] *= -1;
1497 }
1498 }
1499
1500 for (i = 0; i < P; i++)
1501 {
1502 swap(maparray[i * Q], maparray[i * Q + 1]);
1503 swap(signarray[i * Q], signarray[i * Q + 1]);
1504 }
1505 }
1506 }
1507 }
1508}
1509
1511 const int eid, Array<OneD, unsigned int> &maparray,
1512 Array<OneD, int> &signarray, const Orientation edgeOrient)
1513{
1514 int i;
1515 bool signChange;
1516 const int P = m_base[0]->GetNumModes() - 1;
1517 const int Q = m_base[1]->GetNumModes() - 1;
1518 const int R = m_base[2]->GetNumModes() - 1;
1519 const int nEdgeIntCoeffs = v_GetEdgeNcoeffs(eid) - 2;
1520
1521 if (maparray.size() != nEdgeIntCoeffs)
1522 {
1523 maparray = Array<OneD, unsigned int>(nEdgeIntCoeffs);
1524 }
1525
1526 if (signarray.size() != nEdgeIntCoeffs)
1527 {
1528 signarray = Array<OneD, int>(nEdgeIntCoeffs, 1);
1529 }
1530 else
1531 {
1532 fill(signarray.data(), signarray.data() + nEdgeIntCoeffs, 1);
1533 }
1534
1535 // If edge is oriented backwards, change sign of modes which have
1536 // degree 2n+1, n >= 1.
1537 signChange = edgeOrient == eBackwards;
1538
1539 switch (eid)
1540 {
1541 case 0:
1542 for (i = 2; i <= P; ++i)
1543 {
1544 maparray[i - 2] = GetMode(i, 0, 0);
1545 }
1546 break;
1547
1548 case 1:
1549 for (i = 2; i <= Q; ++i)
1550 {
1551 maparray[i - 2] = GetMode(1, i, 0);
1552 }
1553 break;
1554
1555 case 2:
1556 // Base quad; reverse direction.
1557 // signChange = !signChange;
1558 for (i = 2; i <= P; ++i)
1559 {
1560 maparray[i - 2] = GetMode(i, 1, 0);
1561 }
1562 break;
1563
1564 case 3:
1565 // Base quad; reverse direction.
1566 // signChange = !signChange;
1567 for (i = 2; i <= Q; ++i)
1568 {
1569 maparray[i - 2] = GetMode(0, i, 0);
1570 }
1571 break;
1572
1573 case 4:
1574 for (i = 2; i <= R; ++i)
1575 {
1576 maparray[i - 2] = GetMode(0, 0, i);
1577 }
1578 break;
1579
1580 case 5:
1581 for (i = 1; i <= R - 1; ++i)
1582 {
1583 maparray[i - 1] = GetMode(1, 0, i);
1584 }
1585 break;
1586
1587 case 6:
1588 for (i = 1; i <= R - 1; ++i)
1589 {
1590 maparray[i - 1] = GetMode(1, 1, i);
1591 }
1592 break;
1593
1594 case 7:
1595 for (i = 2; i <= R; ++i)
1596 {
1597 maparray[i - 2] = GetMode(0, 1, i);
1598 }
1599 break;
1600
1601 case 8:
1602 for (i = 2; i <= Q; ++i)
1603 {
1604 maparray[i - 2] = GetMode(0, i, 1);
1605 }
1606 break;
1607
1608 default:
1609 ASSERTL0(false, "Edge not defined.");
1610 break;
1611 }
1612
1613 if (signChange)
1614 {
1615 for (i = 1; i < nEdgeIntCoeffs; i += 2)
1616 {
1617 signarray[i] = -1;
1618 }
1619 }
1620}
1621
1623 const int fid, Array<OneD, unsigned int> &maparray,
1624 Array<OneD, int> &signarray, const Orientation faceOrient)
1625{
1626 const int P = m_base[0]->GetNumModes() - 1;
1627 const int Q = m_base[1]->GetNumModes() - 1;
1628 const int R = m_base[2]->GetNumModes() - 1;
1629 const int nFaceIntCoeffs = v_GetTraceIntNcoeffs(fid);
1630 int p, q, r, idx = 0;
1631 int nummodesA = 0;
1632 int nummodesB = 0;
1633 int i = 0;
1634 int j = 0;
1635
1636 if (maparray.size() != nFaceIntCoeffs)
1637 {
1638 maparray = Array<OneD, unsigned int>(nFaceIntCoeffs);
1639 }
1640
1641 if (signarray.size() != nFaceIntCoeffs)
1642 {
1643 signarray = Array<OneD, int>(nFaceIntCoeffs, 1);
1644 }
1645 else
1646 {
1647 fill(signarray.data(), signarray.data() + nFaceIntCoeffs, 1);
1648 }
1649
1650 // Set up an array indexing for quad faces, since the ordering may
1651 // need to be transposed depending on orientation.
1652 Array<OneD, int> arrayindx(nFaceIntCoeffs);
1653 if (fid != 1 && fid != 3)
1654 {
1655 if (fid == 0) // Base quad
1656 {
1657 nummodesA = P - 1;
1658 nummodesB = Q - 1;
1659 }
1660 else // front and back quad
1661 {
1662 nummodesA = Q - 1;
1663 nummodesB = R - 1;
1664 }
1665
1666 for (i = 0; i < nummodesB; i++)
1667 {
1668 for (j = 0; j < nummodesA; j++)
1669 {
1670 if (faceOrient < eDir1FwdDir2_Dir2FwdDir1)
1671 {
1672 arrayindx[i * nummodesA + j] = i * nummodesA + j;
1673 }
1674 else
1675 {
1676 arrayindx[i * nummodesA + j] = j * nummodesB + i;
1677 }
1678 }
1679 }
1680 }
1681
1682 switch (fid)
1683 {
1684 case 0: // Bottom quad
1685 for (q = 2; q <= Q; ++q)
1686 {
1687 for (p = 2; p <= P; ++p)
1688 {
1689 maparray[arrayindx[(q - 2) * nummodesA + (p - 2)]] =
1690 GetMode(p, q, 0);
1691 }
1692 }
1693 break;
1694
1695 case 1: // Left triangle
1696 for (p = 2; p <= P; ++p)
1697 {
1698 for (r = 1; r <= R - p; ++r)
1699 {
1700 if (faceOrient == eDir1BwdDir1_Dir2FwdDir2)
1701 {
1702 signarray[idx] = p % 2 ? -1 : 1;
1703 }
1704 maparray[idx++] = GetMode(p, 0, r);
1705 }
1706 }
1707 break;
1708
1709 case 2: // Slanted quad
1710 for (r = 1; r <= R - 1; ++r)
1711 {
1712 for (q = 2; q <= Q; ++q)
1713 {
1714 maparray[arrayindx[(r - 1) * nummodesA + (q - 2)]] =
1715 GetMode(1, q, r);
1716 }
1717 }
1718 break;
1719
1720 case 3: // Right triangle
1721 for (p = 2; p <= P; ++p)
1722 {
1723 for (r = 1; r <= R - p; ++r)
1724 {
1725 if (faceOrient == eDir1BwdDir1_Dir2FwdDir2)
1726 {
1727 signarray[idx] = p % 2 ? -1 : 1;
1728 }
1729 maparray[idx++] = GetMode(p, 1, r);
1730 }
1731 }
1732 break;
1733
1734 case 4: // Back quad
1735 for (r = 2; r <= R; ++r)
1736 {
1737 for (q = 2; q <= Q; ++q)
1738 {
1739 maparray[arrayindx[(r - 2) * nummodesA + (q - 2)]] =
1740 GetMode(0, q, r);
1741 }
1742 }
1743 break;
1744
1745 default:
1746 ASSERTL0(false, "Face interior map not available.");
1747 }
1748
1749 // Triangular faces are processed in the above switch loop; for
1750 // remaining quad faces, set up orientation if necessary.
1751 if (fid == 1 || fid == 3)
1752 {
1753 return;
1754 }
1755
1756 if (faceOrient == eDir1FwdDir1_Dir2BwdDir2 ||
1757 faceOrient == eDir1BwdDir1_Dir2BwdDir2 ||
1758 faceOrient == eDir1BwdDir2_Dir2FwdDir1 ||
1759 faceOrient == eDir1BwdDir2_Dir2BwdDir1)
1760 {
1761 if (faceOrient < eDir1FwdDir2_Dir2FwdDir1)
1762 {
1763 for (i = 1; i < nummodesB; i += 2)
1764 {
1765 for (j = 0; j < nummodesA; j++)
1766 {
1767 signarray[arrayindx[i * nummodesA + j]] *= -1;
1768 }
1769 }
1770 }
1771 else
1772 {
1773 for (i = 0; i < nummodesB; i++)
1774 {
1775 for (j = 1; j < nummodesA; j += 2)
1776 {
1777 signarray[arrayindx[i * nummodesA + j]] *= -1;
1778 }
1779 }
1780 }
1781 }
1782
1783 if (faceOrient == eDir1BwdDir1_Dir2FwdDir2 ||
1784 faceOrient == eDir1BwdDir1_Dir2BwdDir2 ||
1785 faceOrient == eDir1FwdDir2_Dir2BwdDir1 ||
1786 faceOrient == eDir1BwdDir2_Dir2BwdDir1)
1787 {
1788 if (faceOrient < eDir1FwdDir2_Dir2FwdDir1)
1789 {
1790 for (i = 0; i < nummodesB; i++)
1791 {
1792 for (j = 1; j < nummodesA; j += 2)
1793 {
1794 signarray[arrayindx[i * nummodesA + j]] *= -1;
1795 }
1796 }
1797 }
1798 else
1799 {
1800 for (i = 1; i < nummodesB; i += 2)
1801 {
1802 for (j = 0; j < nummodesA; j++)
1803 {
1804 signarray[arrayindx[i * nummodesA + j]] *= -1;
1805 }
1806 }
1807 }
1808 }
1809}
1810
1811//---------------------------------------
1812// Wrapper functions
1813//---------------------------------------
1814
1816{
1817
1818 MatrixType mtype = mkey.GetMatrixType();
1819
1820 DNekMatSharedPtr Mat;
1821
1822 switch (mtype)
1823 {
1825 {
1826 int nq0 = m_base[0]->GetNumPoints();
1827 int nq1 = m_base[1]->GetNumPoints();
1828 int nq2 = m_base[2]->GetNumPoints();
1829 int nq;
1830
1831 // take definition from key
1833 {
1834 nq = (int)mkey.GetConstFactor(eFactorConst);
1835 }
1836 else
1837 {
1838 nq = max(nq0, max(nq1, nq2));
1839 }
1840
1841 int neq =
1844 Array<OneD, NekDouble> coll(3);
1846 Array<OneD, NekDouble> tmp(nq0);
1847
1848 Mat =
1849 MemoryManager<DNekMat>::AllocateSharedPtr(neq, nq0 * nq1 * nq2);
1850 int cnt = 0;
1851 for (int i = 0; i < nq; ++i)
1852 {
1853 for (int j = 0; j < nq; ++j)
1854 {
1855 for (int k = 0; k < nq - i; ++k, ++cnt)
1856 {
1857 coords[cnt] = Array<OneD, NekDouble>(3);
1858 coords[cnt][0] = -1.0 + 2 * k / (NekDouble)(nq - 1);
1859 coords[cnt][1] = -1.0 + 2 * j / (NekDouble)(nq - 1);
1860 coords[cnt][2] = -1.0 + 2 * i / (NekDouble)(nq - 1);
1861 }
1862 }
1863 }
1864
1865 for (int i = 0; i < neq; ++i)
1866 {
1867 LocCoordToLocCollapsed(coords[i], coll);
1868
1869 I[0] = m_base[0]->GetI(coll);
1870 I[1] = m_base[1]->GetI(coll + 1);
1871 I[2] = m_base[2]->GetI(coll + 2);
1872
1873 // interpolate first coordinate direction
1874 NekDouble fac;
1875 for (int k = 0; k < nq2; ++k)
1876 {
1877 for (int j = 0; j < nq1; ++j)
1878 {
1879
1880 fac = (I[1]->GetPtr())[j] * (I[2]->GetPtr())[k];
1881 Vmath::Smul(nq0, fac, I[0]->GetPtr(), 1, tmp, 1);
1882
1883 Vmath::Vcopy(nq0, &tmp[0], 1,
1884 Mat->GetRawPtr() + k * nq0 * nq1 * neq +
1885 j * nq0 * neq + i,
1886 neq);
1887 }
1888 }
1889 }
1890 }
1891 break;
1892 default:
1893 {
1895 }
1896 break;
1897 }
1898
1899 return Mat;
1900}
1901
1906
1907/**
1908 * @brief Compute the local mode number in the expansion for a
1909 * particular tensorial combination.
1910 *
1911 * Modes are numbered with the r index travelling fastest, followed by
1912 * q and then p, and each q-r plane is of size (R+1-p). For example,
1913 * with P=1, Q=2, R=3, the indexing inside each q-r plane (with r
1914 * increasing upwards and q to the right) is:
1915 *
1916 * p = 0: p = 1:
1917 * -----------------------
1918 * 3 7 11
1919 * 2 6 10 14 17 20
1920 * 1 5 9 13 16 19
1921 * 0 4 8 12 15 18
1922 *
1923 * Note that in this element, we must have that \f$ P <= R \f$.
1924 */
1925int StdPrismExp::GetMode(int p, int q, int r)
1926{
1927 int Q = m_base[1]->GetNumModes() - 1;
1928 int R = m_base[2]->GetNumModes() - 1;
1929
1930 return r + // Skip along stacks (r-direction)
1931 q * (R + 1 - p) + // Skip along columns (q-direction)
1932 (Q + 1) * (p * R + 1 -
1933 (p - 2) * (p - 1) / 2); // Skip along rows (p-direction)
1934}
1935
1937 const Array<OneD, const NekDouble> &inarray,
1938 Array<OneD, NekDouble> &outarray)
1939{
1940 int i, j;
1941 int nquad0 = m_base[0]->GetNumPoints();
1942 int nquad1 = m_base[1]->GetNumPoints();
1943 int nquad2 = m_base[2]->GetNumPoints();
1944
1945 const Array<OneD, const NekDouble> &w0 = m_base[0]->GetW();
1946 const Array<OneD, const NekDouble> &w1 = m_base[1]->GetW();
1947 const Array<OneD, const NekDouble> &w2 = m_base[2]->GetW();
1948
1949 const Array<OneD, const NekDouble> &z2 = m_base[2]->GetZ();
1950
1951 // Multiply by integration constants in x-direction
1952 for (i = 0; i < nquad1 * nquad2; ++i)
1953 {
1954 Vmath::Vmul(nquad0, inarray.data() + i * nquad0, 1, w0.data(), 1,
1955 outarray.data() + i * nquad0, 1);
1956 }
1957
1958 // Multiply by integration constants in y-direction
1959 for (j = 0; j < nquad2; ++j)
1960 {
1961 for (i = 0; i < nquad1; ++i)
1962 {
1963 Blas::Dscal(nquad0, w1[i],
1964 &outarray[0] + i * nquad0 + j * nquad0 * nquad1, 1);
1965 }
1966 }
1967
1968 // Multiply by integration constants in z-direction; need to
1969 // incorporate factor (1-eta_3)/2 into weights, but only if using
1970 // GLL quadrature points.
1971 switch (m_base[2]->GetPointsType())
1972 {
1973 // (1,0) Jacobi inner product.
1974 case LibUtilities::eGaussRadauMAlpha1Beta0:
1975 for (i = 0; i < nquad2; ++i)
1976 {
1977 Blas::Dscal(nquad0 * nquad1, 0.5 * w2[i],
1978 &outarray[0] + i * nquad0 * nquad1, 1);
1979 }
1980 break;
1981
1982 default:
1983 for (i = 0; i < nquad2; ++i)
1984 {
1985 Blas::Dscal(nquad0 * nquad1, 0.5 * (1 - z2[i]) * w2[i],
1986 &outarray[0] + i * nquad0 * nquad1, 1);
1987 }
1988 break;
1989 }
1990}
1991
1993 const StdMatrixKey &mkey)
1994{
1995 // Generate an orthonogal expansion
1996 int qa = m_base[0]->GetNumPoints();
1997 int qb = m_base[1]->GetNumPoints();
1998 int qc = m_base[2]->GetNumPoints();
1999 int nmodes_a = m_base[0]->GetNumModes();
2000 int nmodes_b = m_base[1]->GetNumModes();
2001 int nmodes_c = m_base[2]->GetNumModes();
2002 // Declare orthogonal basis.
2006
2010 StdPrismExp OrthoExp(Ba, Bb, Bc);
2011
2012 Array<OneD, NekDouble> orthocoeffs(OrthoExp.GetNcoeffs());
2013 int i, j, k, cnt = 0;
2014
2015 // project onto modal space.
2016 OrthoExp.FwdTrans(array, orthocoeffs);
2017
2019 {
2020 // Rodrigo's power kernel
2022 NekDouble SvvDiffCoeff =
2025
2026 for (i = 0; i < nmodes_a; ++i)
2027 {
2028 for (j = 0; j < nmodes_b; ++j)
2029 {
2030 NekDouble fac1 = std::max(
2031 pow((1.0 * i) / (nmodes_a - 1), cutoff * nmodes_a),
2032 pow((1.0 * j) / (nmodes_b - 1), cutoff * nmodes_b));
2033
2034 for (k = 0; k < nmodes_c - i; ++k)
2035 {
2036 NekDouble fac =
2037 std::max(fac1, pow((1.0 * k) / (nmodes_c - 1),
2038 cutoff * nmodes_c));
2039
2040 orthocoeffs[cnt] *= SvvDiffCoeff * fac;
2041 cnt++;
2042 }
2043 }
2044 }
2045 }
2046 else if (mkey.ConstFactorExists(
2047 eFactorSVVDGKerDiffCoeff)) // Rodrigo/Mansoor's DG Kernel
2048 {
2051
2052 int max_abc = max(nmodes_a - kSVVDGFiltermodesmin,
2053 nmodes_b - kSVVDGFiltermodesmin);
2054 max_abc = max(max_abc, nmodes_c - kSVVDGFiltermodesmin);
2055 // clamp max_abc
2056 max_abc = max(max_abc, 0);
2057 max_abc = min(max_abc, kSVVDGFiltermodesmax - kSVVDGFiltermodesmin);
2058
2059 for (i = 0; i < nmodes_a; ++i)
2060 {
2061 for (j = 0; j < nmodes_b; ++j)
2062 {
2063 int maxij = max(i, j);
2064
2065 for (k = 0; k < nmodes_c - i; ++k)
2066 {
2067 int maxijk = max(maxij, k);
2068 maxijk = min(maxijk, kSVVDGFiltermodesmax - 1);
2069
2070 orthocoeffs[cnt] *=
2071 SvvDiffCoeff * kSVVDGFilter[max_abc][maxijk];
2072 cnt++;
2073 }
2074 }
2075 }
2076 }
2077 else
2078 {
2079 // SVV filter paramaters (how much added diffusion relative
2080 // to physical one and fraction of modes from which you
2081 // start applying this added diffusion)
2082 //
2083 NekDouble SvvDiffCoeff =
2085 NekDouble SVVCutOff =
2087
2088 // Defining the cut of mode
2089 int cutoff_a = (int)(SVVCutOff * nmodes_a);
2090 int cutoff_b = (int)(SVVCutOff * nmodes_b);
2091 int cutoff_c = (int)(SVVCutOff * nmodes_c);
2092 // To avoid the fac[j] from blowing up
2093 NekDouble epsilon = 1;
2094
2095 int nmodes = min(min(nmodes_a, nmodes_b), nmodes_c);
2096 NekDouble cutoff = min(min(cutoff_a, cutoff_b), cutoff_c);
2097
2098 //------"New" Version August 22nd '13--------------------
2099 for (i = 0; i < nmodes_a; ++i) // P
2100 {
2101 for (j = 0; j < nmodes_b; ++j) // Q
2102 {
2103 for (k = 0; k < nmodes_c - i; ++k) // R
2104 {
2105 if (j >= cutoff || i + k >= cutoff)
2106 {
2107 orthocoeffs[cnt] *=
2108 (SvvDiffCoeff *
2109 exp(-(i + k - nmodes) * (i + k - nmodes) /
2110 ((NekDouble)((i + k - cutoff + epsilon) *
2111 (i + k - cutoff + epsilon)))) *
2112 exp(-(j - nmodes) * (j - nmodes) /
2113 ((NekDouble)((j - cutoff + epsilon) *
2114 (j - cutoff + epsilon)))));
2115 }
2116 else
2117 {
2118 orthocoeffs[cnt] *= 0.0;
2119 }
2120 cnt++;
2121 }
2122 }
2123 }
2124 }
2125
2126 // backward transform to physical space
2127 OrthoExp.BwdTrans(orthocoeffs, array);
2128}
2129
2131 int numMin, const Array<OneD, const NekDouble> &inarray,
2132 Array<OneD, NekDouble> &outarray)
2133{
2134 int nquad0 = m_base[0]->GetNumPoints();
2135 int nquad1 = m_base[1]->GetNumPoints();
2136 int nquad2 = m_base[2]->GetNumPoints();
2137 int nqtot = nquad0 * nquad1 * nquad2;
2138 int nmodes0 = m_base[0]->GetNumModes();
2139 int nmodes1 = m_base[1]->GetNumModes();
2140 int nmodes2 = m_base[2]->GetNumModes();
2141 int numMax = nmodes0;
2142
2144 Array<OneD, NekDouble> coeff_tmp1(m_ncoeffs, 0.0);
2145 Array<OneD, NekDouble> phys_tmp(nqtot, 0.0);
2146 Array<OneD, NekDouble> tmp, tmp2, tmp3, tmp4;
2147
2148 const LibUtilities::PointsKey Pkey0 = m_base[0]->GetPointsKey();
2149 const LibUtilities::PointsKey Pkey1 = m_base[1]->GetPointsKey();
2150 const LibUtilities::PointsKey Pkey2 = m_base[2]->GetPointsKey();
2151
2152 LibUtilities::BasisKey bortho0(LibUtilities::eOrtho_A, nmodes0, Pkey0);
2153 LibUtilities::BasisKey bortho1(LibUtilities::eOrtho_A, nmodes1, Pkey1);
2154 LibUtilities::BasisKey bortho2(LibUtilities::eOrtho_B, nmodes2, Pkey2);
2155
2156 int cnt = 0;
2157 int u = 0;
2158 int i = 0;
2160
2162 bortho0, bortho1, bortho2);
2163
2164 BwdTrans(inarray, phys_tmp);
2165 OrthoPrismExp->FwdTrans(phys_tmp, coeff);
2166
2167 // filtering
2168 for (u = 0; u < numMin; ++u)
2169 {
2170 for (i = 0; i < numMin; ++i)
2171 {
2172 Vmath::Vcopy(numMin - u, tmp = coeff + cnt, 1,
2173 tmp2 = coeff_tmp1 + cnt, 1);
2174 cnt += numMax - u;
2175 }
2176
2177 for (i = numMin; i < numMax; ++i)
2178 {
2179 cnt += numMax - u;
2180 }
2181 }
2182
2183 OrthoPrismExp->BwdTrans(coeff_tmp1, phys_tmp);
2184 StdPrismExp::FwdTrans(phys_tmp, outarray);
2185}
2186} // 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...
Describes the specification for a Basis.
Definition Basis.h:45
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.
void BwdTrans_SumFacKernel(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, Array< OneD, NekDouble > &wsp, bool doCheckCollDir0, bool doCheckCollDir1, bool doCheckCollDir2)
void IProductWRTBase_SumFacKernel(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, Array< OneD, NekDouble > &wsp, bool doCheckCollDir0, bool doCheckCollDir1, bool doCheckCollDir2)
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 > &outarray_d1, Array< OneD, NekDouble > &outarray_d2, Array< OneD, NekDouble > &outarray_d3)
Calculate the 3D derivative in the local tensor/collapsed coordinate at the physical points.
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.
DNekMatSharedPtr GetStdMatrix(const StdMatrixKey &mkey)
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.
LibUtilities::ShapeType DetShapeType() const
This function returns the shape of the expansion 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)
This function performs the Forward transformation from physical space to coefficient space.
int GetNumPoints(const int dir) const
This function returns the number of quadrature points in the dir direction.
void MultiplyByQuadratureMetric(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray)
int GetBasisNumModes(const int dir) const
This function returns the number of expansion modes in the dir direction.
void PhysDeriv(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &out_d0, Array< OneD, NekDouble > &out_d1=NullNekDouble1DArray, Array< OneD, NekDouble > &out_d2=NullNekDouble1DArray)
Array< OneD, LibUtilities::BasisSharedPtr > m_base
MatrixType GetMatrixType() const
NekDouble GetConstFactor(const ConstFactorType &factor) const
bool ConstFactorExists(const ConstFactorType &factor) const
Class representing a prismatic element in reference space.
Definition StdPrismExp.h:45
void v_SVVLaplacianFilter(Array< OneD, NekDouble > &array, const StdMatrixKey &mkey) override
void v_GetElmtTraceToTraceMap(const unsigned int fid, Array< OneD, unsigned int > &maparray, Array< OneD, int > &signarray, Orientation faceOrient, int P, int Q) override
void v_ReduceOrderCoeffs(int numMin, const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray) override
void v_GetEdgeInteriorToElementMap(const int tid, Array< OneD, unsigned int > &maparray, Array< OneD, int > &signarray, const Orientation traceOrient=eDir1FwdDir1_Dir2FwdDir2) override
LibUtilities::PointsKey v_GetTracePointsKey(const int i, const int j) const override
const LibUtilities::BasisKey v_GetTraceBasisKey(const int i, const int k, bool UseGLL=false) const override
NekDouble v_PhysEvalFirstDeriv(const Array< OneD, NekDouble > &coord, const Array< OneD, const NekDouble > &inarray, std::array< NekDouble, 3 > &firstOrderDerivs) override
int v_GetVertexMap(int localVertexId, bool useCoeffPacking=false) override
int v_CalcNumberOfCoefficients(const std::vector< unsigned int > &nummodes, int &modes_offset) override
int v_GetTraceIntNcoeffs(const int i) const override
StdPrismExp(const LibUtilities::BasisKey &Ba, const LibUtilities::BasisKey &Bb, const LibUtilities::BasisKey &Bc)
int v_NumBndryCoeffs() const override
void v_FillMode(const int mode, Array< OneD, NekDouble > &outarray) override
NekDouble v_PhysEvaluateBasis(const Array< OneD, const NekDouble > &coords, int mode) final
void v_BwdTrans(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray) override
void v_IProductWRTBase_SumFac(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray, bool multiplybyweights=true) override
LibUtilities::ShapeType v_DetShapeType() const override
Return Shape of region, using ShapeType enum list; i.e. prism.
void v_IProductWRTBase(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray) override
Calculate the inner product of inarray with respect to the basis B=base0*base1*base2 and put into out...
int v_GetNverts() const override
int v_NumDGBndryCoeffs() const override
void v_PhysDeriv(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.
void v_GetTraceNumModes(const int fid, int &numModes0, int &numModes1, Orientation faceOrient=eDir1FwdDir1_Dir2FwdDir2) override
void v_GetCoords(Array< OneD, NekDouble > &xi_x, Array< OneD, NekDouble > &xi_y, Array< OneD, NekDouble > &xi_z) override
void v_GetBoundaryMap(Array< OneD, unsigned int > &outarray) override
DNekMatSharedPtr v_CreateStdMatrix(const StdMatrixKey &mkey) override
void v_IProductWRTDerivBase_SumFac(const int dir, const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray) override
int v_GetNtraces() const 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
int GetMode(int I, int J, int K)
Compute the local mode number in the expansion for a particular tensorial combination.
int v_GetTraceNcoeffs(const int i) const override
void v_IProductWRTBase_SumFacKernel(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, Array< OneD, NekDouble > &wsp, bool doCheckCollDir0, bool doCheckCollDir1, bool doCheckCollDir2) override
void v_FwdTrans(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray) override
Forward transform from physical quadrature space stored in inarray and evaluate the expansion coeffic...
void v_BwdTrans_SumFacKernel(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, Array< OneD, NekDouble > &wsp, bool doCheckCollDir0, bool doCheckCollDir1, bool doCheckCollDir2) override
int v_GetEdgeNcoeffs(const int i) const override
void v_LocCollapsedToLocCoord(const Array< OneD, const NekDouble > &eta, Array< OneD, NekDouble > &xi) override
void v_GetInteriorMap(Array< OneD, unsigned int > &outarray) override
void v_BwdTrans_SumFac(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray) override
void v_GetTraceCoeffMap(const unsigned int fid, Array< OneD, unsigned int > &maparray) override
void v_GetTraceInteriorToElementMap(const int tid, Array< OneD, unsigned int > &maparray, Array< OneD, int > &signarray, const Orientation traceOrient=eDir1FwdDir1_Dir2FwdDir2) override
void v_MultiplyByStdQuadratureMetric(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray) override
DNekMatSharedPtr v_GenMatrix(const StdMatrixKey &mkey) override
int v_GetTraceNumPoints(const int i) const override
bool v_IsBoundaryInteriorExpansion() const override
int v_GetNedges() const override
void v_IProductWRTDerivBase(const int dir, const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray) override
Inner product of inarray over region with respect to the object's default expansion basis; output in ...
void v_LocCoordToLocCollapsed(const Array< OneD, const NekDouble > &xi, Array< OneD, NekDouble > &eta) override
static void Dscal(const int &n, const double &alpha, double *x, const int &incx)
BLAS level 1: x = alpha x.
Definition Blas.hpp:149
static double Ddot(const int &n, const double *x, const int &incx, const double *y, const int &incy)
BLAS level 1: output = .
Definition Blas.hpp:163
static void Dgemm(const char &transa, const char &transb, const int &m, const int &n, const int &k, const double &alpha, const double *a, const int &lda, const double *b, const int &ldb, const double &beta, double *c, const int &ldc)
BLAS level 3: Matrix-matrix multiply C = A x B where op(A)[m x k], op(B)[k x n], C[m x n] DGEMM perfo...
Definition Blas.hpp:383
static void Daxpy(const int &n, const double &alpha, const double *x, const int &incx, const double *y, const int &incy)
BLAS level 1: y = alpha x plus y.
Definition Blas.hpp:135
int getNumberOfCoefficients(int Na, int Nb, int Nc)
int getNumberOfBndCoefficients(int Na, int Nb, int Nc)
static const BasisKey NullBasisKey(eNoBasisType, 0, NullPointsKey)
Defines a null basis with no type or points.
@ eModified_B
Principle Modified Functions .
Definition BasisType.h:49
@ P
Monomial polynomials .
Definition BasisType.h:62
@ eOrtho_A
Principle Orthogonal Functions .
Definition BasisType.h:42
@ eModified_C
Principle Modified Functions .
Definition BasisType.h:50
@ eGLL_Lagrange
Lagrange for SEM basis .
Definition BasisType.h:56
@ eOrtho_C
Principle Orthogonal Functions .
Definition BasisType.h:46
@ eOrtho_B
Principle Orthogonal Functions .
Definition BasisType.h:44
@ eModified_A
Principle Modified Functions .
Definition BasisType.h:48
static const NekDouble kNekZeroTol
std::shared_ptr< StdPrismExp > StdPrismExpSharedPtr
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
const int kSVVDGFiltermodesmax
const NekDouble kSVVDGFilter[9][11]
static Array< OneD, NekDouble > NullNekDouble1DArray
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 Svtvp(int n, const T alpha, const T *x, const int incx, const T *y, const int incy, T *z, const int incz)
Svtvp (scalar times vector plus vector): z = alpha*x + y.
Definition Vmath.hpp:396
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
scalarT< T > sqrt(scalarT< T > in)
Definition scalar.hpp:290