Nektar++
Foundations/Basis.cpp
Go to the documentation of this file.
1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 // File: Basis.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: Basis definition
32 //
33 ///////////////////////////////////////////////////////////////////////////////
34 
41 #include <boost/math/special_functions/gamma.hpp>
42 
43 namespace Nektar
44 {
45 namespace LibUtilities
46 {
47 bool Basis::initBasisManager[] = {
49 
50 bool operator<(const BasisKey &lhs, const BasisKey &rhs)
51 {
52  PointsKey lhsPointsKey = lhs.GetPointsKey();
53  PointsKey rhsPointsKey = rhs.GetPointsKey();
54 
55  if (lhsPointsKey < rhsPointsKey)
56  {
57  return true;
58  }
59  if (lhsPointsKey != rhsPointsKey)
60  {
61  return false;
62  }
63 
64  if (lhs.m_nummodes < rhs.m_nummodes)
65  {
66  return true;
67  }
68  if (lhs.m_nummodes > rhs.m_nummodes)
69  {
70  return false;
71  }
72 
73  return (lhs.m_basistype < rhs.m_basistype);
74 }
75 
76 bool operator>(const BasisKey &lhs, const BasisKey &rhs)
77 {
78  return (rhs < lhs);
79 }
80 
82  const BasisKey &rhs) const
83 {
84  return (lhs.m_basistype < rhs.m_basistype);
85 }
86 
87 std::ostream &operator<<(std::ostream &os, const BasisKey &rhs)
88 {
89  os << "NumModes: " << rhs.GetNumModes()
90  << " BasisType: " << BasisTypeMap[rhs.GetBasisType()];
91  os << " " << rhs.GetPointsKey() << std::endl;
92 
93  return os;
94 }
95 
96 Basis::Basis(const BasisKey &bkey)
97  : m_basisKey(bkey), m_points(PointsManager()[bkey.GetPointsKey()]),
98  m_bdata(bkey.GetTotNumModes() * bkey.GetTotNumPoints()),
99  m_dbdata(bkey.GetTotNumModes() * bkey.GetTotNumPoints())
100 {
101  m_InterpManager.RegisterGlobalCreator(
102  std::bind(&Basis::CalculateInterpMatrix, this, std::placeholders::_1));
103 }
104 
105 std::shared_ptr<Basis> Basis::Create(const BasisKey &bkey)
106 {
107  std::shared_ptr<Basis> returnval(new Basis(bkey));
108  returnval->Initialize();
109 
110  return returnval;
111 }
112 
114 
115 {
116  ASSERTL0(GetNumModes() > 0,
117  "Cannot call Basis initialisation with zero or negative order");
118  ASSERTL0(GetTotNumPoints() > 0, "Cannot call Basis initialisation with "
119  "zero or negative numbers of points");
120 
121  GenBasis();
122 }
123 
124 /** \brief Calculate the interpolation Matrix for coefficient from
125  * one base (m_basisKey) to another (tbasis0)
126  */
127 std::shared_ptr<NekMatrix<NekDouble>> Basis::CalculateInterpMatrix(
128  const BasisKey &tbasis0)
129 {
130  int dim = m_basisKey.GetNumModes();
132  BasisKey fbkey(m_basisKey.GetBasisType(), dim, pkey);
133  BasisKey tbkey(tbasis0.GetBasisType(), dim, pkey);
134 
135  // "Constructur" of the basis
136  BasisSharedPtr fbasis = BasisManager()[fbkey];
137  BasisSharedPtr tbasis = BasisManager()[tbkey];
138 
139  // Get B Matrices
140  Array<OneD, NekDouble> fB_data = fbasis->GetBdata();
141  Array<OneD, NekDouble> tB_data = tbasis->GetBdata();
142 
143  // Convert to a NekMatrix
144  NekMatrix<NekDouble> fB(dim, dim, fB_data);
145  NekMatrix<NekDouble> tB(dim, dim, tB_data);
146 
147  // Invert the "to" matrix: tu = tB^(-1)*fB fu = ftB fu
148  tB.Invert();
149 
150  // Compute transformation matrix
151  Array<OneD, NekDouble> zero1D(dim * dim, 0.0);
152  std::shared_ptr<NekMatrix<NekDouble>> ftB(
153  MemoryManager<NekMatrix<NekDouble>>::AllocateSharedPtr(dim, dim,
154  zero1D));
155  (*ftB) = tB * fB;
156 
157  return ftB;
158 }
159 
160 // Method used to generate appropriate basis
161 /** The following expansions are generated depending on the
162  * enum type defined in \a m_basisKey.m_basistype:
163  *
164  * NOTE: This definition does not follow the order in the
165  * Karniadakis \& Sherwin book since this leads to a more
166  * compact hierarchical pattern for implementation
167  * purposes. The order of these modes dictates the
168  * ordering of the expansion coefficients.
169  *
170  * In the following m_numModes = P
171  *
172  * \a eModified_A:
173  *
174  * m_bdata[i + j*m_numpoints] =
175  * \f$ \phi^a_i(z_j) = \left \{
176  * \begin{array}{ll} \left ( \frac{1-z_j}{2}\right ) & i = 0 \\
177  * \\
178  * \left ( \frac{1+z_j}{2}\right ) & i = 1 \\
179  * \\
180  * \left ( \frac{1-z_j}{2}\right )\left ( \frac{1+z_j}{2}\right )
181  * P^{1,1}_{i-2}(z_j) & 2\leq i < P\\
182  * \end{array} \right . \f$
183  *
184  * \a eModified_B:
185  *
186  * m_bdata[n(i,j) + k*m_numpoints] =
187  * \f$ \phi^b_{ij}(z_k) = \left \{ \begin{array}{lll}
188  * \phi^a_j(z_k) & i = 0, & 0\leq j < P \\
189  * \\
190  * \left ( \frac{1-z_k}{2}\right )^{i} & 1 \leq i < P,& j = 0 \\
191  * \\
192  * \left ( \frac{1-z_k}{2}\right )^{i} \left ( \frac{1+z_k}{2}\right )
193  * P^{2i-1,1}_{j-1}(z_k) & 1 \leq i < P,\ & 1\leq j < P-i\ \\
194  * \end{array} \right . , \f$
195  *
196  * where \f$ n(i,j) \f$ is a consecutive ordering of the
197  * triangular indices \f$ 0 \leq i, i+j < P \f$ where \a j
198  * runs fastest.
199  *
200  *
201  * \a eModified_C:
202  *
203  * m_bdata[n(i,j,k) + l*m_numpoints] =
204  * \f$ \phi^c_{ij,k}(z_l) = \phi^b_{i+j,k}(z_l) =
205  * \left \{ \begin{array}{llll}
206  * \phi^b_{j,k}(z_l) & i = 0, & 0\leq j < P & 0\leq k < P-j\\
207  * \\
208  * \left ( \frac{1-z_l}{2}\right )^{i+j} & 1\leq i < P,\
209  * & 0\leq j < P-i,\ & k = 0 \\
210  * \\
211  * \left ( \frac{1-z_l}{2}\right )^{i+j}
212  * \left ( \frac{1+z_l}{2}\right )
213  * P^{2i+2j-1,1}_{k-1}(z_k) & 1\leq i < P,& 0\leq j < P-i&
214  * 1\leq k < P-i-j \\
215  * \\
216  * \end{array} \right . , \f$
217  *
218  * where \f$ n(i,j,k) \f$ is a consecutive ordering of the
219  * triangular indices \f$ 0 \leq i, i+j, i+j+k < P \f$ where \a k
220  * runs fastest, then \a j and finally \a i.
221  *
222  */
224 {
225  int i, p, q;
226  NekDouble scal;
227  Array<OneD, NekDouble> modeSharedArray;
228  NekDouble *mode;
231  const NekDouble *D;
232 
233  m_points->GetZW(z, w);
234 
235  D = &(m_points->GetD()->GetPtr())[0];
236  int numModes = GetNumModes();
237  int numPoints = GetNumPoints();
238 
239  switch (GetBasisType())
240  {
241 
242  /** \brief Orthogonal basis A
243 
244  \f$\tilde \psi_p^a (\eta_1) = L_p(\eta_1) = P_p^{0,0}(\eta_1)\f$
245 
246  */
247  case eOrtho_A:
248  case eLegendre:
249  mode = m_bdata.data();
250 
251  for (p = 0; p < numModes; ++p, mode += numPoints)
252  {
253  Polylib::jacobfd(numPoints, z.data(), mode, NULL, p, 0.0, 0.0);
254  // normalise
255  scal = sqrt(0.5 * (2.0 * p + 1.0));
256  for (i = 0; i < numPoints; ++i)
257  {
258  mode[i] *= scal;
259  }
260  }
261  // define derivative basis
262  Blas::Dgemm('n', 'n', numPoints, numModes, numPoints, 1.0, D,
263  numPoints, m_bdata.data(), numPoints, 0.0,
264  m_dbdata.data(), numPoints);
265  break;
266 
267  /** \brief Orthogonal basis B
268 
269  \f$\tilde \psi_{pq}^b(\eta_2) = \left ( {1 - \eta_2} \over 2 \right)^p
270  P_q^{2p+1,0}(\eta_2)\f$ \\
271 
272  */
273 
274  // This is tilde psi_pq in Spen's book, page 105
275  // The 3-dimensional array is laid out in memory such that
276  // 1) Eta_y values are the changing the fastest, then q and p.
277  // 2) q index increases by the stride of numPoints.
278  case eOrtho_B:
279  {
280  NekDouble *mode = m_bdata.data();
281 
282  for (int p = 0; p < numModes; ++p)
283  {
284  for (int q = 0; q < numModes - p; ++q, mode += numPoints)
285  {
286  Polylib::jacobfd(numPoints, z.data(), mode, NULL, q,
287  2 * p + 1.0, 0.0);
288  for (int j = 0; j < numPoints; ++j)
289  {
290  mode[j] *=
291  sqrt(p + q + 1.0) * pow(0.5 * (1.0 - z[j]), p);
292  }
293  }
294  }
295 
296  // define derivative basis
297  Blas::Dgemm('n', 'n', numPoints, numModes * (numModes + 1) / 2,
298  numPoints, 1.0, D, numPoints, m_bdata.data(), numPoints,
299  0.0, m_dbdata.data(), numPoints);
300  }
301  break;
302 
303  /** \brief Orthogonal basis C
304 
305  \f$\tilde \psi_{pqr}^c = \left ( {1 - \eta_3} \over 2 \right)^{p+q}
306  P_r^{2p+2q+2, 0}(\eta_3)\f$ \ \
307 
308  */
309 
310  // This is tilde psi_pqr in Spen's book, page 105
311  // The 4-dimensional array is laid out in memory such that
312  // 1) Eta_z values are the changing the fastest, then r, q, and finally
313  // p. 2) r index increases by the stride of numPoints.
314  case eOrtho_C:
315  {
316  int P = numModes - 1, Q = numModes - 1, R = numModes - 1;
317  NekDouble *mode = m_bdata.data();
318 
319  for (int p = 0; p <= P; ++p)
320  {
321  for (int q = 0; q <= Q - p; ++q)
322  {
323  for (int r = 0; r <= R - p - q; ++r, mode += numPoints)
324  {
325  Polylib::jacobfd(numPoints, z.data(), mode, NULL, r,
326  2 * p + 2 * q + 2.0, 0.0);
327  for (int k = 0; k < numPoints; ++k)
328  {
329  // Note factor of 0.5 is part of normalisation
330  mode[k] *= pow(0.5 * (1.0 - z[k]), p + q);
331 
332  // finish normalisation
333  mode[k] *= sqrt(r + p + q + 1.5);
334  }
335  }
336  }
337  }
338 
339  // Define derivative basis
340  Blas::Dgemm('n', 'n', numPoints,
341  numModes * (numModes + 1) * (numModes + 2) / 6,
342  numPoints, 1.0, D, numPoints, m_bdata.data(), numPoints,
343  0.0, m_dbdata.data(), numPoints);
344  }
345  break;
346 
347  /** \brief Orthogonal basis C for Pyramid expansion
348  (which is richer than tets)
349 
350  \f$\tilde \psi_{pqr}^c = \left ( {1 - \eta_3} \over
351  2\right)^{pq} P_r^{2pq+2, 0}(\eta_3)\f$ \f$ \mbox{where
352  }pq = max(p+q,0) \f$
353 
354  This orthogonal expansion has modes that are
355  always in the Cartesian space, however the
356  equivalent ModifiedPyr_C has vertex modes that do
357  not lie in this space. If one chooses \f$pq =
358  max(p+q-1,0)\f$ then the expansion will space the
359  same space as the vertices but the order of the
360  expanion in 'r' is reduced by one.
361 
362  1) Eta_z values are the changing the fastest, then
363  r, q, and finally p. 2) r index increases by the
364  stride of numPoints.
365  */
366  case eOrthoPyr_C:
367  {
368  int P = numModes - 1, Q = numModes - 1, R = numModes - 1;
369  NekDouble *mode = m_bdata.data();
370 
371  for (int p = 0; p <= P; ++p)
372  {
373  for (int q = 0; q <= Q; ++q)
374  {
375  for (int r = 0; r <= R - std::max(p, q);
376  ++r, mode += numPoints)
377  {
378  // this offset allows for orthogonal
379  // expansion to span linear FE space
380  // of modified basis but means that
381  // the cartesian polynomial space
382  // spanned by the expansion is one
383  // order lower.
384  // int pq = max(p + q -1,0);
385  int pq = std::max(p + q, 0);
386 
387  Polylib::jacobfd(numPoints, z.data(), mode, NULL, r,
388  2 * pq + 2.0, 0.0);
389  for (int k = 0; k < numPoints; ++k)
390  {
391  // Note factor of 0.5 is part of normalisation
392  mode[k] *= pow(0.5 * (1.0 - z[k]), pq);
393 
394  // finish normalisation
395  mode[k] *= sqrt(r + pq + 1.5);
396  }
397  }
398  }
399  }
400 
401  // Define derivative basis
402  Blas::Dgemm('n', 'n', numPoints,
403  numModes * (numModes + 1) * (numModes + 2) / 6,
404  numPoints, 1.0, D, numPoints, m_bdata.data(), numPoints,
405  0.0, m_dbdata.data(), numPoints);
406  }
407  break;
408 
409  case eModified_A:
410 
411  // Note the following packing deviates from the
412  // definition in the Book by Karniadakis in that we
413  // put the vertex degrees of freedom at the lower
414  // index range to follow a more hierarchic structure.
415 
416  for (i = 0; i < numPoints; ++i)
417  {
418  m_bdata[i] = 0.5 * (1 - z[i]);
419  m_bdata[numPoints + i] = 0.5 * (1 + z[i]);
420  }
421 
422  mode = m_bdata.data() + 2 * numPoints;
423 
424  for (p = 2; p < numModes; ++p, mode += numPoints)
425  {
426  Polylib::jacobfd(numPoints, z.data(), mode, NULL, p - 2, 1.0,
427  1.0);
428 
429  for (i = 0; i < numPoints; ++i)
430  {
431  mode[i] *= m_bdata[i] * m_bdata[numPoints + i];
432  }
433  }
434 
435  // define derivative basis
436  Blas::Dgemm('n', 'n', numPoints, numModes, numPoints, 1.0, D,
437  numPoints, m_bdata.data(), numPoints, 0.0,
438  m_dbdata.data(), numPoints);
439  break;
440 
441  case eModified_B:
442  {
443 
444  // Note the following packing deviates from the
445  // definition in the Book by Karniadakis in two
446  // ways. 1) We put the vertex degrees of freedom
447  // at the lower index range to follow a more
448  // hierarchic structure. 2) We do not duplicate
449  // the singular vertex definition so that only a
450  // triangular number (i.e. (modes)*(modes+1)/2) of
451  // modes are required consistent with the
452  // orthogonal basis.
453 
454  // In the current structure the q index runs
455  // faster than the p index so that the matrix has
456  // a more compact structure
457 
458  const NekDouble *one_m_z_pow, *one_p_z;
459 
460  // bdata should be of size order*(order+1)/2*zorder
461 
462  // first fow
463  for (i = 0; i < numPoints; ++i)
464  {
465  m_bdata[0 * numPoints + i] = 0.5 * (1 - z[i]);
466  m_bdata[1 * numPoints + i] = 0.5 * (1 + z[i]);
467  }
468 
469  mode = m_bdata.data() + 2 * numPoints;
470 
471  for (q = 2; q < numModes; ++q, mode += numPoints)
472  {
473  Polylib::jacobfd(numPoints, z.data(), mode, NULL, q - 2, 1.0,
474  1.0);
475 
476  for (i = 0; i < numPoints; ++i)
477  {
478  mode[i] *= m_bdata[i] * m_bdata[numPoints + i];
479  }
480  }
481 
482  // second row
483  for (i = 0; i < numPoints; ++i)
484  {
485  mode[i] = 0.5 * (1 - z[i]);
486  }
487 
488  mode += numPoints;
489 
490  for (q = 2; q < numModes; ++q, mode += numPoints)
491  {
492  Polylib::jacobfd(numPoints, z.data(), mode, NULL, q - 2, 1.0,
493  1.0);
494 
495  for (i = 0; i < numPoints; ++i)
496  {
497  mode[i] *= m_bdata[i] * m_bdata[numPoints + i];
498  }
499  }
500 
501  // third and higher rows
502  one_m_z_pow = m_bdata.data();
503  one_p_z = m_bdata.data() + numPoints;
504 
505  for (p = 2; p < numModes; ++p)
506  {
507  for (i = 0; i < numPoints; ++i)
508  {
509  mode[i] = m_bdata[i] * one_m_z_pow[i];
510  }
511 
512  one_m_z_pow = mode;
513  mode += numPoints;
514 
515  for (q = 1; q < numModes - p; ++q, mode += numPoints)
516  {
517  Polylib::jacobfd(numPoints, z.data(), mode, NULL, q - 1,
518  2 * p - 1, 1.0);
519 
520  for (i = 0; i < numPoints; ++i)
521  {
522  mode[i] *= one_m_z_pow[i] * one_p_z[i];
523  }
524  }
525  }
526 
527  Blas::Dgemm('n', 'n', numPoints, numModes * (numModes + 1) / 2,
528  numPoints, 1.0, D, numPoints, m_bdata.data(), numPoints,
529  0.0, m_dbdata.data(), numPoints);
530  }
531  break;
532 
533  case eModified_C:
534  {
535  // Note the following packing deviates from the
536  // definition in the Book by Karniadakis &
537  // Sherwin in two ways. 1) We put the vertex
538  // degrees of freedom at the lower index range to
539  // follow a more hierarchic structure. 2) We do
540  // not duplicate the singular vertex definition
541  // (or the duplicated face information in the book
542  // ) so that only a tetrahedral number
543  // (i.e. (modes)*(modes+1)*(modes+2)/6) of modes
544  // are required consistent with the orthogonal
545  // basis.
546 
547  // In the current structure the r index runs
548  // fastest rollowed by q and than the p index so
549  // that the matrix has a more compact structure
550 
551  // Note that eModified_C is a re-organisation/
552  // duplication of eModified_B so will get a
553  // temporary Modified_B expansion and copy the
554  // correct components.
555 
556  // Generate Modified_B basis;
559  BasisSharedPtr ModB = BasisManager()[ModBKey];
560 
561  Array<OneD, const NekDouble> ModB_data = ModB->GetBdata();
562 
563  // Copy Modified_B basis into first
564  // (numModes*(numModes+1)/2)*numPoints entires of
565  // bdata. This fills in the complete (r,p) face.
566 
567  // Set up \phi^c_{p,q,r} = \phi^b_{p+q,r}
568 
569  int N;
570  int B_offset = 0;
571  int offset = 0;
572  for (p = 0; p < numModes; ++p)
573  {
574  N = numPoints * (numModes - p) * (numModes - p + 1) / 2;
575  Vmath::Vcopy(N, &ModB_data[0] + B_offset, 1,
576  &m_bdata[0] + offset, 1);
577  B_offset += numPoints * (numModes - p);
578  offset += N;
579  }
580 
581  // set up derivative of basis.
582  Blas::Dgemm('n', 'n', numPoints,
583  numModes * (numModes + 1) * (numModes + 2) / 6,
584  numPoints, 1.0, D, numPoints, m_bdata.data(), numPoints,
585  0.0, m_dbdata.data(), numPoints);
586  }
587  break;
588 
589  case eModifiedPyr_C:
590  {
591  // Note the following packing deviates from the
592  // definition in the Book by Karniadakis &
593  // Sherwin in two ways. 1) We put the vertex
594  // degrees of freedom at the lower index range to
595  // follow a more hierarchic structure. 2) We do
596  // not duplicate the singular vertex definition
597  // so that only a pyramidic number
598  // (i.e. (modes)*(modes+1)*(2*modes+1)/6) of modes
599  // are required consistent with the orthogonal
600  // basis.
601 
602  // In the current structure the r index runs
603  // fastest rollowed by q and than the p index so
604  // that the matrix has a more compact structure
605 
606  // Generate Modified_B basis;
609  BasisSharedPtr ModB = BasisManager()[ModBKey];
610 
611  Array<OneD, const NekDouble> ModB_data = ModB->GetBdata();
612 
613  // Copy Modified_B basis into first
614  // (numModes*(numModes+1)/2)*numPoints entires of
615  // bdata.
616 
617  int N;
618  int B_offset = 0;
619  int offset = 0;
620 
621  // Vertex 0,3,4, edges 3,4,7, face 4
622  N = numPoints * (numModes) * (numModes + 1) / 2;
623  Vmath::Vcopy(N, &ModB_data[0], 1, &m_bdata[0], 1);
624  offset += N;
625 
626  B_offset += numPoints * (numModes);
627  // Vertex 1 edges 5
628  N = numPoints * (numModes - 1);
629  Vmath::Vcopy(N, &ModB_data[0] + B_offset, 1, &m_bdata[0] + offset,
630  1);
631  offset += N;
632 
633  // Vertex 2 edges 1,6, face 2
634  N = numPoints * (numModes - 1) * (numModes) / 2;
635  Vmath::Vcopy(N, &ModB_data[0] + B_offset, 1, &m_bdata[0] + offset,
636  1);
637  offset += N;
638 
639  B_offset += numPoints * (numModes - 1);
640 
641  NekDouble *one_m_z_pow, *one_p_z;
642  NekDouble *mode;
643 
644  mode = m_bdata.data() + offset;
645 
646  for (p = 2; p < numModes; ++p)
647  {
648  // edges 0 2, faces 1 3
649  N = numPoints * (numModes - p);
650  Vmath::Vcopy(N, &ModB_data[0] + B_offset, 1, mode, 1);
651  mode += N;
652  Vmath::Vcopy(N, &ModB_data[0] + B_offset, 1, mode, 1);
653  mode += N;
654  B_offset += N;
655 
656  one_p_z = m_bdata.data() + numPoints;
657 
658  for (q = 2; q < numModes; ++q)
659  {
660  // face 0
661  for (i = 0; i < numPoints; ++i)
662  {
663  // [(1-z)/2]^{p+q-2} Note in book it
664  // seems to suggest p+q-1 but that
665  // does not seem to give complete
666  // polynomial space for pyramids
667  mode[i] = pow(m_bdata[i], p + q - 2);
668  }
669 
670  one_m_z_pow = mode;
671  mode += numPoints;
672 
673  // interior
674  for (int r = 1; r < numModes - std::max(p, q); ++r)
675  {
676  Polylib::jacobfd(numPoints, z.data(), mode, NULL, r - 1,
677  2 * p + 2 * q - 3, 1.0);
678 
679  for (i = 0; i < numPoints; ++i)
680  {
681  mode[i] *= one_m_z_pow[i] * one_p_z[i];
682  }
683  mode += numPoints;
684  }
685  }
686  }
687 
688  // set up derivative of basis.
689  Blas::Dgemm('n', 'n', numPoints,
690  numModes * (numModes + 1) * (2 * numModes + 1) / 6,
691  numPoints, 1.0, D, numPoints, m_bdata.data(), numPoints,
692  0.0, m_dbdata.data(), numPoints);
693  }
694  break;
695 
696  case eGLL_Lagrange:
697  {
698  mode = m_bdata.data();
699  std::shared_ptr<Points<NekDouble>> m_points =
701  const Array<OneD, const NekDouble> &zp(m_points->GetZ());
702 
703  for (p = 0; p < numModes; ++p, mode += numPoints)
704  {
705  for (q = 0; q < numPoints; ++q)
706  {
707  mode[q] =
708  Polylib::hglj(p, z[q], zp.data(), numModes, 0.0, 0.0);
709  }
710  }
711 
712  // define derivative basis
713  Blas::Dgemm('n', 'n', numPoints, numModes, numPoints, 1.0, D,
714  numPoints, m_bdata.data(), numPoints, 0.0,
715  m_dbdata.data(), numPoints);
716 
717  } // end scope
718  break;
719  case eGauss_Lagrange:
720  {
721  mode = m_bdata.data();
722  std::shared_ptr<Points<NekDouble>> m_points =
724  const Array<OneD, const NekDouble> &zp(m_points->GetZ());
725 
726  for (p = 0; p < numModes; ++p, mode += numPoints)
727  {
728  for (q = 0; q < numPoints; ++q)
729  {
730  mode[q] =
731  Polylib::hgj(p, z[q], zp.data(), numModes, 0.0, 0.0);
732  }
733  }
734 
735  // define derivative basis
736  Blas::Dgemm('n', 'n', numPoints, numModes, numPoints, 1.0, D,
737  numPoints, m_bdata.data(), numPoints, 0.0,
738  m_dbdata.data(), numPoints);
739 
740  } // end scope
741  break;
742  case eFourier:
743 
744  ASSERTL0(numModes % 2 == 0,
745  "Fourier modes should be a factor of 2");
746 
747  for (i = 0; i < numPoints; ++i)
748  {
749  m_bdata[i] = 1.0;
750  m_bdata[numPoints + i] = 0.0;
751 
752  m_dbdata[i] = m_dbdata[numPoints + i] = 0.0;
753  }
754 
755  for (p = 1; p < numModes / 2; ++p)
756  {
757  for (i = 0; i < numPoints; ++i)
758  {
759  m_bdata[2 * p * numPoints + i] = cos(p * M_PI * (z[i] + 1));
760  m_bdata[(2 * p + 1) * numPoints + i] =
761  -sin(p * M_PI * (z[i] + 1));
762 
763  m_dbdata[2 * p * numPoints + i] =
764  -p * M_PI * sin(p * M_PI * (z[i] + 1));
765  m_dbdata[(2 * p + 1) * numPoints + i] =
766  -p * M_PI * cos(p * M_PI * (z[i] + 1));
767  }
768  }
769 
770  break;
771 
772  // Fourier Single Mode (1st mode)
773  case eFourierSingleMode:
774 
775  for (i = 0; i < numPoints; ++i)
776  {
777  m_bdata[i] = cos(M_PI * (z[i] + 1));
778  m_bdata[numPoints + i] = -sin(M_PI * (z[i] + 1));
779 
780  m_dbdata[i] = -M_PI * sin(M_PI * (z[i] + 1));
781  m_dbdata[numPoints + i] = -M_PI * cos(M_PI * (z[i] + 1));
782  }
783 
784  for (p = 1; p < numModes / 2; ++p)
785  {
786  for (i = 0; i < numPoints; ++i)
787  {
788  m_bdata[2 * p * numPoints + i] = 0.;
789  m_bdata[(2 * p + 1) * numPoints + i] = 0.;
790 
791  m_dbdata[2 * p * numPoints + i] = 0.;
792  m_dbdata[(2 * p + 1) * numPoints + i] = 0.;
793  }
794  }
795  break;
796 
797  // Fourier Real Half Mode
798  case eFourierHalfModeRe:
799  m_bdata[0] = cos(M_PI * z[0]);
800  m_dbdata[0] = -M_PI * sin(M_PI * z[0]);
801  break;
802 
803  // Fourier Imaginary Half Mode
804  case eFourierHalfModeIm:
805  m_bdata[0] = -sin(M_PI * z[0]);
806  m_dbdata[0] = -M_PI * cos(M_PI * z[0]);
807  break;
808 
809  case eChebyshev:
810  {
811  mode = m_bdata.data();
812 
813  for (p = 0, scal = 1; p < numModes; ++p, mode += numPoints)
814  {
815  Polylib::jacobfd(numPoints, z.data(), mode, NULL, p, -0.5,
816  -0.5);
817 
818  for (i = 0; i < numPoints; ++i)
819  {
820  mode[i] *= scal;
821  }
822 
823  scal *= 4 * (p + 1) * (p + 1) / (2 * p + 2) / (2 * p + 1);
824  }
825 
826  // Define derivative basis
827  Blas::Dgemm('n', 'n', numPoints, numModes, numPoints, 1.0, D,
828  numPoints, m_bdata.data(), numPoints, 0.0,
829  m_dbdata.data(), numPoints);
830  }
831  break;
832 
833  case eMonomial:
834  {
835  int P = numModes - 1;
836  NekDouble *mode = m_bdata.data();
837 
838  for (int p = 0; p <= P; ++p, mode += numPoints)
839  {
840  for (int i = 0; i < numPoints; ++i)
841  {
842  mode[i] = pow(z[i], p);
843  }
844  }
845 
846  // define derivative basis
847  Blas::Dgemm('n', 'n', numPoints, numModes, numPoints, 1.0, D,
848  numPoints, m_bdata.data(), numPoints, 0.0,
849  m_dbdata.data(), numPoints);
850  } // end scope
851  break;
852  default:
853  NEKERROR(ErrorUtil::efatal, "Basis Type not known or "
854  "not implemented at this time.");
855  }
856 }
857 
858 /** \brief Determine if polynomial basis can be eactly integrated
859  * with itself
860  */
861 bool BasisKey::ExactIprodInt(void) const
862 {
863  bool returnval = false;
864 
865  switch (GetPointsType())
866  {
867  case eGaussGaussLegendre:
871  case eGaussKronrodLegendre:
874  returnval = (GetNumPoints() >= GetNumModes());
875  break;
876 
877  default:
878  break;
879  }
880 
881  return returnval;
882 }
883 
884 /** \brief Determine if basis has collocation property,
885  * i.e. GLL_Lagrange with Lobatto integration of appropriate order,
886  * Gauss_Lagrange with Gauss integration of appropriate order.
887  */
889 {
890  return ((m_basistype == eGLL_Lagrange &&
892  GetNumModes() == GetNumPoints()) ||
895  GetNumModes() == GetNumPoints()));
896 }
897 
898 // BasisKey compared to BasisKey
899 bool operator==(const BasisKey &x, const BasisKey &y)
900 {
901  return (x.GetPointsKey() == y.GetPointsKey() &&
902  x.m_basistype == y.m_basistype &&
903  x.GetNumModes() == y.GetNumModes());
904 }
905 
906 // BasisKey* compared to BasisKey
907 bool operator==(const BasisKey *x, const BasisKey &y)
908 {
909  return (*x == y);
910 }
911 
912 // \brief BasisKey compared to BasisKey*
913 bool operator==(const BasisKey &x, const BasisKey *y)
914 {
915  return (x == *y);
916 }
917 
918 // \brief BasisKey compared to BasisKey
919 bool operator!=(const BasisKey &x, const BasisKey &y)
920 {
921  return (!(x == y));
922 }
923 
924 // BasisKey* compared to BasisKey
925 bool operator!=(const BasisKey *x, const BasisKey &y)
926 {
927  return (!(*x == y));
928 }
929 
930 // BasisKey compared to BasisKey*
931 bool operator!=(const BasisKey &x, const BasisKey *y)
932 {
933  return (!(x == *y));
934 }
935 
936 } // namespace LibUtilities
937 } // namespace Nektar
#define ASSERTL0(condition, msg)
Definition: ErrorUtil.hpp:215
#define NEKERROR(type, msg)
Assert Level 0 – Fundamental assert which is used whether in FULLDEBUG, DEBUG or OPT compilation mode...
Definition: ErrorUtil.hpp:209
int GetNumModes() const
Return order of basis from the basis specification.
Definition: Basis.h:222
Array< OneD, NekDouble > m_dbdata
Derivative Basis definition.
Definition: Basis.h:339
static std::shared_ptr< Basis > Create(const BasisKey &bkey)
Returns a new instance of a Basis with given BasisKey.
PointsSharedPtr m_points
Set of points.
Definition: Basis.h:337
int GetTotNumPoints() const
Return total number of points from the basis specification.
Definition: Basis.h:240
BasisKey m_basisKey
Basis specification.
Definition: Basis.h:336
static bool initBasisManager[]
Definition: Basis.h:344
Basis()
Private default constructor.
Definition: Basis.h:350
BasisType GetBasisType() const
Return the type of expansion basis.
Definition: Basis.h:246
int GetNumPoints() const
Return the number of points from the basis specification.
Definition: Basis.h:234
std::shared_ptr< NekMatrix< NekDouble > > CalculateInterpMatrix(const BasisKey &tbasis0)
Calculate the interpolation Matrix for coefficient from one base (m_basisKey) to another (tbasis0)
NekManager< BasisKey, NekMatrix< NekDouble >, BasisKey::opLess > m_InterpManager
Definition: Basis.h:341
void GenBasis()
Generate appropriate basis and their derivatives.
Array< OneD, NekDouble > m_bdata
Basis definition.
Definition: Basis.h:338
Describes the specification for a Basis.
Definition: Basis.h:50
unsigned int m_nummodes
Expansion order.
Definition: Basis.h:196
int GetNumPoints() const
Return points order at which basis is defined.
Definition: Basis.h:130
BasisType GetBasisType() const
Return type of expansion basis.
Definition: Basis.h:141
PointsKey GetPointsKey() const
Return distribution of points.
Definition: Basis.h:147
int GetTotNumPoints() const
Definition: Basis.h:135
int GetTotNumModes() const
Definition: Basis.h:89
int GetNumModes() const
Returns the order of the basis.
Definition: Basis.h:83
PointsType GetPointsType() const
Return type of quadrature.
Definition: Basis.h:153
BasisType m_basistype
Expansion type.
Definition: Basis.h:197
bool Collocation() const
Determine if basis has collocation properties.
bool ExactIprodInt() const
Determine if basis has exact integration for inner product.
bool RegisterGlobalCreator(const CreateFuncType &createFunc)
Register the Global Create Function. The return value is just to facilitate calling statically.
Definition: NekManager.hpp:179
Defines a specification for a set of points.
Definition: Points.h:59
General purpose memory allocation routines with the ability to allocate from thread specific memory p...
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
BasisManagerT & BasisManager(void)
bool operator==(const BasisKey &x, const BasisKey &y)
std::shared_ptr< Basis > BasisSharedPtr
const char *const BasisTypeMap[]
Definition: Foundations.hpp:46
PointsManagerT & PointsManager(void)
bool operator<(const BasisKey &lhs, const BasisKey &rhs)
bool operator>(const BasisKey &lhs, const BasisKey &rhs)
bool operator!=(const BasisKey &x, const BasisKey &y)
std::ostream & operator<<(std::ostream &os, const BasisKey &rhs)
@ eGaussRadauMLegendre
1D Gauss-Radau-Legendre quadrature points, pinned at x=-1
Definition: PointsType.h:49
@ eGaussRadauKronrodMLegendre
1D Gauss-Radau-Kronrod-Legendre quadrature points, pinned at x=-1
Definition: PointsType.h:69
@ eGaussLobattoLegendre
1D Gauss-Lobatto-Legendre quadrature points
Definition: PointsType.h:53
@ eGaussLobattoKronrodLegendre
1D Lobatto Kronrod quadrature points
Definition: PointsType.h:74
@ eGaussGaussLegendre
1D Gauss-Gauss-Legendre quadrature points
Definition: PointsType.h:48
@ eGaussRadauPLegendre
1D Gauss-Radau-Legendre quadrature points, pinned at x=1
Definition: PointsType.h:51
@ eModified_B
Principle Modified Functions .
Definition: BasisType.h:51
@ eGauss_Lagrange
Lagrange Polynomials using the Gauss points.
Definition: BasisType.h:59
@ 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
@ eFourierSingleMode
Fourier ModifiedExpansion with just the first mode .
Definition: BasisType.h:66
@ eChebyshev
Chebyshev Polynomials.
Definition: BasisType.h:63
@ eOrtho_C
Principle Orthogonal Functions .
Definition: BasisType.h:48
@ eModifiedPyr_C
Principle Modified Functions.
Definition: BasisType.h:55
@ eOrtho_B
Principle Orthogonal Functions .
Definition: BasisType.h:46
@ eModified_A
Principle Modified Functions .
Definition: BasisType.h:50
@ eFourierHalfModeIm
Fourier Modified expansions with just the imaginary part of the first mode .
Definition: BasisType.h:70
@ eFourierHalfModeRe
Fourier Modified expansions with just the real part of the first mode .
Definition: BasisType.h:68
@ eOrthoPyr_C
Principle Orthogonal Functions .
Definition: BasisType.h:53
@ eFourier
Fourier Expansion .
Definition: BasisType.h:57
The above copyright notice and this permission notice shall be included.
Definition: CoupledSolver.h:2
double NekDouble
double hgj(const int i, const double z, const double *zgj, const int np, const double alpha, const double beta)
Compute the value of the i th Lagrangian interpolant through the np Gauss-Jacobi points zgj at the ar...
Definition: Polylib.cpp:858
double hglj(const int i, const double z, const double *zglj, const int np, const double alpha, const double beta)
Compute the value of the i th Lagrangian interpolant through the np Gauss-Lobatto-Jacobi points zgrj ...
Definition: Polylib.cpp:964
void jacobfd(const int np, const double *z, double *poly_in, double *polyd, const int n, const double alpha, const double beta)
Routine to calculate Jacobi polynomials, , and their first derivative, .
Definition: Polylib.cpp:1181
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:294
bool operator()(const BasisKey &lhs, const BasisKey &rhs) const