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