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