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