Nektar++
StdHexExp.cpp
Go to the documentation of this file.
1///////////////////////////////////////////////////////////////////////////////
2//
3// File: StdHexExp.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: Heaxhedral methods
32//
33///////////////////////////////////////////////////////////////////////////////
34
36
37#ifdef max
38#undef max
39#endif
40
41using namespace std;
42
43namespace Nektar::StdRegions
44{
46 const LibUtilities::BasisKey &Bb,
47 const LibUtilities::BasisKey &Bc)
48 : StdExpansion(Ba.GetNumModes() * Bb.GetNumModes() * Bc.GetNumModes(), 3,
49 Ba, Bb, Bc),
50 StdExpansion3D(Ba.GetNumModes() * Bb.GetNumModes() * Bc.GetNumModes(), Ba,
51 Bb, Bc)
52{
53}
54
56{
60 (m_base[0]->GetBasisType() == LibUtilities::eGLL_Lagrange &&
61 m_base[1]->GetBasisType() == LibUtilities::eGLL_Lagrange &&
62 m_base[1]->GetBasisType() == LibUtilities::eGLL_Lagrange);
63}
64
65///////////////////////////////
66/// Differentiation Methods
67///////////////////////////////
68/**
69 * For Hexahedral region can use the PhysTensorDeriv function defined
70 * under StdExpansion. Following tenserproduct:
71 */
76{
77 StdExpansion3D::PhysTensorDeriv(inarray, out_d0, out_d1, out_d2);
78}
79
80/**
81 * @param dir Direction in which to compute derivative.
82 * Valid values are 0, 1, 2.
83 * @param inarray Input array.
84 * @param outarray Output array.
85 */
86void StdHexExp::v_PhysDeriv(const int dir,
87 const Array<OneD, const NekDouble> &inarray,
88 Array<OneD, NekDouble> &outarray)
89{
90 switch (dir)
91 {
92 case 0:
93 {
94 PhysDeriv(inarray, outarray, NullNekDouble1DArray,
96 }
97 break;
98 case 1:
99 {
100 PhysDeriv(inarray, NullNekDouble1DArray, outarray,
102 }
103 break;
104 case 2:
105 {
107 outarray);
108 }
109 break;
110 default:
111 {
112 ASSERTL1(false, "input dir is out of range");
113 }
114 break;
115 }
116}
117
122{
123 StdHexExp::v_PhysDeriv(inarray, out_d0, out_d1, out_d2);
124}
125
126void StdHexExp::v_StdPhysDeriv(const int dir,
127 const Array<OneD, const NekDouble> &inarray,
128 Array<OneD, NekDouble> &outarray)
129{
130 StdHexExp::v_PhysDeriv(dir, inarray, outarray);
131}
132
133/**
134 * Backward transformation is three dimensional tensorial expansion
135 * \f$ u (\xi_{1i}, \xi_{2j}, \xi_{3k})
136 * = \sum_{p=0}^{Q_x} \psi_p^a (\xi_{1i})
137 * \lbrace { \sum_{q=0}^{Q_y} \psi_{q}^a (\xi_{2j})
138 * \lbrace { \sum_{r=0}^{Q_z} \hat u_{pqr} \psi_{r}^a (\xi_{3k})
139 * \rbrace}
140 * \rbrace}. \f$
141 * And sumfactorizing step of the form is as:\\
142 * \f$ f_{r} (\xi_{3k})
143 * = \sum_{r=0}^{Q_z} \hat u_{pqr} \psi_{r}^a (\xi_{3k}),\\
144 * g_{p} (\xi_{2j}, \xi_{3k})
145 * = \sum_{r=0}^{Q_y} \psi_{p}^a (\xi_{2j}) f_{r} (\xi_{3k}),\\
146 * u(\xi_{1i}, \xi_{2j}, \xi_{3k})
147 * = \sum_{p=0}^{Q_x} \psi_{p}^a (\xi_{1i}) g_{p} (\xi_{2j}, \xi_{3k}).
148 * \f$
149 *
150 * @param inarray ?
151 * @param outarray ?
152 */
154 Array<OneD, NekDouble> &outarray)
155{
158 "Basis[1] is not a general tensor type");
159
162 "Basis[2] is not a general tensor type");
163
164 if (m_base[0]->Collocation() && m_base[1]->Collocation() &&
165 m_base[2]->Collocation())
166 {
168 m_base[2]->GetNumPoints(),
169 inarray, 1, outarray, 1);
170 }
171 else
172 {
173 StdHexExp::BwdTrans_SumFac(inarray, outarray);
174 }
175}
176
177/**
178 *
179 */
181 Array<OneD, NekDouble> &outarray)
182{
184 m_base[0]->GetNumPoints() * m_base[2]->GetNumModes() *
185 (m_base[1]->GetNumModes() + m_base[1]->GetNumPoints())); // FIX THIS
186
187 BwdTrans_SumFacKernel(m_base[0]->GetBdata(), m_base[1]->GetBdata(),
188 m_base[2]->GetBdata(), inarray, outarray, wsp, true,
189 true, true);
190}
191
192/**
193 * @param base0 x-dirn basis matrix
194 * @param base1 y-dirn basis matrix
195 * @param base2 z-dirn basis matrix
196 * @param inarray Input vector of modes.
197 * @param outarray Output vector of physical space data.
198 * @param wsp Workspace of size Q_x*P_z*(P_y+Q_y)
199 * @param doCheckCollDir0 Check for collocation of basis.
200 * @param doCheckCollDir1 Check for collocation of basis.
201 * @param doCheckCollDir2 Check for collocation of basis.
202 * @todo Account for some directions being collocated. See
203 * StdQuadExp as an example.
204 */
206 const Array<OneD, const NekDouble> &base0,
207 const Array<OneD, const NekDouble> &base1,
208 const Array<OneD, const NekDouble> &base2,
209 const Array<OneD, const NekDouble> &inarray,
211 bool doCheckCollDir0, bool doCheckCollDir1, bool doCheckCollDir2)
212{
213 int nquad0 = m_base[0]->GetNumPoints();
214 int nquad1 = m_base[1]->GetNumPoints();
215 int nquad2 = m_base[2]->GetNumPoints();
216 int nmodes0 = m_base[0]->GetNumModes();
217 int nmodes1 = m_base[1]->GetNumModes();
218 int nmodes2 = m_base[2]->GetNumModes();
219
220 // Check if using collocation, if requested.
221 bool colldir0 = doCheckCollDir0 ? (m_base[0]->Collocation()) : false;
222 bool colldir1 = doCheckCollDir1 ? (m_base[1]->Collocation()) : false;
223 bool colldir2 = doCheckCollDir2 ? (m_base[2]->Collocation()) : false;
224
225 // If collocation in all directions, Physical values at quadrature
226 // points is just a copy of the modes.
227 if (colldir0 && colldir1 && colldir2)
228 {
229 Vmath::Vcopy(m_ncoeffs, inarray.get(), 1, outarray.get(), 1);
230 }
231 else
232 {
233 // Check sufficiently large workspace.
234 ASSERTL1(wsp.size() >= nquad0 * nmodes2 * (nmodes1 + nquad1),
235 "Workspace size is not sufficient");
236
237 // Assign second half of workspace for 2nd DGEMM operation.
238 Array<OneD, NekDouble> wsp2 = wsp + nquad0 * nmodes1 * nmodes2;
239
240 // BwdTrans in each direction using DGEMM
241 Blas::Dgemm('T', 'T', nmodes1 * nmodes2, nquad0, nmodes0, 1.0,
242 &inarray[0], nmodes0, base0.get(), nquad0, 0.0, &wsp[0],
243 nmodes1 * nmodes2);
244 Blas::Dgemm('T', 'T', nquad0 * nmodes2, nquad1, nmodes1, 1.0, &wsp[0],
245 nmodes1, base1.get(), nquad1, 0.0, &wsp2[0],
246 nquad0 * nmodes2);
247 Blas::Dgemm('T', 'T', nquad0 * nquad1, nquad2, nmodes2, 1.0, &wsp2[0],
248 nmodes2, base2.get(), nquad2, 0.0, &outarray[0],
249 nquad0 * nquad1);
250 }
251}
252
253/**
254 * Solves the system
255 * \f$ \mathbf{B^{\top}WB\hat{u}}=\mathbf{B^{\top}Wu^{\delta}} \f$
256 *
257 * @param inarray array of physical quadrature points to be
258 * transformed, \f$ \mathbf{u^{\delta}} \f$.
259 * @param outarray array of expansion coefficients,
260 * \f$ \mathbf{\hat{u}} \f$.
261 */
263 Array<OneD, NekDouble> &outarray)
264{
265 // If using collocation expansion, coefficients match physical
266 // data points so just do a direct copy.
267 if ((m_base[0]->Collocation()) && (m_base[1]->Collocation()) &&
268 (m_base[2]->Collocation()))
269 {
270 Vmath::Vcopy(GetNcoeffs(), &inarray[0], 1, &outarray[0], 1);
271 }
272 else
273 {
274 // Compute B^TWu
275 IProductWRTBase(inarray, outarray);
276
277 // get Mass matrix inverse
278 StdMatrixKey masskey(eInvMass, DetShapeType(), *this);
279 DNekMatSharedPtr matsys = GetStdMatrix(masskey);
280
281 // copy inarray in case inarray == outarray
282 DNekVec in(m_ncoeffs, outarray);
283 DNekVec out(m_ncoeffs, outarray, eWrapper);
284
285 // Solve for coefficients.
286 out = (*matsys) * in;
287 }
288}
289
290/**
291 * \f$
292 * \begin{array}{rcl}
293 * I_{pqr} = (\phi_{pqr}, u)_{\delta} & = &
294 * \sum_{i=0}^{nq_0} \sum_{j=0}^{nq_1} \sum_{k=0}^{nq_2}
295 * \psi_{p}^{a}(\xi_{1i}) \psi_{q}^{a}(\xi_{2j}) \psi_{r}^{a}(\xi_{3k})
296 * w_i w_j w_k u(\xi_{1,i} \xi_{2,j} \xi_{3,k})
297 *
298 * J_{i,j,k}\\ & = & \sum_{i=0}^{nq_0} \psi_p^a(\xi_{1,i})
299 * \sum_{j=0}^{nq_1} \psi_{q}^a(\xi_{2,j})
300 * \sum_{k=0}^{nq_2} \psi_{r}^a
301 * u(\xi_{1i},\xi_{2j},\xi_{3k}) J_{i,j,k}
302 * \end{array} \f$ \n
303 * where
304 * \f$ \phi_{pqr} (\xi_1 , \xi_2 , \xi_3)
305 * = \psi_p^a( \xi_1) \psi_{q}^a(\xi_2) \psi_{r}^a(\xi_3) \f$ \n
306 * which can be implemented as \n
307 * \f$f_{r} (\xi_{3k})
308 * = \sum_{k=0}^{nq_3} \psi_{r}^a u(\xi_{1i},\xi_{2j}, \xi_{3k})
309 * J_{i,j,k} = {\bf B_3 U} \f$ \n
310 * \f$ g_{q} (\xi_{3k})
311 * = \sum_{j=0}^{nq_1} \psi_{q}^a(\xi_{2j}) f_{r}(\xi_{3k})
312 * = {\bf B_2 F} \f$ \n
313 * \f$ (\phi_{pqr}, u)_{\delta}
314 * = \sum_{k=0}^{nq_0} \psi_{p}^a (\xi_{3k}) g_{q} (\xi_{3k})
315 * = {\bf B_1 G} \f$
316 *
317 * @param inarray ?
318 * @param outarray ?
319 */
321 Array<OneD, NekDouble> &outarray)
322{
323 if (m_base[0]->Collocation() && m_base[1]->Collocation() &&
324 m_base[2]->Collocation())
325 {
326 MultiplyByQuadratureMetric(inarray, outarray);
327 }
328 else
329 {
330 StdHexExp::v_IProductWRTBase_SumFac(inarray, outarray);
331 }
332}
333
334/**
335 * Implementation of the sum-factorization inner product operation.
336 */
338 const Array<OneD, const NekDouble> &inarray,
339 Array<OneD, NekDouble> &outarray, bool multiplybyweights)
340{
341 int nquad0 = m_base[0]->GetNumPoints();
342 int nquad1 = m_base[1]->GetNumPoints();
343 int nquad2 = m_base[2]->GetNumPoints();
344 int order0 = m_base[0]->GetNumModes();
345 int order1 = m_base[1]->GetNumModes();
346
347 Array<OneD, NekDouble> wsp(nquad0 * nquad1 * (nquad2 + order0) +
348 order0 * order1 * nquad2);
349
350 if (multiplybyweights)
351 {
352 Array<OneD, NekDouble> tmp(inarray.size());
353 MultiplyByQuadratureMetric(inarray, tmp);
354
356 m_base[0]->GetBdata(), m_base[1]->GetBdata(), m_base[2]->GetBdata(),
357 tmp, outarray, wsp, true, true, true);
358 }
359 else
360 {
362 m_base[0]->GetBdata(), m_base[1]->GetBdata(), m_base[2]->GetBdata(),
363 inarray, outarray, wsp, true, true, true);
364 }
365}
366
367/**
368 * Implementation of the sum-factorisation inner product operation.
369 * @todo Implement cases where only some directions are collocated.
370 */
372 const Array<OneD, const NekDouble> &base0,
373 const Array<OneD, const NekDouble> &base1,
374 const Array<OneD, const NekDouble> &base2,
375 const Array<OneD, const NekDouble> &inarray,
377 bool doCheckCollDir0, bool doCheckCollDir1, bool doCheckCollDir2)
378{
379 int nquad0 = m_base[0]->GetNumPoints();
380 int nquad1 = m_base[1]->GetNumPoints();
381 int nquad2 = m_base[2]->GetNumPoints();
382 int nmodes0 = m_base[0]->GetNumModes();
383 int nmodes1 = m_base[1]->GetNumModes();
384 int nmodes2 = m_base[2]->GetNumModes();
385
386 bool colldir0 = doCheckCollDir0 ? (m_base[0]->Collocation()) : false;
387 bool colldir1 = doCheckCollDir1 ? (m_base[1]->Collocation()) : false;
388 bool colldir2 = doCheckCollDir2 ? (m_base[2]->Collocation()) : false;
389
390 if (colldir0 && colldir1 && colldir2)
391 {
392 Vmath::Vcopy(m_ncoeffs, inarray.get(), 1, outarray.get(), 1);
393 }
394 else
395 {
396 ASSERTL1(wsp.size() >= nmodes0 * nquad2 * (nquad1 + nmodes1),
397 "Insufficient workspace size");
398
399 Array<OneD, NekDouble> tmp0 = wsp;
400 Array<OneD, NekDouble> tmp1 = wsp + nmodes0 * nquad1 * nquad2;
401
402 if (colldir0)
403 {
404 // reshuffle data for next operation.
405 for (int n = 0; n < nmodes0; ++n)
406 {
407 Vmath::Vcopy(nquad1 * nquad2, inarray.get() + n, nquad0,
408 tmp0.get() + nquad1 * nquad2 * n, 1);
409 }
410 }
411 else
412 {
413 Blas::Dgemm('T', 'N', nquad1 * nquad2, nmodes0, nquad0, 1.0,
414 inarray.get(), nquad0, base0.get(), nquad0, 0.0,
415 tmp0.get(), nquad1 * nquad2);
416 }
417
418 if (colldir1)
419 {
420 // reshuffle data for next operation.
421 for (int n = 0; n < nmodes1; ++n)
422 {
423 Vmath::Vcopy(nquad2 * nmodes0, tmp0.get() + n, nquad1,
424 tmp1.get() + nquad2 * nmodes0 * n, 1);
425 }
426 }
427 else
428 {
429 Blas::Dgemm('T', 'N', nquad2 * nmodes0, nmodes1, nquad1, 1.0,
430 tmp0.get(), nquad1, base1.get(), nquad1, 0.0,
431 tmp1.get(), nquad2 * nmodes0);
432 }
433
434 if (colldir2)
435 {
436 // reshuffle data for next operation.
437 for (int n = 0; n < nmodes2; ++n)
438 {
439 Vmath::Vcopy(nmodes0 * nmodes1, tmp1.get() + n, nquad2,
440 outarray.get() + nmodes0 * nmodes1 * n, 1);
441 }
442 }
443 else
444 {
445 Blas::Dgemm('T', 'N', nmodes0 * nmodes1, nmodes2, nquad2, 1.0,
446 tmp1.get(), nquad2, base2.get(), nquad2, 0.0,
447 outarray.get(), nmodes0 * nmodes1);
448 }
449 }
450}
451
453 const int dir, const Array<OneD, const NekDouble> &inarray,
454 Array<OneD, NekDouble> &outarray)
455{
456 StdHexExp::IProductWRTDerivBase_SumFac(dir, inarray, outarray);
457}
458
460 const int dir, const Array<OneD, const NekDouble> &inarray,
461 Array<OneD, NekDouble> &outarray)
462{
463 ASSERTL0((dir == 0) || (dir == 1) || (dir == 2),
464 "input dir is out of range");
465
466 int nquad1 = m_base[1]->GetNumPoints();
467 int nquad2 = m_base[2]->GetNumPoints();
468 int order0 = m_base[0]->GetNumModes();
469 int order1 = m_base[1]->GetNumModes();
470
471 // If outarray > inarray then no need for temporary storage.
472 Array<OneD, NekDouble> tmp = outarray;
473 if (outarray.size() < inarray.size())
474 {
475 tmp = Array<OneD, NekDouble>(inarray.size());
476 }
477
478 // Need workspace for sumfackernel though
479 Array<OneD, NekDouble> wsp(order0 * nquad2 * (nquad1 + order1));
480
481 // multiply by integration constants
482 MultiplyByQuadratureMetric(inarray, tmp);
483
484 // perform sum-factorisation
485 switch (dir)
486 {
487 case 0:
489 m_base[0]->GetDbdata(), m_base[1]->GetBdata(),
490 m_base[2]->GetBdata(), tmp, outarray, wsp, false, true, true);
491 break;
492 case 1:
494 m_base[0]->GetBdata(), m_base[1]->GetDbdata(),
495 m_base[2]->GetBdata(), tmp, outarray, wsp, true, false, true);
496 break;
497 case 2:
499 m_base[0]->GetBdata(), m_base[1]->GetBdata(),
500 m_base[2]->GetDbdata(), tmp, outarray, wsp, true, true, false);
501 break;
502 }
503}
504
507{
508 eta[0] = xi[0];
509 eta[1] = xi[1];
510 eta[2] = xi[2];
511}
512
515{
516 xi[0] = eta[0];
517 xi[1] = eta[1];
518 xi[2] = eta[2];
519}
520
521/**
522 * @note for hexahedral expansions _base[0] (i.e. p) modes run fastest.
523 */
524void StdHexExp::v_FillMode(const int mode, Array<OneD, NekDouble> &outarray)
525{
526 int nquad0 = m_base[0]->GetNumPoints();
527 int nquad1 = m_base[1]->GetNumPoints();
528 int nquad2 = m_base[2]->GetNumPoints();
529
530 Array<OneD, const NekDouble> base0 = m_base[0]->GetBdata();
531 Array<OneD, const NekDouble> base1 = m_base[1]->GetBdata();
532 Array<OneD, const NekDouble> base2 = m_base[2]->GetBdata();
533
534 int btmp0 = m_base[0]->GetNumModes();
535 int btmp1 = m_base[1]->GetNumModes();
536 int mode2 = mode / (btmp0 * btmp1);
537 int mode1 = (mode - mode2 * btmp0 * btmp1) / btmp0;
538 int mode0 = (mode - mode2 * btmp0 * btmp1) % btmp0;
539
540 ASSERTL2(mode == mode2 * btmp0 * btmp1 + mode1 * btmp0 + mode0,
541 "Mode lookup failed.");
542 ASSERTL2(mode < m_ncoeffs,
543 "Calling argument mode is larger than total expansion "
544 "order");
545
546 for (int i = 0; i < nquad1 * nquad2; ++i)
547 {
548 Vmath::Vcopy(nquad0, (NekDouble *)(base0.get() + mode0 * nquad0), 1,
549 &outarray[0] + i * nquad0, 1);
550 }
551
552 for (int j = 0; j < nquad2; ++j)
553 {
554 for (int i = 0; i < nquad0; ++i)
555 {
556 Vmath::Vmul(nquad1, (NekDouble *)(base1.get() + mode1 * nquad1), 1,
557 &outarray[0] + i + j * nquad0 * nquad1, nquad0,
558 &outarray[0] + i + j * nquad0 * nquad1, nquad0);
559 }
560 }
561
562 for (int i = 0; i < nquad2; i++)
563 {
564 Blas::Dscal(nquad0 * nquad1, base2[mode2 * nquad2 + i],
565 &outarray[0] + i * nquad0 * nquad1, 1);
566 }
567}
568
570 const Array<OneD, const NekDouble> &coords, int mode)
571{
572 ASSERTL2(coords[0] > -1 - NekConstants::kNekZeroTol, "coord[0] < -1");
573 ASSERTL2(coords[0] < 1 + NekConstants::kNekZeroTol, "coord[0] > 1");
574 ASSERTL2(coords[1] > -1 - NekConstants::kNekZeroTol, "coord[1] < -1");
575 ASSERTL2(coords[1] < 1 + NekConstants::kNekZeroTol, "coord[1] > 1");
576 ASSERTL2(coords[2] > -1 - NekConstants::kNekZeroTol, "coord[2] < -1");
577 ASSERTL2(coords[2] < 1 + NekConstants::kNekZeroTol, "coord[2] > 1");
578
579 const int nm0 = m_base[0]->GetNumModes();
580 const int nm1 = m_base[1]->GetNumModes();
581 const int mode2 = mode / (nm0 * nm1);
582 const int mode1 = (mode - mode2 * nm0 * nm1) / nm0;
583 const int mode0 = (mode - mode2 * nm0 * nm1) % nm0;
584
585 return StdExpansion::BaryEvaluateBasis<0>(coords[0], mode0) *
586 StdExpansion::BaryEvaluateBasis<1>(coords[1], mode1) *
587 StdExpansion::BaryEvaluateBasis<2>(coords[2], mode2);
588}
589
591{
592 return 8;
593}
594
596{
597 return 12;
598}
599
601{
602 return 6;
603}
604
606{
608}
609
611{
614 "BasisType is not a boundary interior form");
617 "BasisType is not a boundary interior form");
620 "BasisType is not a boundary interior form");
621
622 int nmodes0 = m_base[0]->GetNumModes();
623 int nmodes1 = m_base[1]->GetNumModes();
624 int nmodes2 = m_base[2]->GetNumModes();
625
626 return (2 * (nmodes0 * nmodes1 + nmodes0 * nmodes2 + nmodes1 * nmodes2) -
627 4 * (nmodes0 + nmodes1 + nmodes2) + 8);
628}
629
631{
634 "BasisType is not a boundary interior form");
637 "BasisType is not a boundary interior form");
640 "BasisType is not a boundary interior form");
641
642 int nmodes0 = m_base[0]->GetNumModes();
643 int nmodes1 = m_base[1]->GetNumModes();
644 int nmodes2 = m_base[2]->GetNumModes();
645
646 return 2 * (nmodes0 * nmodes1 + nmodes0 * nmodes2 + nmodes1 * nmodes2);
647}
648
649int StdHexExp::v_GetTraceNcoeffs(const int i) const
650{
651 ASSERTL2((i >= 0) && (i <= 5), "face id is out of range");
652 if ((i == 0) || (i == 5))
653 {
654 return GetBasisNumModes(0) * GetBasisNumModes(1);
655 }
656 else if ((i == 1) || (i == 3))
657 {
658 return GetBasisNumModes(0) * GetBasisNumModes(2);
659 }
660 else
661 {
662 return GetBasisNumModes(1) * GetBasisNumModes(2);
663 }
664}
665
667{
668 ASSERTL2((i >= 0) && (i <= 5), "face id is out of range");
669 if ((i == 0) || (i == 5))
670 {
671 return (GetBasisNumModes(0) - 2) * (GetBasisNumModes(1) - 2);
672 }
673 else if ((i == 1) || (i == 3))
674 {
675 return (GetBasisNumModes(0) - 2) * (GetBasisNumModes(2) - 2);
676 }
677 else
678 {
679 return (GetBasisNumModes(1) - 2) * (GetBasisNumModes(2) - 2);
680 }
681}
682
683int StdHexExp::v_GetTraceNumPoints(const int i) const
684{
685 ASSERTL2(i >= 0 && i <= 5, "face id is out of range");
686
687 if (i == 0 || i == 5)
688 {
689 return m_base[0]->GetNumPoints() * m_base[1]->GetNumPoints();
690 }
691 else if (i == 1 || i == 3)
692 {
693 return m_base[0]->GetNumPoints() * m_base[2]->GetNumPoints();
694 }
695 else
696 {
697 return m_base[1]->GetNumPoints() * m_base[2]->GetNumPoints();
698 }
699}
700
702 const int j) const
703{
704 ASSERTL2(i >= 0 && i <= 5, "face id is out of range");
705 ASSERTL2(j == 0 || j == 1, "face direction is out of range");
706
707 if (i == 0 || i == 5)
708 {
709 return m_base[j]->GetPointsKey();
710 }
711 else if (i == 1 || i == 3)
712 {
713 return m_base[2 * j]->GetPointsKey();
714 }
715 else
716 {
717 return m_base[j + 1]->GetPointsKey();
718 }
719}
720
722 const std::vector<unsigned int> &nummodes, int &modes_offset)
723{
724 int nmodes = nummodes[modes_offset] * nummodes[modes_offset + 1] *
725 nummodes[modes_offset + 2];
726 modes_offset += 3;
727
728 return nmodes;
729}
730
732 const int k) const
733{
734 ASSERTL2(i >= 0 && i <= 5, "face id is out of range");
735 ASSERTL2(k >= 0 && k <= 1, "basis key id is out of range");
736
737 int dir = k;
738 switch (i)
739 {
740 case 0:
741 case 5:
742 dir = k;
743 break;
744 case 1:
745 case 3:
746 dir = 2 * k;
747 break;
748 case 2:
749 case 4:
750 dir = k + 1;
751 break;
752 }
753
755 m_base[dir]->GetNumPoints(),
756 m_base[dir]->GetNumModes());
757}
758
762{
763 Array<OneD, const NekDouble> eta_x = m_base[0]->GetZ();
764 Array<OneD, const NekDouble> eta_y = m_base[1]->GetZ();
765 Array<OneD, const NekDouble> eta_z = m_base[2]->GetZ();
766 int Qx = GetNumPoints(0);
767 int Qy = GetNumPoints(1);
768 int Qz = GetNumPoints(2);
769
770 // Convert collapsed coordinates into cartesian coordinates:
771 // eta --> xi
772 for (int k = 0; k < Qz; ++k)
773 {
774 for (int j = 0; j < Qy; ++j)
775 {
776 for (int i = 0; i < Qx; ++i)
777 {
778 int s = i + Qx * (j + Qy * k);
779 xi_x[s] = eta_x[i];
780 xi_y[s] = eta_y[j];
781 xi_z[s] = eta_z[k];
782 }
783 }
784 }
785}
786
787void StdHexExp::v_GetTraceNumModes(const int fid, int &numModes0,
788 int &numModes1, Orientation faceOrient)
789{
790 int nummodes[3] = {m_base[0]->GetNumModes(), m_base[1]->GetNumModes(),
791 m_base[2]->GetNumModes()};
792 switch (fid)
793 {
794 case 0:
795 case 5:
796 {
797 numModes0 = nummodes[0];
798 numModes1 = nummodes[1];
799 }
800 break;
801 case 1:
802 case 3:
803 {
804 numModes0 = nummodes[0];
805 numModes1 = nummodes[2];
806 }
807 break;
808 case 2:
809 case 4:
810 {
811 numModes0 = nummodes[1];
812 numModes1 = nummodes[2];
813 }
814 break;
815 default:
816 {
817 ASSERTL0(false, "fid out of range");
818 }
819 break;
820 }
821
822 if (faceOrient >= eDir1FwdDir2_Dir2FwdDir1)
823 {
824 std::swap(numModes0, numModes1);
825 }
826}
827
828/**
829 * Expansions in each of the three dimensions must be of type
830 * LibUtilities#eModified_A or LibUtilities#eGLL_Lagrange.
831 *
832 * @param localVertexId ID of vertex (0..7)
833 * @returns Position of vertex in local numbering scheme.
834 */
835int StdHexExp::v_GetVertexMap(const int localVertexId, bool useCoeffPacking)
836{
839 "BasisType is not a boundary interior form");
842 "BasisType is not a boundary interior form");
845 "BasisType is not a boundary interior form");
846
847 ASSERTL1((localVertexId >= 0) && (localVertexId < 8),
848 "local vertex id must be between 0 and 7");
849
850 int p = 0;
851 int q = 0;
852 int r = 0;
853
854 // Retrieve the number of modes in each dimension.
855 int nummodes[3] = {m_base[0]->GetNumModes(), m_base[1]->GetNumModes(),
856 m_base[2]->GetNumModes()};
857
858 if (useCoeffPacking == true) // follow packing of coefficients i.e q,r,p
859 {
860 if (localVertexId > 3)
861 {
863 {
864 r = nummodes[2] - 1;
865 }
866 else
867 {
868 r = 1;
869 }
870 }
871
872 switch (localVertexId % 4)
873 {
874 case 0:
875 break;
876 case 1:
877 {
879 {
880 p = nummodes[0] - 1;
881 }
882 else
883 {
884 p = 1;
885 }
886 }
887 break;
888 case 2:
889 {
891 {
892 q = nummodes[1] - 1;
893 }
894 else
895 {
896 q = 1;
897 }
898 }
899 break;
900 case 3:
901 {
903 {
904 p = nummodes[0] - 1;
905 q = nummodes[1] - 1;
906 }
907 else
908 {
909 p = 1;
910 q = 1;
911 }
912 }
913 break;
914 }
915 }
916 else
917 {
918 // Right face (vertices 1,2,5,6)
919 if ((localVertexId % 4) % 3 > 0)
920 {
922 {
923 p = nummodes[0] - 1;
924 }
925 else
926 {
927 p = 1;
928 }
929 }
930 // Back face (vertices 2,3,6,7)
931 if (localVertexId % 4 > 1)
932 {
934 {
935 q = nummodes[1] - 1;
936 }
937 else
938 {
939 q = 1;
940 }
941 }
942
943 // Top face (vertices 4,5,6,7)
944 if (localVertexId > 3)
945 {
947 {
948 r = nummodes[2] - 1;
949 }
950 else
951 {
952 r = 1;
953 }
954 }
955 }
956 // Compute the local number.
957 return r * nummodes[0] * nummodes[1] + q * nummodes[0] + p;
958}
959
960/**
961 * @param outarray Storage area for computed map.
962 */
964{
967 "BasisType is not a boundary interior form");
970 "BasisType is not a boundary interior form");
973 "BasisType is not a boundary interior form");
974
975 int i;
976 int nummodes[3] = {m_base[0]->GetNumModes(), m_base[1]->GetNumModes(),
977 m_base[2]->GetNumModes()};
978
979 int nIntCoeffs = m_ncoeffs - NumBndryCoeffs();
980
981 if (outarray.size() != nIntCoeffs)
982 {
983 outarray = Array<OneD, unsigned int>(nIntCoeffs);
984 }
985
986 const LibUtilities::BasisType Btype[3] = {GetBasisType(0), GetBasisType(1),
987 GetBasisType(2)};
988
989 int p, q, r;
990 int cnt = 0;
991
992 int IntIdx[3][2];
993
994 for (i = 0; i < 3; i++)
995 {
996 if (Btype[i] == LibUtilities::eModified_A)
997 {
998 IntIdx[i][0] = 2;
999 IntIdx[i][1] = nummodes[i];
1000 }
1001 else
1002 {
1003 IntIdx[i][0] = 1;
1004 IntIdx[i][1] = nummodes[i] - 1;
1005 }
1006 }
1007
1008 for (r = IntIdx[2][0]; r < IntIdx[2][1]; r++)
1009 {
1010 for (q = IntIdx[1][0]; q < IntIdx[1][1]; q++)
1011 {
1012 for (p = IntIdx[0][0]; p < IntIdx[0][1]; p++)
1013 {
1014 outarray[cnt++] =
1015 r * nummodes[0] * nummodes[1] + q * nummodes[0] + p;
1016 }
1017 }
1018 }
1019}
1020
1021/**
1022 * @param outarray Storage for computed map.
1023 */
1025{
1028 "BasisType is not a boundary interior form");
1031 "BasisType is not a boundary interior form");
1034 "BasisType is not a boundary interior form");
1035
1036 int i;
1037 int nummodes[3] = {m_base[0]->GetNumModes(), m_base[1]->GetNumModes(),
1038 m_base[2]->GetNumModes()};
1039
1040 int nBndCoeffs = NumBndryCoeffs();
1041
1042 if (outarray.size() != nBndCoeffs)
1043 {
1044 outarray = Array<OneD, unsigned int>(nBndCoeffs);
1045 }
1046
1047 const LibUtilities::BasisType Btype[3] = {GetBasisType(0), GetBasisType(1),
1048 GetBasisType(2)};
1049
1050 int p, q, r;
1051 int cnt = 0;
1052
1053 int BndIdx[3][2];
1054 int IntIdx[3][2];
1055
1056 for (i = 0; i < 3; i++)
1057 {
1058 BndIdx[i][0] = 0;
1059
1060 if (Btype[i] == LibUtilities::eModified_A)
1061 {
1062 BndIdx[i][1] = 1;
1063 IntIdx[i][0] = 2;
1064 IntIdx[i][1] = nummodes[i];
1065 }
1066 else
1067 {
1068 BndIdx[i][1] = nummodes[i] - 1;
1069 IntIdx[i][0] = 1;
1070 IntIdx[i][1] = nummodes[i] - 1;
1071 }
1072 }
1073
1074 for (i = 0; i < 2; i++)
1075 {
1076 r = BndIdx[2][i];
1077 for (q = 0; q < nummodes[1]; q++)
1078 {
1079 for (p = 0; p < nummodes[0]; p++)
1080 {
1081 outarray[cnt++] =
1082 r * nummodes[0] * nummodes[1] + q * nummodes[0] + p;
1083 }
1084 }
1085 }
1086
1087 for (r = IntIdx[2][0]; r < IntIdx[2][1]; r++)
1088 {
1089 for (i = 0; i < 2; i++)
1090 {
1091 q = BndIdx[1][i];
1092 for (p = 0; p < nummodes[0]; p++)
1093 {
1094 outarray[cnt++] =
1095 r * nummodes[0] * nummodes[1] + q * nummodes[0] + p;
1096 }
1097 }
1098
1099 for (q = IntIdx[1][0]; q < IntIdx[1][1]; q++)
1100 {
1101 for (i = 0; i < 2; i++)
1102 {
1103 p = BndIdx[0][i];
1104 outarray[cnt++] =
1105 r * nummodes[0] * nummodes[1] + q * nummodes[0] + p;
1106 }
1107 }
1108 }
1109
1110 sort(outarray.get(), outarray.get() + nBndCoeffs);
1111}
1112
1114 const Array<OneD, const NekDouble> &inarray,
1115 std::array<NekDouble, 3> &firstOrderDerivs)
1116{
1117 return BaryTensorDeriv(coord, inarray, firstOrderDerivs);
1118}
1119
1120/**
1121 * Only for basis type Modified_A or GLL_LAGRANGE in all directions.
1122 */
1123void StdHexExp::v_GetTraceCoeffMap(const unsigned int fid,
1124 Array<OneD, unsigned int> &maparray)
1125{
1126 int i, j;
1127 int nummodesA = 0, nummodesB = 0;
1128
1130 GetBasisType(0) == GetBasisType(2),
1131 "Method only implemented if BasisType is indentical in "
1132 "all directions");
1135 "Method only implemented for Modified_A or "
1136 "GLL_Lagrange BasisType");
1137
1138 const int nummodes0 = m_base[0]->GetNumModes();
1139 const int nummodes1 = m_base[1]->GetNumModes();
1140 const int nummodes2 = m_base[2]->GetNumModes();
1141
1142 switch (fid)
1143 {
1144 case 0:
1145 case 5:
1146 nummodesA = nummodes0;
1147 nummodesB = nummodes1;
1148 break;
1149 case 1:
1150 case 3:
1151 nummodesA = nummodes0;
1152 nummodesB = nummodes2;
1153 break;
1154 case 2:
1155 case 4:
1156 nummodesA = nummodes1;
1157 nummodesB = nummodes2;
1158 break;
1159 default:
1160 ASSERTL0(false, "fid must be between 0 and 5");
1161 }
1162
1163 int nFaceCoeffs = nummodesA * nummodesB;
1164
1165 if (maparray.size() != nFaceCoeffs)
1166 {
1167 maparray = Array<OneD, unsigned int>(nFaceCoeffs);
1168 }
1169
1170 bool modified = (GetBasisType(0) == LibUtilities::eModified_A);
1171
1172 int offset = 0;
1173 int jump1 = 1;
1174 int jump2 = 1;
1175
1176 switch (fid)
1177 {
1178 case 5:
1179 {
1180 if (modified)
1181 {
1182 offset = nummodes0 * nummodes1;
1183 }
1184 else
1185 {
1186 offset = (nummodes2 - 1) * nummodes0 * nummodes1;
1187 jump1 = nummodes0;
1188 }
1189 }
1190 /* Falls through. */
1191 case 0:
1192 {
1193 jump1 = nummodes0;
1194 break;
1195 }
1196 case 3:
1197 {
1198 if (modified)
1199 {
1200 offset = nummodes0;
1201 }
1202 else
1203 {
1204 offset = nummodes0 * (nummodes1 - 1);
1205 jump1 = nummodes0 * nummodes1;
1206 }
1207 }
1208 /* Falls through. */
1209 case 1:
1210 {
1211 jump1 = nummodes0 * nummodes1;
1212 break;
1213 }
1214 case 2:
1215 {
1216 if (modified)
1217 {
1218 offset = 1;
1219 }
1220 else
1221 {
1222 offset = nummodes0 - 1;
1223 jump1 = nummodes0 * nummodes1;
1224 jump2 = nummodes0;
1225 }
1226 }
1227 /* Falls through. */
1228 case 4:
1229 {
1230 jump1 = nummodes0 * nummodes1;
1231 jump2 = nummodes0;
1232 break;
1233 }
1234 default:
1235 ASSERTL0(false, "fid must be between 0 and 5");
1236 }
1237
1238 for (i = 0; i < nummodesB; i++)
1239 {
1240 for (j = 0; j < nummodesA; j++)
1241 {
1242 maparray[i * nummodesA + j] = i * jump1 + j * jump2 + offset;
1243 }
1244 }
1245}
1246
1247void StdHexExp::v_GetElmtTraceToTraceMap(const unsigned int fid,
1248 Array<OneD, unsigned int> &maparray,
1249 Array<OneD, int> &signarray,
1250 Orientation faceOrient, int P, int Q)
1251{
1252 int i, j;
1253 int nummodesA = 0, nummodesB = 0;
1254
1256 GetBasisType(0) == GetBasisType(2),
1257 "Method only implemented if BasisType is indentical in "
1258 "all directions");
1261 "Method only implemented for Modified_A or "
1262 "GLL_Lagrange BasisType");
1263
1264 const int nummodes0 = m_base[0]->GetNumModes();
1265 const int nummodes1 = m_base[1]->GetNumModes();
1266 const int nummodes2 = m_base[2]->GetNumModes();
1267
1268 switch (fid)
1269 {
1270 case 0:
1271 case 5:
1272 nummodesA = nummodes0;
1273 nummodesB = nummodes1;
1274 break;
1275 case 1:
1276 case 3:
1277 nummodesA = nummodes0;
1278 nummodesB = nummodes2;
1279 break;
1280 case 2:
1281 case 4:
1282 nummodesA = nummodes1;
1283 nummodesB = nummodes2;
1284 break;
1285 default:
1286 ASSERTL0(false, "fid must be between 0 and 5");
1287 }
1288
1289 if (P == -1)
1290 {
1291 P = nummodesA;
1292 Q = nummodesB;
1293 }
1294
1295 bool modified = (GetBasisType(0) == LibUtilities::eModified_A);
1296
1297 // check that
1298 if (modified == false)
1299 {
1300 ASSERTL1((P == nummodesA) || (Q == nummodesB),
1301 "Different trace space face dimention "
1302 "and element face dimention not possible for "
1303 "GLL-Lagrange bases");
1304 }
1305
1306 int nFaceCoeffs = P * Q;
1307
1308 if (maparray.size() != nFaceCoeffs)
1309 {
1310 maparray = Array<OneD, unsigned int>(nFaceCoeffs);
1311 }
1312
1313 // fill default mapping as increasing index
1314 for (i = 0; i < nFaceCoeffs; ++i)
1315 {
1316 maparray[i] = i;
1317 }
1318
1319 if (signarray.size() != nFaceCoeffs)
1320 {
1321 signarray = Array<OneD, int>(nFaceCoeffs, 1);
1322 }
1323 else
1324 {
1325 fill(signarray.get(), signarray.get() + nFaceCoeffs, 1);
1326 }
1327
1328 // setup indexing to manage transpose directions
1329 Array<OneD, int> arrayindx(nFaceCoeffs);
1330 for (i = 0; i < Q; i++)
1331 {
1332 for (j = 0; j < P; j++)
1333 {
1334 if (faceOrient < eDir1FwdDir2_Dir2FwdDir1)
1335 {
1336 arrayindx[i * P + j] = i * P + j;
1337 }
1338 else
1339 {
1340 arrayindx[i * P + j] = j * Q + i;
1341 }
1342 }
1343 }
1344
1345 // zero signmap and set maparray to zero if elemental
1346 // modes are not as large as face models
1347 for (i = 0; i < nummodesB; i++)
1348 {
1349 for (j = nummodesA; j < P; j++)
1350 {
1351 signarray[arrayindx[i * P + j]] = 0.0;
1352 maparray[arrayindx[i * P + j]] = maparray[0];
1353 }
1354 }
1355
1356 for (i = nummodesB; i < Q; i++)
1357 {
1358 for (j = 0; j < P; j++)
1359 {
1360 signarray[arrayindx[i * P + j]] = 0.0;
1361 maparray[arrayindx[i * P + j]] = maparray[0];
1362 }
1363 }
1364
1365 // zero signmap and set maparray to zero entry if
1366 // elemental modes are not as large as face modesl
1367 for (i = 0; i < Q; i++)
1368 {
1369 // fill values into map array of trace size
1370 // for element face index
1371 for (j = 0; j < P; j++)
1372 {
1373 maparray[arrayindx[i * P + j]] = i * nummodesA + j;
1374 }
1375
1376 // zero values if P > numModesA
1377 for (j = nummodesA; j < P; j++)
1378 {
1379 signarray[arrayindx[i * P + j]] = 0.0;
1380 maparray[arrayindx[i * P + j]] = maparray[0];
1381 }
1382 }
1383
1384 // zero values if Q > numModesB
1385 for (i = nummodesB; i < Q; i++)
1386 {
1387 for (j = 0; j < P; j++)
1388 {
1389 signarray[arrayindx[i * P + j]] = 0.0;
1390 maparray[arrayindx[i * P + j]] = maparray[0];
1391 }
1392 }
1393
1394 // Now reorientate indices accordign to orientation
1395 if ((faceOrient == eDir1FwdDir1_Dir2BwdDir2) ||
1396 (faceOrient == eDir1BwdDir1_Dir2BwdDir2) ||
1397 (faceOrient == eDir1BwdDir2_Dir2FwdDir1) ||
1398 (faceOrient == eDir1BwdDir2_Dir2BwdDir1))
1399 {
1400 if (faceOrient < eDir1FwdDir2_Dir2FwdDir1)
1401 {
1402 if (modified)
1403 {
1404 for (int i = 3; i < Q; i += 2)
1405 {
1406 for (int j = 0; j < P; j++)
1407 {
1408 signarray[arrayindx[i * P + j]] *= -1;
1409 }
1410 }
1411
1412 for (int i = 0; i < P; i++)
1413 {
1414 swap(maparray[i], maparray[i + P]);
1415 swap(signarray[i], signarray[i + P]);
1416 }
1417 }
1418 else
1419 {
1420 for (int i = 0; i < P; i++)
1421 {
1422 for (int j = 0; j < Q / 2; j++)
1423 {
1424 swap(maparray[i + j * P],
1425 maparray[i + P * Q - P - j * P]);
1426 swap(signarray[i + j * P],
1427 signarray[i + P * Q - P - j * P]);
1428 }
1429 }
1430 }
1431 }
1432 else
1433 {
1434 if (modified)
1435 {
1436 for (int i = 0; i < Q; i++)
1437 {
1438 for (int j = 3; j < P; j += 2)
1439 {
1440 signarray[arrayindx[i * P + j]] *= -1;
1441 }
1442 }
1443
1444 for (int i = 0; i < Q; i++)
1445 {
1446 swap(maparray[i], maparray[i + Q]);
1447 swap(signarray[i], signarray[i + Q]);
1448 }
1449 }
1450 else
1451 {
1452 for (int i = 0; i < P; i++)
1453 {
1454 for (int j = 0; j < Q / 2; j++)
1455 {
1456 swap(maparray[i * Q + j], maparray[i * Q + Q - 1 - j]);
1457 swap(signarray[i * Q + j],
1458 signarray[i * Q + Q - 1 - j]);
1459 }
1460 }
1461 }
1462 }
1463 }
1464
1465 if ((faceOrient == eDir1BwdDir1_Dir2FwdDir2) ||
1466 (faceOrient == eDir1BwdDir1_Dir2BwdDir2) ||
1467 (faceOrient == eDir1FwdDir2_Dir2BwdDir1) ||
1468 (faceOrient == eDir1BwdDir2_Dir2BwdDir1))
1469 {
1470 if (faceOrient < eDir1FwdDir2_Dir2FwdDir1)
1471 {
1472 if (modified)
1473 {
1474 for (i = 0; i < Q; i++)
1475 {
1476 for (j = 3; j < P; j += 2)
1477 {
1478 signarray[arrayindx[i * P + j]] *= -1;
1479 }
1480 }
1481
1482 for (i = 0; i < Q; i++)
1483 {
1484 swap(maparray[i * P], maparray[i * P + 1]);
1485 swap(signarray[i * P], signarray[i * P + 1]);
1486 }
1487 }
1488 else
1489 {
1490 for (i = 0; i < Q; i++)
1491 {
1492 for (j = 0; j < P / 2; j++)
1493 {
1494 swap(maparray[i * P + j], maparray[i * P + P - 1 - j]);
1495 swap(signarray[i * P + j],
1496 signarray[i * P + P - 1 - j]);
1497 }
1498 }
1499 }
1500 }
1501 else
1502 {
1503 if (modified)
1504 {
1505 for (i = 3; i < Q; i += 2)
1506 {
1507 for (j = 0; j < P; j++)
1508 {
1509 signarray[arrayindx[i * P + j]] *= -1;
1510 }
1511 }
1512
1513 for (i = 0; i < P; i++)
1514 {
1515 swap(maparray[i * Q], maparray[i * Q + 1]);
1516 swap(signarray[i * Q], signarray[i * Q + 1]);
1517 }
1518 }
1519 else
1520 {
1521 for (i = 0; i < Q; i++)
1522 {
1523 for (j = 0; j < P / 2; j++)
1524 {
1525 swap(maparray[i + j * Q],
1526 maparray[i + P * Q - Q - j * Q]);
1527 swap(signarray[i + j * Q],
1528 signarray[i + P * Q - Q - j * Q]);
1529 }
1530 }
1531 }
1532 }
1533 }
1534}
1535
1536/**
1537 * @param eid The edge to compute the numbering for.
1538 * @param edgeOrient Orientation of the edge.
1539 * @param maparray Storage for computed mapping array.
1540 * @param signarray ?
1541 */
1543 const int eid, Array<OneD, unsigned int> &maparray,
1544 Array<OneD, int> &signarray, const Orientation edgeOrient)
1545{
1548 "BasisType is not a boundary interior form");
1551 "BasisType is not a boundary interior form");
1554 "BasisType is not a boundary interior form");
1555
1556 ASSERTL1((eid >= 0) && (eid < 12),
1557 "local edge id must be between 0 and 11");
1558
1559 int nEdgeIntCoeffs = GetEdgeNcoeffs(eid) - 2;
1560
1561 if (maparray.size() != nEdgeIntCoeffs)
1562 {
1563 maparray = Array<OneD, unsigned int>(nEdgeIntCoeffs);
1564 }
1565
1566 if (signarray.size() != nEdgeIntCoeffs)
1567 {
1568 signarray = Array<OneD, int>(nEdgeIntCoeffs, 1);
1569 }
1570 else
1571 {
1572 fill(signarray.get(), signarray.get() + nEdgeIntCoeffs, 1);
1573 }
1574
1575 int nummodes[3] = {m_base[0]->GetNumModes(), m_base[1]->GetNumModes(),
1576 m_base[2]->GetNumModes()};
1577
1578 const LibUtilities::BasisType bType[3] = {GetBasisType(0), GetBasisType(1),
1579 GetBasisType(2)};
1580
1581 bool reverseOrdering = false;
1582 bool signChange = false;
1583
1584 int IdxRange[3][2] = {{0, 0}, {0, 0}, {0, 0}};
1585
1586 switch (eid)
1587 {
1588 case 0:
1589 case 1:
1590 case 2:
1591 case 3:
1592 {
1593 IdxRange[2][0] = 0;
1594 IdxRange[2][1] = 1;
1595 }
1596 break;
1597 case 8:
1598 case 9:
1599 case 10:
1600 case 11:
1601 {
1602 if (bType[2] == LibUtilities::eGLL_Lagrange)
1603 {
1604 IdxRange[2][0] = nummodes[2] - 1;
1605 IdxRange[2][1] = nummodes[2];
1606 }
1607 else
1608 {
1609 IdxRange[2][0] = 1;
1610 IdxRange[2][1] = 2;
1611 }
1612 }
1613 break;
1614 case 4:
1615 case 5:
1616 case 6:
1617 case 7:
1618 {
1619 if (bType[2] == LibUtilities::eGLL_Lagrange)
1620 {
1621 IdxRange[2][0] = 1;
1622 IdxRange[2][1] = nummodes[2] - 1;
1623
1624 if (edgeOrient == eBackwards)
1625 {
1626 reverseOrdering = true;
1627 }
1628 }
1629 else
1630 {
1631 IdxRange[2][0] = 2;
1632 IdxRange[2][1] = nummodes[2];
1633
1634 if (edgeOrient == eBackwards)
1635 {
1636 signChange = true;
1637 }
1638 }
1639 }
1640 break;
1641 }
1642
1643 switch (eid)
1644 {
1645 case 0:
1646 case 4:
1647 case 5:
1648 case 8:
1649 {
1650 IdxRange[1][0] = 0;
1651 IdxRange[1][1] = 1;
1652 }
1653 break;
1654 case 2:
1655 case 6:
1656 case 7:
1657 case 10:
1658 {
1659 if (bType[1] == LibUtilities::eGLL_Lagrange)
1660 {
1661 IdxRange[1][0] = nummodes[1] - 1;
1662 IdxRange[1][1] = nummodes[1];
1663 }
1664 else
1665 {
1666 IdxRange[1][0] = 1;
1667 IdxRange[1][1] = 2;
1668 }
1669 }
1670 break;
1671 case 1:
1672 case 9:
1673 {
1674 if (bType[1] == LibUtilities::eGLL_Lagrange)
1675 {
1676 IdxRange[1][0] = 1;
1677 IdxRange[1][1] = nummodes[1] - 1;
1678
1679 if (edgeOrient == eBackwards)
1680 {
1681 reverseOrdering = true;
1682 }
1683 }
1684 else
1685 {
1686 IdxRange[1][0] = 2;
1687 IdxRange[1][1] = nummodes[1];
1688
1689 if (edgeOrient == eBackwards)
1690 {
1691 signChange = true;
1692 }
1693 }
1694 }
1695 break;
1696 case 3:
1697 case 11:
1698 {
1699 if (bType[1] == LibUtilities::eGLL_Lagrange)
1700 {
1701 IdxRange[1][0] = 1;
1702 IdxRange[1][1] = nummodes[1] - 1;
1703
1704 if (edgeOrient == eForwards)
1705 {
1706 reverseOrdering = true;
1707 }
1708 }
1709 else
1710 {
1711 IdxRange[1][0] = 2;
1712 IdxRange[1][1] = nummodes[1];
1713
1714 if (edgeOrient == eForwards)
1715 {
1716 signChange = true;
1717 }
1718 }
1719 }
1720 break;
1721 }
1722
1723 switch (eid)
1724 {
1725 case 3:
1726 case 4:
1727 case 7:
1728 case 11:
1729 {
1730 IdxRange[0][0] = 0;
1731 IdxRange[0][1] = 1;
1732 }
1733 break;
1734 case 1:
1735 case 5:
1736 case 6:
1737 case 9:
1738 {
1739 if (bType[0] == LibUtilities::eGLL_Lagrange)
1740 {
1741 IdxRange[0][0] = nummodes[0] - 1;
1742 IdxRange[0][1] = nummodes[0];
1743 }
1744 else
1745 {
1746 IdxRange[0][0] = 1;
1747 IdxRange[0][1] = 2;
1748 }
1749 }
1750 break;
1751 case 0:
1752 case 8:
1753 {
1754 if (bType[0] == LibUtilities::eGLL_Lagrange)
1755 {
1756 IdxRange[0][0] = 1;
1757 IdxRange[0][1] = nummodes[0] - 1;
1758
1759 if (edgeOrient == eBackwards)
1760 {
1761 reverseOrdering = true;
1762 }
1763 }
1764 else
1765 {
1766 IdxRange[0][0] = 2;
1767 IdxRange[0][1] = nummodes[0];
1768
1769 if (edgeOrient == eBackwards)
1770 {
1771 signChange = true;
1772 }
1773 }
1774 }
1775 break;
1776 case 2:
1777 case 10:
1778 {
1779 if (bType[0] == LibUtilities::eGLL_Lagrange)
1780 {
1781 IdxRange[0][0] = 1;
1782 IdxRange[0][1] = nummodes[0] - 1;
1783
1784 if (edgeOrient == eForwards)
1785 {
1786 reverseOrdering = true;
1787 }
1788 }
1789 else
1790 {
1791 IdxRange[0][0] = 2;
1792 IdxRange[0][1] = nummodes[0];
1793
1794 if (edgeOrient == eForwards)
1795 {
1796 signChange = true;
1797 }
1798 }
1799 }
1800 break;
1801 }
1802
1803 int cnt = 0;
1804
1805 for (int r = IdxRange[2][0]; r < IdxRange[2][1]; r++)
1806 {
1807 for (int q = IdxRange[1][0]; q < IdxRange[1][1]; q++)
1808 {
1809 for (int p = IdxRange[0][0]; p < IdxRange[0][1]; p++)
1810 {
1811 maparray[cnt++] =
1812 r * nummodes[0] * nummodes[1] + q * nummodes[0] + p;
1813 }
1814 }
1815 }
1816
1817 if (reverseOrdering)
1818 {
1819 reverse(maparray.get(), maparray.get() + nEdgeIntCoeffs);
1820 }
1821
1822 if (signChange)
1823 {
1824 for (int p = 1; p < nEdgeIntCoeffs; p += 2)
1825 {
1826 signarray[p] = -1;
1827 }
1828 }
1829}
1830
1831/**
1832 * Generate mapping describing which elemental modes lie on the
1833 * interior of a given face. Accounts for face orientation.
1834 */
1836 const int fid, Array<OneD, unsigned int> &maparray,
1837 Array<OneD, int> &signarray, const Orientation faceOrient)
1838{
1841 "BasisType is not a boundary interior form");
1844 "BasisType is not a boundary interior form");
1847 "BasisType is not a boundary interior form");
1848
1849 ASSERTL1((fid >= 0) && (fid < 6), "local face id must be between 0 and 5");
1850
1851 int nFaceIntCoeffs = v_GetTraceIntNcoeffs(fid);
1852
1853 if (maparray.size() != nFaceIntCoeffs)
1854 {
1855 maparray = Array<OneD, unsigned int>(nFaceIntCoeffs);
1856 }
1857
1858 if (signarray.size() != nFaceIntCoeffs)
1859 {
1860 signarray = Array<OneD, int>(nFaceIntCoeffs, 1);
1861 }
1862 else
1863 {
1864 fill(signarray.get(), signarray.get() + nFaceIntCoeffs, 1);
1865 }
1866
1867 int nummodes[3] = {m_base[0]->GetNumModes(), m_base[1]->GetNumModes(),
1868 m_base[2]->GetNumModes()};
1869
1870 const LibUtilities::BasisType bType[3] = {GetBasisType(0), GetBasisType(1),
1871 GetBasisType(2)};
1872
1873 int nummodesA = 0;
1874 int nummodesB = 0;
1875
1876 // Determine the number of modes in face directions A & B based
1877 // on the face index given.
1878 switch (fid)
1879 {
1880 case 0:
1881 case 5:
1882 {
1883 nummodesA = nummodes[0];
1884 nummodesB = nummodes[1];
1885 }
1886 break;
1887 case 1:
1888 case 3:
1889 {
1890 nummodesA = nummodes[0];
1891 nummodesB = nummodes[2];
1892 }
1893 break;
1894 case 2:
1895 case 4:
1896 {
1897 nummodesA = nummodes[1];
1898 nummodesB = nummodes[2];
1899 }
1900 }
1901
1902 Array<OneD, int> arrayindx(nFaceIntCoeffs);
1903
1904 // Create a mapping array to account for transposition of the
1905 // coordinates due to face orientation.
1906 for (int i = 0; i < (nummodesB - 2); i++)
1907 {
1908 for (int j = 0; j < (nummodesA - 2); j++)
1909 {
1910 if (faceOrient < eDir1FwdDir2_Dir2FwdDir1)
1911 {
1912 arrayindx[i * (nummodesA - 2) + j] = i * (nummodesA - 2) + j;
1913 }
1914 else
1915 {
1916 arrayindx[i * (nummodesA - 2) + j] = j * (nummodesB - 2) + i;
1917 }
1918 }
1919 }
1920
1921 int IdxRange[3][2];
1922 int Incr[3];
1923
1924 Array<OneD, int> sign0(nummodes[0], 1);
1925 Array<OneD, int> sign1(nummodes[1], 1);
1926 Array<OneD, int> sign2(nummodes[2], 1);
1927
1928 // Set the upper and lower bounds, and increment for the faces
1929 // involving the first coordinate direction.
1930 switch (fid)
1931 {
1932 case 0: // bottom face
1933 {
1934 IdxRange[2][0] = 0;
1935 IdxRange[2][1] = 1;
1936 Incr[2] = 1;
1937 }
1938 break;
1939 case 5: // top face
1940 {
1941 if (bType[2] == LibUtilities::eGLL_Lagrange)
1942 {
1943 IdxRange[2][0] = nummodes[2] - 1;
1944 IdxRange[2][1] = nummodes[2];
1945 Incr[2] = 1;
1946 }
1947 else
1948 {
1949 IdxRange[2][0] = 1;
1950 IdxRange[2][1] = 2;
1951 Incr[2] = 1;
1952 }
1953 }
1954 break;
1955 default: // all other faces
1956 {
1957 if (bType[2] == LibUtilities::eGLL_Lagrange)
1958 {
1959 if (((int)(faceOrient - eDir1FwdDir1_Dir2FwdDir2)) % 2)
1960 {
1961 IdxRange[2][0] = nummodes[2] - 2;
1962 IdxRange[2][1] = 0;
1963 Incr[2] = -1;
1964 }
1965 else
1966 {
1967 IdxRange[2][0] = 1;
1968 IdxRange[2][1] = nummodes[2] - 1;
1969 Incr[2] = 1;
1970 }
1971 }
1972 else
1973 {
1974 IdxRange[2][0] = 2;
1975 IdxRange[2][1] = nummodes[2];
1976 Incr[2] = 1;
1977
1978 if (((int)(faceOrient - eDir1FwdDir1_Dir2FwdDir2)) % 2)
1979 {
1980 for (int i = 3; i < nummodes[2]; i += 2)
1981 {
1982 sign2[i] = -1;
1983 }
1984 }
1985 }
1986 }
1987 }
1988
1989 // Set the upper and lower bounds, and increment for the faces
1990 // involving the second coordinate direction.
1991 switch (fid)
1992 {
1993 case 1:
1994 {
1995 IdxRange[1][0] = 0;
1996 IdxRange[1][1] = 1;
1997 Incr[1] = 1;
1998 }
1999 break;
2000 case 3:
2001 {
2002 if (bType[1] == LibUtilities::eGLL_Lagrange)
2003 {
2004 IdxRange[1][0] = nummodes[1] - 1;
2005 IdxRange[1][1] = nummodes[1];
2006 Incr[1] = 1;
2007 }
2008 else
2009 {
2010 IdxRange[1][0] = 1;
2011 IdxRange[1][1] = 2;
2012 Incr[1] = 1;
2013 }
2014 }
2015 break;
2016 case 0:
2017 case 5:
2018 {
2019 if (bType[1] == LibUtilities::eGLL_Lagrange)
2020 {
2021 if (((int)(faceOrient - eDir1FwdDir1_Dir2FwdDir2)) % 2)
2022 {
2023 IdxRange[1][0] = nummodes[1] - 2;
2024 IdxRange[1][1] = 0;
2025 Incr[1] = -1;
2026 }
2027 else
2028 {
2029 IdxRange[1][0] = 1;
2030 IdxRange[1][1] = nummodes[1] - 1;
2031 Incr[1] = 1;
2032 }
2033 }
2034 else
2035 {
2036 IdxRange[1][0] = 2;
2037 IdxRange[1][1] = nummodes[1];
2038 Incr[1] = 1;
2039
2040 if (((int)(faceOrient - eDir1FwdDir1_Dir2FwdDir2)) % 2)
2041 {
2042 for (int i = 3; i < nummodes[1]; i += 2)
2043 {
2044 sign1[i] = -1;
2045 }
2046 }
2047 }
2048 }
2049 break;
2050 default: // case2: case4:
2051 {
2052 if (bType[1] == LibUtilities::eGLL_Lagrange)
2053 {
2054 if (((int)(faceOrient - eDir1FwdDir1_Dir2FwdDir2)) % 4 > 1)
2055 {
2056 IdxRange[1][0] = nummodes[1] - 2;
2057 IdxRange[1][1] = 0;
2058 Incr[1] = -1;
2059 }
2060 else
2061 {
2062 IdxRange[1][0] = 1;
2063 IdxRange[1][1] = nummodes[1] - 1;
2064 Incr[1] = 1;
2065 }
2066 }
2067 else
2068 {
2069 IdxRange[1][0] = 2;
2070 IdxRange[1][1] = nummodes[1];
2071 Incr[1] = 1;
2072
2073 if (((int)(faceOrient - eDir1FwdDir1_Dir2FwdDir2)) % 4 > 1)
2074 {
2075 for (int i = 3; i < nummodes[1]; i += 2)
2076 {
2077 sign1[i] = -1;
2078 }
2079 }
2080 }
2081 }
2082 }
2083
2084 switch (fid)
2085 {
2086 case 4:
2087 {
2088 IdxRange[0][0] = 0;
2089 IdxRange[0][1] = 1;
2090 Incr[0] = 1;
2091 }
2092 break;
2093 case 2:
2094 {
2095 if (bType[0] == LibUtilities::eGLL_Lagrange)
2096 {
2097 IdxRange[0][0] = nummodes[0] - 1;
2098 IdxRange[0][1] = nummodes[0];
2099 Incr[0] = 1;
2100 }
2101 else
2102 {
2103 IdxRange[0][0] = 1;
2104 IdxRange[0][1] = 2;
2105 Incr[0] = 1;
2106 }
2107 }
2108 break;
2109 default:
2110 {
2111 if (bType[0] == LibUtilities::eGLL_Lagrange)
2112 {
2113 if (((int)(faceOrient - eDir1FwdDir1_Dir2FwdDir2)) % 4 > 1)
2114 {
2115 IdxRange[0][0] = nummodes[0] - 2;
2116 IdxRange[0][1] = 0;
2117 Incr[0] = -1;
2118 }
2119 else
2120 {
2121 IdxRange[0][0] = 1;
2122 IdxRange[0][1] = nummodes[0] - 1;
2123 Incr[0] = 1;
2124 }
2125 }
2126 else
2127 {
2128 IdxRange[0][0] = 2;
2129 IdxRange[0][1] = nummodes[0];
2130 Incr[0] = 1;
2131
2132 if (((int)(faceOrient - eDir1FwdDir1_Dir2FwdDir2)) % 4 > 1)
2133 {
2134 for (int i = 3; i < nummodes[0]; i += 2)
2135 {
2136 sign0[i] = -1;
2137 }
2138 }
2139 }
2140 }
2141 }
2142
2143 int cnt = 0;
2144
2145 for (int r = IdxRange[2][0]; r != IdxRange[2][1]; r += Incr[2])
2146 {
2147 for (int q = IdxRange[1][0]; q != IdxRange[1][1]; q += Incr[1])
2148 {
2149 for (int p = IdxRange[0][0]; p != IdxRange[0][1]; p += Incr[0])
2150 {
2151 maparray[arrayindx[cnt]] =
2152 r * nummodes[0] * nummodes[1] + q * nummodes[0] + p;
2153 signarray[arrayindx[cnt++]] = sign0[p] * sign1[q] * sign2[r];
2154 }
2155 }
2156 }
2157}
2158
2159int StdHexExp::v_GetEdgeNcoeffs(const int i) const
2160{
2161 ASSERTL2((i >= 0) && (i <= 11), "edge id is out of range");
2162
2163 if ((i == 0) || (i == 2) || (i == 8) || (i == 10))
2164 {
2165 return GetBasisNumModes(0);
2166 }
2167 else if ((i == 1) || (i == 3) || (i == 9) || (i == 11))
2168 {
2169 return GetBasisNumModes(1);
2170 }
2171 else
2172 {
2173 return GetBasisNumModes(2);
2174 }
2175}
2176
2178{
2179
2180 MatrixType mtype = mkey.GetMatrixType();
2181
2182 DNekMatSharedPtr Mat;
2183
2184 switch (mtype)
2185 {
2187 {
2188 int nq0 = m_base[0]->GetNumPoints();
2189 int nq1 = m_base[1]->GetNumPoints();
2190 int nq2 = m_base[2]->GetNumPoints();
2191 int nq;
2192
2193 // take definition from key
2195 {
2196 nq = (int)mkey.GetConstFactor(eFactorConst);
2197 }
2198 else
2199 {
2200 nq = max(nq0, max(nq1, nq2));
2201 }
2202
2203 int neq =
2206 Array<OneD, NekDouble> coll(3);
2208 Array<OneD, NekDouble> tmp(nq0);
2209
2210 Mat =
2211 MemoryManager<DNekMat>::AllocateSharedPtr(neq, nq0 * nq1 * nq2);
2212 int cnt = 0;
2213
2214 for (int i = 0; i < nq; ++i)
2215 {
2216 for (int j = 0; j < nq; ++j)
2217 {
2218 for (int k = 0; k < nq; ++k, ++cnt)
2219 {
2220 coords[cnt] = Array<OneD, NekDouble>(3);
2221 coords[cnt][0] = -1.0 + 2 * k / (NekDouble)(nq - 1);
2222 coords[cnt][1] = -1.0 + 2 * j / (NekDouble)(nq - 1);
2223 coords[cnt][2] = -1.0 + 2 * i / (NekDouble)(nq - 1);
2224 }
2225 }
2226 }
2227
2228 for (int i = 0; i < neq; ++i)
2229 {
2230 LocCoordToLocCollapsed(coords[i], coll);
2231
2232 I[0] = m_base[0]->GetI(coll);
2233 I[1] = m_base[1]->GetI(coll + 1);
2234 I[2] = m_base[2]->GetI(coll + 2);
2235
2236 // interpolate first coordinate direction
2237 NekDouble fac;
2238 for (int k = 0; k < nq2; ++k)
2239 {
2240 for (int j = 0; j < nq1; ++j)
2241 {
2242
2243 fac = (I[1]->GetPtr())[j] * (I[2]->GetPtr())[k];
2244 Vmath::Smul(nq0, fac, I[0]->GetPtr(), 1, tmp, 1);
2245
2246 Vmath::Vcopy(nq0, &tmp[0], 1,
2247 Mat->GetRawPtr() + k * nq0 * nq1 * neq +
2248 j * nq0 * neq + i,
2249 neq);
2250 }
2251 }
2252 }
2253 }
2254 break;
2255 default:
2256 {
2258 }
2259 break;
2260 }
2261
2262 return Mat;
2263}
2264
2266{
2267 return v_GenMatrix(mkey);
2268}
2269
2271 Array<OneD, NekDouble> &outarray,
2272 const StdMatrixKey &mkey)
2273{
2274 StdExpansion::MassMatrixOp_MatFree(inarray, outarray, mkey);
2275}
2276
2278 Array<OneD, NekDouble> &outarray,
2279 const StdMatrixKey &mkey)
2280{
2281 StdHexExp::v_LaplacianMatrixOp_MatFree(inarray, outarray, mkey);
2282}
2283
2284void StdHexExp::v_LaplacianMatrixOp(const int k1, const int k2,
2285 const Array<OneD, const NekDouble> &inarray,
2286 Array<OneD, NekDouble> &outarray,
2287 const StdMatrixKey &mkey)
2288{
2289 StdExpansion::LaplacianMatrixOp_MatFree(k1, k2, inarray, outarray, mkey);
2290}
2291
2293 const Array<OneD, const NekDouble> &inarray,
2294 Array<OneD, NekDouble> &outarray,
2295 const StdMatrixKey &mkey)
2296{
2297 StdExpansion::WeakDerivMatrixOp_MatFree(i, inarray, outarray, mkey);
2298}
2299
2301 Array<OneD, NekDouble> &outarray,
2302 const StdMatrixKey &mkey)
2303{
2304 StdHexExp::v_HelmholtzMatrixOp_MatFree(inarray, outarray, mkey);
2305}
2306
2308 const Array<OneD, const NekDouble> &inarray,
2309 Array<OneD, NekDouble> &outarray)
2310{
2311 int nquad0 = m_base[0]->GetNumPoints();
2312 int nquad1 = m_base[1]->GetNumPoints();
2313 int nquad2 = m_base[2]->GetNumPoints();
2314 int nq01 = nquad0 * nquad1;
2315 int nq12 = nquad1 * nquad2;
2316
2317 const Array<OneD, const NekDouble> &w0 = m_base[0]->GetW();
2318 const Array<OneD, const NekDouble> &w1 = m_base[1]->GetW();
2319 const Array<OneD, const NekDouble> &w2 = m_base[2]->GetW();
2320
2321 for (int i = 0; i < nq12; ++i)
2322 {
2323 Vmath::Vmul(nquad0, inarray.get() + i * nquad0, 1, w0.get(), 1,
2324 outarray.get() + i * nquad0, 1);
2325 }
2326
2327 for (int i = 0; i < nq12; ++i)
2328 {
2329 Vmath::Smul(nquad0, w1[i % nquad1], outarray.get() + i * nquad0, 1,
2330 outarray.get() + i * nquad0, 1);
2331 }
2332
2333 for (int i = 0; i < nquad2; ++i)
2334 {
2335 Vmath::Smul(nq01, w2[i], outarray.get() + i * nq01, 1,
2336 outarray.get() + i * nq01, 1);
2337 }
2338}
2339
2341 const StdMatrixKey &mkey)
2342{
2343 // Generate an orthonogal expansion
2344 int qa = m_base[0]->GetNumPoints();
2345 int qb = m_base[1]->GetNumPoints();
2346 int qc = m_base[2]->GetNumPoints();
2347 int nmodes_a = m_base[0]->GetNumModes();
2348 int nmodes_b = m_base[1]->GetNumModes();
2349 int nmodes_c = m_base[2]->GetNumModes();
2350 // Declare orthogonal basis.
2354
2358 StdHexExp OrthoExp(Ba, Bb, Bc);
2359
2360 Array<OneD, NekDouble> orthocoeffs(OrthoExp.GetNcoeffs());
2361 int cnt = 0;
2362
2363 // project onto modal space.
2364 OrthoExp.FwdTrans(array, orthocoeffs);
2365
2367 {
2368 // Rodrigo's power kernel
2370 NekDouble SvvDiffCoeff =
2373
2374 for (int i = 0; i < nmodes_a; ++i)
2375 {
2376 for (int j = 0; j < nmodes_b; ++j)
2377 {
2378 NekDouble fac1 = std::max(
2379 pow((1.0 * i) / (nmodes_a - 1), cutoff * nmodes_a),
2380 pow((1.0 * j) / (nmodes_b - 1), cutoff * nmodes_b));
2381
2382 for (int k = 0; k < nmodes_c; ++k)
2383 {
2384 NekDouble fac =
2385 std::max(fac1, pow((1.0 * k) / (nmodes_c - 1),
2386 cutoff * nmodes_c));
2387
2388 orthocoeffs[cnt] *= SvvDiffCoeff * fac;
2389 cnt++;
2390 }
2391 }
2392 }
2393 }
2394 else if (mkey.ConstFactorExists(
2395 eFactorSVVDGKerDiffCoeff)) // Rodrigo/Mansoor's DG Kernel
2396 {
2399
2400 int max_abc = max(nmodes_a - kSVVDGFiltermodesmin,
2401 nmodes_b - kSVVDGFiltermodesmin);
2402 max_abc = max(max_abc, nmodes_c - kSVVDGFiltermodesmin);
2403 // clamp max_abc
2404 max_abc = max(max_abc, 0);
2405 max_abc = min(max_abc, kSVVDGFiltermodesmax - kSVVDGFiltermodesmin);
2406
2407 for (int i = 0; i < nmodes_a; ++i)
2408 {
2409 for (int j = 0; j < nmodes_b; ++j)
2410 {
2411 int maxij = max(i, j);
2412
2413 for (int k = 0; k < nmodes_c; ++k)
2414 {
2415 int maxijk = max(maxij, k);
2416 maxijk = min(maxijk, kSVVDGFiltermodesmax - 1);
2417
2418 orthocoeffs[cnt] *=
2419 SvvDiffCoeff * kSVVDGFilter[max_abc][maxijk];
2420 cnt++;
2421 }
2422 }
2423 }
2424 }
2425 else
2426 {
2427
2428 int cutoff = (int)(mkey.GetConstFactor(eFactorSVVCutoffRatio) *
2429 min(nmodes_a, nmodes_b));
2430 NekDouble SvvDiffCoeff = mkey.GetConstFactor(eFactorSVVDiffCoeff);
2431 // Filter just trilinear space
2432 int nmodes = max(nmodes_a, nmodes_b);
2433 nmodes = max(nmodes, nmodes_c);
2434
2435 Array<OneD, NekDouble> fac(nmodes, 1.0);
2436 for (int j = cutoff; j < nmodes; ++j)
2437 {
2438 fac[j] = fabs((j - nmodes) / ((NekDouble)(j - cutoff + 1.0)));
2439 fac[j] *= fac[j]; // added this line to conform with equation
2440 }
2441
2442 for (int i = 0; i < nmodes_a; ++i)
2443 {
2444 for (int j = 0; j < nmodes_b; ++j)
2445 {
2446 for (int k = 0; k < nmodes_c; ++k)
2447 {
2448 if ((i >= cutoff) || (j >= cutoff) || (k >= cutoff))
2449 {
2450 orthocoeffs[i * nmodes_a * nmodes_b + j * nmodes_c +
2451 k] *=
2452 (SvvDiffCoeff * exp(-(fac[i] + fac[j] + fac[k])));
2453 }
2454 else
2455 {
2456 orthocoeffs[i * nmodes_a * nmodes_b + j * nmodes_c +
2457 k] *= 0.0;
2458 }
2459 }
2460 }
2461 }
2462 }
2463
2464 // backward transform to physical space
2465 OrthoExp.BwdTrans(orthocoeffs, array);
2466}
2467
2469 const NekDouble alpha,
2470 const NekDouble exponent,
2471 const NekDouble cutoff)
2472{
2473 // Generate an orthogonal expansion
2474 int qa = m_base[0]->GetNumPoints();
2475 int qb = m_base[1]->GetNumPoints();
2476 int qc = m_base[2]->GetNumPoints();
2477 int nmodesA = m_base[0]->GetNumModes();
2478 int nmodesB = m_base[1]->GetNumModes();
2479 int nmodesC = m_base[2]->GetNumModes();
2480 int P = nmodesA - 1;
2481 int Q = nmodesB - 1;
2482 int R = nmodesC - 1;
2483
2484 // Declare orthogonal basis.
2488
2492 StdHexExp OrthoExp(Ba, Bb, Bc);
2493
2494 // Cutoff
2495 int Pcut = cutoff * P;
2496 int Qcut = cutoff * Q;
2497 int Rcut = cutoff * R;
2498
2499 // Project onto orthogonal space.
2500 Array<OneD, NekDouble> orthocoeffs(OrthoExp.GetNcoeffs());
2501 OrthoExp.FwdTrans(array, orthocoeffs);
2502
2503 //
2504 NekDouble fac, fac1, fac2, fac3;
2505 int index = 0;
2506 for (int i = 0; i < nmodesA; ++i)
2507 {
2508 for (int j = 0; j < nmodesB; ++j)
2509 {
2510 for (int k = 0; k < nmodesC; ++k, ++index)
2511 {
2512 // to filter out only the "high-modes"
2513 if (i > Pcut || j > Qcut || k > Rcut)
2514 {
2515 fac1 = (NekDouble)(i - Pcut) / ((NekDouble)(P - Pcut));
2516 fac2 = (NekDouble)(j - Qcut) / ((NekDouble)(Q - Qcut));
2517 fac3 = (NekDouble)(k - Rcut) / ((NekDouble)(R - Rcut));
2518 fac = max(max(fac1, fac2), fac3);
2519 fac = pow(fac, exponent);
2520 orthocoeffs[index] *= exp(-alpha * fac);
2521 }
2522 }
2523 }
2524 }
2525
2526 // backward transform to physical space
2527 OrthoExp.BwdTrans(orthocoeffs, array);
2528}
2529
2531 Array<OneD, int> &conn, [[maybe_unused]] bool standard)
2532{
2533 int np0 = m_base[0]->GetNumPoints();
2534 int np1 = m_base[1]->GetNumPoints();
2535 int np2 = m_base[2]->GetNumPoints();
2536 int np = max(np0, max(np1, np2));
2537
2538 conn = Array<OneD, int>(6 * (np - 1) * (np - 1) * (np - 1));
2539
2540 int row = 0;
2541 int rowp1 = 0;
2542 int cnt = 0;
2543 int plane = 0;
2544 for (int i = 0; i < np - 1; ++i)
2545 {
2546 for (int j = 0; j < np - 1; ++j)
2547 {
2548 rowp1 += np;
2549 for (int k = 0; k < np - 1; ++k)
2550 {
2551 conn[cnt++] = plane + row + k;
2552 conn[cnt++] = plane + row + k + 1;
2553 conn[cnt++] = plane + rowp1 + k;
2554
2555 conn[cnt++] = plane + rowp1 + k + 1;
2556 conn[cnt++] = plane + rowp1 + k;
2557 conn[cnt++] = plane + row + k + 1;
2558 }
2559 row += np;
2560 }
2561 plane += np * np;
2562 }
2563}
2564} // namespace Nektar::StdRegions
#define ASSERTL0(condition, msg)
Definition: ErrorUtil.hpp:208
#define ASSERTL1(condition, msg)
Assert Level 1 – Debugging which is used whether in FULLDEBUG or DEBUG compilation mode....
Definition: ErrorUtil.hpp:242
#define ASSERTL2(condition, msg)
Assert Level 2 – Debugging which is used FULLDEBUG compilation mode. This level assert is designed to...
Definition: ErrorUtil.hpp:265
Describes the specification for a Basis.
Definition: Basis.h:45
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)
int GetEdgeNcoeffs(const int i) const
This function returns the number of expansion coefficients belonging to the i-th edge.
void v_HelmholtzMatrixOp_MatFree(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray, const StdRegions::StdMatrixKey &mkey) override
NekDouble BaryTensorDeriv(const Array< OneD, NekDouble > &coord, const Array< OneD, const NekDouble > &inarray, std::array< NekDouble, 3 > &firstOrderDerivs)
void v_LaplacianMatrixOp_MatFree(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray, const StdRegions::StdMatrixKey &mkey) override
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.
Definition: StdExpansion.h:65
int GetNcoeffs(void) const
This function returns the total number of coefficients used in the expansion.
Definition: StdExpansion.h:124
void WeakDerivMatrixOp_MatFree(const int i, const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray, const StdMatrixKey &mkey)
LibUtilities::BasisType GetBasisType(const int dir) const
This function returns the type of basis used in the dir direction.
Definition: StdExpansion.h:156
DNekMatSharedPtr GetStdMatrix(const StdMatrixKey &mkey)
Definition: StdExpansion.h:603
void LocCoordToLocCollapsed(const Array< OneD, const NekDouble > &xi, Array< OneD, NekDouble > &eta)
Convert local cartesian coordinate xi into local collapsed coordinates eta.
void BwdTrans_SumFac(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray)
void IProductWRTDerivBase_SumFac(const int dir, const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray)
DNekMatSharedPtr CreateGeneralMatrix(const StdMatrixKey &mkey)
this function generates the mass matrix
void IProductWRTBase(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray)
this function calculates the inner product of a given function f with the different modes of the expa...
Definition: StdExpansion.h:528
void LaplacianMatrixOp_MatFree(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray, const StdMatrixKey &mkey)
LibUtilities::ShapeType DetShapeType() const
This function returns the shape of the expansion domain.
Definition: StdExpansion.h:367
void BwdTrans(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray)
This function performs the Backward transformation from coefficient space to physical space.
Definition: StdExpansion.h:424
LibUtilities::PointsType GetPointsType(const int dir) const
This function returns the type of quadrature points used in the dir direction.
Definition: StdExpansion.h:205
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.
Definition: StdExpansion.h:218
void MultiplyByQuadratureMetric(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray)
Definition: StdExpansion.h:723
int GetBasisNumModes(const int dir) const
This function returns the number of expansion modes in the dir direction.
Definition: StdExpansion.h:169
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)
Definition: StdExpansion.h:849
Array< OneD, LibUtilities::BasisSharedPtr > m_base
void MassMatrixOp_MatFree(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray, const StdMatrixKey &mkey)
Class representing a hexehedral element in reference space.
Definition: StdHexExp.h:44
int v_NumDGBndryCoeffs() const override
Definition: StdHexExp.cpp:630
void v_MassMatrixOp(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray, const StdMatrixKey &mkey) override
Definition: StdHexExp.cpp:2270
void v_MultiplyByStdQuadratureMetric(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray) override
Definition: StdHexExp.cpp:2307
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
Differentiation Methods.
Definition: StdHexExp.cpp:72
void v_ExponentialFilter(Array< OneD, NekDouble > &array, const NekDouble alpha, const NekDouble exponent, const NekDouble cutoff) override
Definition: StdHexExp.cpp:2468
int v_GetVertexMap(int localVertexId, bool useCoeffPacking=false) override
Definition: StdHexExp.cpp:835
void v_LocCoordToLocCollapsed(const Array< OneD, const NekDouble > &xi, Array< OneD, NekDouble > &eta) override
Definition: StdHexExp.cpp:505
int v_CalcNumberOfCoefficients(const std::vector< unsigned int > &nummodes, int &modes_offset) override
Definition: StdHexExp.cpp:721
LibUtilities::PointsKey v_GetTracePointsKey(const int i, const int j) const override
Definition: StdHexExp.cpp:701
NekDouble v_PhysEvaluateBasis(const Array< OneD, const NekDouble > &coords, int mode) final
Definition: StdHexExp.cpp:569
void v_GetTraceInteriorToElementMap(const int tid, Array< OneD, unsigned int > &maparray, Array< OneD, int > &signarray, const Orientation traceOrient=eDir1FwdDir1_Dir2FwdDir2) override
Definition: StdHexExp.cpp:1835
void v_IProductWRTDerivBase_SumFac(const int dir, const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray) override
Definition: StdHexExp.cpp:459
DNekMatSharedPtr v_CreateStdMatrix(const StdMatrixKey &mkey) override
Definition: StdHexExp.cpp:2265
NekDouble v_PhysEvaluate(const Array< OneD, NekDouble > &coord, const Array< OneD, const NekDouble > &inarray, std::array< NekDouble, 3 > &firstOrderDerivs) override
Definition: StdHexExp.cpp:1113
int v_GetEdgeNcoeffs(const int i) const override
Definition: StdHexExp.cpp:2159
void v_IProductWRTBase_SumFac(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray, bool multbyweights=true) override
Definition: StdHexExp.cpp:337
StdHexExp(const LibUtilities::BasisKey &Ba, const LibUtilities::BasisKey &Bb, const LibUtilities::BasisKey &Bc)
Definition: StdHexExp.cpp:45
int v_GetTraceNumPoints(const int i) const override
Definition: StdHexExp.cpp:683
const LibUtilities::BasisKey v_GetTraceBasisKey(const int i, const int k) const override
Definition: StdHexExp.cpp:731
void v_GetTraceCoeffMap(const unsigned int fid, Array< OneD, unsigned int > &maparray) override
Definition: StdHexExp.cpp:1123
LibUtilities::ShapeType v_DetShapeType() const override
Definition: StdHexExp.cpp:605
void v_GetTraceNumModes(const int fid, int &numModes0, int &numModes1, Orientation faceOrient=eDir1FwdDir1_Dir2FwdDir2) override
Definition: StdHexExp.cpp:787
void v_LocCollapsedToLocCoord(const Array< OneD, const NekDouble > &eta, Array< OneD, NekDouble > &xi) override
Definition: StdHexExp.cpp:513
void v_LaplacianMatrixOp(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray, const StdMatrixKey &mkey) override
Definition: StdHexExp.cpp:2277
int v_NumBndryCoeffs() const override
Definition: StdHexExp.cpp:610
int v_GetNedges() const override
Definition: StdHexExp.cpp:595
void v_FwdTrans(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray) override
Definition: StdHexExp.cpp:262
int v_GetNtraces() const override
Definition: StdHexExp.cpp:600
void v_HelmholtzMatrixOp(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray, const StdMatrixKey &mkey) override
Definition: StdHexExp.cpp:2300
int v_GetNverts() const override
Definition: StdHexExp.cpp:590
bool v_IsBoundaryInteriorExpansion() const override
Definition: StdHexExp.cpp:55
void v_GetInteriorMap(Array< OneD, unsigned int > &outarray) override
Definition: StdHexExp.cpp:963
void v_GetBoundaryMap(Array< OneD, unsigned int > &outarray) override
Definition: StdHexExp.cpp:1024
void v_FillMode(const int mode, Array< OneD, NekDouble > &outarray) override
Definition: StdHexExp.cpp:524
void v_GetSimplexEquiSpacedConnectivity(Array< OneD, int > &conn, bool standard=true) override
Definition: StdHexExp.cpp:2530
void v_WeakDerivMatrixOp(const int i, const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray, const StdMatrixKey &mkey) override
Definition: StdHexExp.cpp:2292
int v_GetTraceIntNcoeffs(const int i) const override
Definition: StdHexExp.cpp:666
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
Definition: StdHexExp.cpp:118
void v_IProductWRTBase(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray) override
Definition: StdHexExp.cpp:320
void v_GetElmtTraceToTraceMap(const unsigned int fid, Array< OneD, unsigned int > &maparray, Array< OneD, int > &signarray, Orientation faceOrient, int P, int Q) override
Definition: StdHexExp.cpp:1247
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
Definition: StdHexExp.cpp:205
void v_GetEdgeInteriorToElementMap(const int tid, Array< OneD, unsigned int > &maparray, Array< OneD, int > &signarray, const Orientation traceOrient=eDir1FwdDir1_Dir2FwdDir2) override
Definition: StdHexExp.cpp:1542
void v_BwdTrans(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray) override
Definition: StdHexExp.cpp:153
void v_SVVLaplacianFilter(Array< OneD, NekDouble > &array, const StdMatrixKey &mkey) override
Definition: StdHexExp.cpp:2340
void v_GetCoords(Array< OneD, NekDouble > &coords_x, Array< OneD, NekDouble > &coords_y, Array< OneD, NekDouble > &coords_z) override
Definition: StdHexExp.cpp:759
DNekMatSharedPtr v_GenMatrix(const StdMatrixKey &mkey) override
Definition: StdHexExp.cpp:2177
void v_IProductWRTDerivBase(const int dir, const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray) override
Definition: StdHexExp.cpp:452
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
Definition: StdHexExp.cpp:371
int v_GetTraceNcoeffs(const int i) const override
Definition: StdHexExp.cpp:649
void v_BwdTrans_SumFac(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray) override
Definition: StdHexExp.cpp:180
MatrixType GetMatrixType() const
Definition: StdMatrixKey.h:83
NekDouble GetConstFactor(const ConstFactorType &factor) const
Definition: StdMatrixKey.h:124
bool ConstFactorExists(const ConstFactorType &factor) const
Definition: StdMatrixKey.h:133
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 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
int getNumberOfCoefficients(int Na, int Nb, int Nc)
Definition: ShapeType.hpp:153
@ 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
const int kSVVDGFiltermodesmin
Definition: StdRegions.hpp:472
const int kSVVDGFiltermodesmax
Definition: StdRegions.hpp:473
LibUtilities::BasisKey EvaluateQuadFaceBasisKey(const int facedir, const LibUtilities::BasisType faceDirBasisType, const int numpoints, const int nummodes)
const NekDouble kSVVDGFilter[9][11]
Definition: StdRegions.hpp:475
std::vector< double > q(NPUPPER *NPUPPER)
static Array< OneD, NekDouble > NullNekDouble1DArray
std::shared_ptr< DNekMat > DNekMatSharedPtr
Definition: NekTypeDefs.hpp:75
double NekDouble
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 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