Nektar++
Loading...
Searching...
No Matches
StdTriExp.cpp
Go to the documentation of this file.
1///////////////////////////////////////////////////////////////////////////////
2//
3// File: StdTriExp.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: Triangle routines built upon StdExpansion2D
32//
33///////////////////////////////////////////////////////////////////////////////
34
38#include <StdRegions/StdSegExp.h> // for StdSegExp, etc
40
41using namespace std;
45
46namespace Nektar::StdRegions
47{
48// Declaration of scalar routine
52
54 const LibUtilities::BasisKey &Bb)
55 : StdExpansion(LibUtilities::StdTriData::getNumberOfCoefficients(
56 Ba.GetNumModes(), Bb.GetNumModes()),
57 2, Ba, Bb),
58 StdExpansion2D(LibUtilities::StdTriData::getNumberOfCoefficients(
59 Ba.GetNumModes(), Bb.GetNumModes()),
60 Ba, Bb)
61{
62 ASSERTL0(Ba.GetNumModes() <= Bb.GetNumModes(),
63 "order in 'a' direction is higher than order "
64 "in 'b' direction");
65
66 // cache integration weights for future use
67 m_weights.push_back(m_base[0]->GetW());
68
69 StdFacKey w1key(eWeights1, Bb);
70 // get weights[1] from manager where points are rescaled
71 m_weights.push_back(GetStdFac(w1key));
72}
73
74//-----------------------------
75// Differentiation Methods
76//-----------------------------
77/**
78 * \brief Calculate the derivative of the physical points.
79 *
80 * \f$ \frac{\partial u}{\partial x_1} = \left .
81 * \frac{2.0}{1-\eta_2} \frac{\partial u}{\partial d\eta_1}
82 * \right |_{\eta_2}\f$
83 *
84 * \f$ \frac{\partial u}{\partial x_2} = \left .
85 * \frac{1+\eta_1}{1-\eta_2} \frac{\partial u}{\partial d\eta_1}
86 * \right |_{\eta_2} + \left . \frac{\partial u}{\partial d\eta_2}
87 * \right |_{\eta_1} \f$
88 */
92 [[maybe_unused]] Array<OneD, NekDouble> &out_d2)
93{
94 int i;
95 int nquad0 = m_base[0]->GetNumPoints();
96 int nquad1 = m_base[1]->GetNumPoints();
97 Array<OneD, NekDouble> wsp(std::max(nquad0, nquad1));
98
99 const Array<OneD, const NekDouble> &z0 = m_base[0]->GetZ();
100 const Array<OneD, const NekDouble> &z1 = m_base[1]->GetZ();
101
102 // set up geometric factor: 2/(1-z1)
103 Vmath::Sadd(nquad1, -1.0, z1, 1, wsp, 1);
104 Vmath::Sdiv(nquad1, -2.0, wsp, 1, wsp, 1);
105
106 if (out_d0.size() > 0)
107 {
108 PhysTensorDeriv(inarray, out_d0, out_d1);
109
110 for (i = 0; i < nquad1; ++i)
111 {
112 Blas::Dscal(nquad0, wsp[i], &out_d0[0] + i * nquad0, 1);
113 }
114
115 // if no d1 required do not need to calculate both deriv
116 if (out_d1.size() > 0)
117 {
118 // set up geometric factor: (1+z0)/2
119 Vmath::Sadd(nquad0, 1.0, z0, 1, wsp, 1);
120 Vmath::Smul(nquad0, 0.5, wsp, 1, wsp, 1);
121
122 for (i = 0; i < nquad1; ++i)
123 {
124 Vmath::Vvtvp(nquad0, &wsp[0], 1, &out_d0[0] + i * nquad0, 1,
125 &out_d1[0] + i * nquad0, 1,
126 &out_d1[0] + i * nquad0, 1);
127 }
128 }
129 }
130 else if (out_d1.size() > 0)
131 {
132 Array<OneD, NekDouble> diff0(nquad0 * nquad1);
133 PhysTensorDeriv(inarray, diff0, out_d1);
134
135 for (i = 0; i < nquad1; ++i)
136 {
137 Blas::Dscal(nquad0, wsp[i], &diff0[0] + i * nquad0, 1);
138 }
139
140 Vmath::Sadd(nquad0, 1.0, z0, 1, wsp, 1);
141 Vmath::Smul(nquad0, 0.5, wsp, 1, wsp, 1);
142
143 for (i = 0; i < nquad1; ++i)
144 {
145 Vmath::Vvtvp(nquad0, &wsp[0], 1, &diff0[0] + i * nquad0, 1,
146 &out_d1[0] + i * nquad0, 1, &out_d1[0] + i * nquad0,
147 1);
148 }
149 }
150}
151
152//---------------------------------------
153// Transforms
154//---------------------------------------
155
156/**
157 * \brief Backward tranform for triangular elements
158 *
159 * @note 'q' (base[1]) runs fastest in this element.
160 */
162 Array<OneD, NekDouble> &outarray)
163{
166 "Basis[1] is not of general tensor type");
167
168 const Array<OneD, const NekDouble> base0 = m_base[0]->GetBdata();
169 const Array<OneD, const NekDouble> base1 = m_base[1]->GetBdata();
170
171 int nquad0 = m_base[0]->GetNumPoints();
172 int nquad1 = m_base[1]->GetNumPoints();
173 int nmodes0 = m_base[0]->GetNumModes();
174 int nmodes1 = m_base[1]->GetNumModes();
175
176 std::vector<vec_t, tinysimd::allocator<vec_t>> wsp0(nmodes0);
177 bool isModified = (m_base[0]->GetBasisType() == LibUtilities::eModified_A);
178
179// Swith statment using boost_pp and macros. This unfolls intwo a
180// nested swtich statement where the outer swtich statement runs
181// from SMIN to SMAX for modal order and the inner switch
182// statemets run from the outer value of the case to 2*SMAX for
183// the quadrature order. If you want to see it unwrapped compile
184// in verbose mode and add --preprocess to the c++ command.
185// Default case
186#undef BWDTRANS_DEF
187#define BWDTRANS_DEF \
188 BwdTransTriKernel(nmodes0, nmodes1, nquad0, nquad1, isModified, \
189 (const vec_t *)base0.data(), \
190 (const vec_t *)base1.data(), wsp0.data(), \
191 (const vec_t *)inarray.data(), (vec_t *)outarray.data())
192
193// Inner loop case over quarature points
194#undef BWDTRANS_Q
195#define BWDTRANS_Q(r, i) \
196 case NQ(i): \
197 BwdTransTriKernel(NM(i), NM(i), NQ(i), NQ_M1(i), isModified, \
198 (const vec_t *)base0.data(), \
199 (const vec_t *)base1.data(), wsp0.data(), \
200 (const vec_t *)inarray.data(), \
201 (vec_t *)outarray.data()); \
202 break;
203
204// outer loop case over modes
205#undef BWDTRANS_M
206#define BWDTRANS_M(r, i) \
207 case NM(i): \
208 { \
209 switch (nquad0) \
210 { \
211 BOOST_PP_FOR_##r((NM(i), NM_P1(i), BOOST_PP_MUL(2, NM(i))), \
212 STDLEV2TEST1, STDLEV2UPDATE1, BWDTRANS_Q) default \
213 : BWDTRANS_DEF; \
214 break; \
215 } \
216 } \
217 break;
218
219 // templated cases on equi-ordered modes and standard quad
220 // usage where quad order goes from mode order to 2(*mode
221 // order)
222 if ((nmodes0 == nmodes1) && (nquad0 == nquad1 + 1))
223 {
224 switch (nmodes0)
225 {
226 BOOST_PP_FOR((SMIN, 0, SMAX), STDLEV2TEST, STDLEV2UPDATE,
228 default:
230 break;
231 }
232 }
233 else
234 {
236 }
237}
238
240 const Array<OneD, const NekDouble> &inarray,
241 Array<OneD, NekDouble> &outarray)
242{
243 int i, j;
244 int npoints[2] = {m_base[0]->GetNumPoints(), m_base[1]->GetNumPoints()};
245 int nmodes[2] = {m_base[0]->GetNumModes(), m_base[1]->GetNumModes()};
246
247 fill(outarray.data(), outarray.data() + m_ncoeffs, 0.0);
248
249 Array<OneD, NekDouble> physEdge[3];
250 Array<OneD, NekDouble> coeffEdge[3];
251 for (i = 0; i < 3; i++)
252 {
253 physEdge[i] = Array<OneD, NekDouble>(npoints[i != 0]);
254 coeffEdge[i] = Array<OneD, NekDouble>(nmodes[i != 0]);
255 }
256
257 for (i = 0; i < npoints[0]; i++)
258 {
259 physEdge[0][i] = inarray[i];
260 }
261
262 for (i = 0; i < npoints[1]; i++)
263 {
264 physEdge[1][i] = inarray[npoints[0] - 1 + i * npoints[0]];
265 physEdge[2][i] =
266 inarray[(npoints[1] - 1) * npoints[0] - i * npoints[0]];
267 }
268
269 StdSegExpSharedPtr segexp[2] = {
271 m_base[0]->GetBasisKey()),
273 m_base[1]->GetBasisKey())};
274
276 Array<OneD, int> signArray;
278
279 for (i = 0; i < 3; i++)
280 {
281 segexp[i != 0]->FwdTransBndConstrained(physEdge[i], coeffEdge[i]);
282
283 GetTraceToElementMap(i, mapArray, signArray);
284 for (j = 0; j < nmodes[i != 0]; j++)
285 {
286 sign = (NekDouble)signArray[j];
287 outarray[mapArray[j]] = sign * coeffEdge[i][j];
288 }
289 }
290
293
294 StdMatrixKey masskey(eMass, DetShapeType(), *this);
295 MassMatrixOp(outarray, tmp0, masskey);
296 v_IProductWRTBase(inarray, tmp1);
297
298 Vmath::Vsub(m_ncoeffs, tmp1, 1, tmp0, 1, tmp1, 1);
299
300 // get Mass matrix inverse (only of interior DOF)
301 // use block (1,1) of the static condensed system
302 // note: this block alreay contains the inverse matrix
303 DNekMatSharedPtr matsys =
304 (m_stdStaticCondMatrixManager[masskey])->GetBlock(1, 1);
305
306 int nBoundaryDofs = v_NumBndryCoeffs();
307 int nInteriorDofs = m_ncoeffs - nBoundaryDofs;
308
309 Array<OneD, NekDouble> rhs(nInteriorDofs);
310 Array<OneD, NekDouble> result(nInteriorDofs);
311
312 v_GetInteriorMap(mapArray);
313
314 for (i = 0; i < nInteriorDofs; i++)
315 {
316 rhs[i] = tmp1[mapArray[i]];
317 }
318
319 Blas::Dgemv('N', nInteriorDofs, nInteriorDofs, 1.0, &(matsys->GetPtr())[0],
320 nInteriorDofs, rhs.data(), 1, 0.0, result.data(), 1);
321
322 for (i = 0; i < nInteriorDofs; i++)
323 {
324 outarray[mapArray[i]] = result[i];
325 }
326}
327
328//---------------------------------------
329// Inner product functions
330//---------------------------------------
331/** \brief Inner product of \a inarray over region with respect to the
332 * expansion basis (this)->m_base[0] and return in \a outarray
333 *
334 * @param base0 - An array containing the values of the basis in the
335 * 0-direction at the quarature poitns
336 * @param base1 - An array containing the values of the basis in the
337 * 1-direction at the quarature poitns
338 * @param inarray - Array of values evaluated at the physical
339 * quadrature points
340 * @param outarray the values of the inner product with respect to
341 * each basis over region will be stored in the array \a outarray as
342 * output of the function
343 * @param jac - An array of size 1 if not deformed or the number of
344 * quadrature points if deformed holding the values of the jacobian
345 * @param Deformed - a bool identifying if the inner product is to be
346 * treated as a deformed or regular integration which just relates to
347 * how the \param jac array is treated
348 */
350 const Array<OneD, const NekDouble> &base0,
351 const Array<OneD, const NekDouble> &base1,
352 const Array<OneD, const NekDouble> &inarray,
354 const bool Deformed, [[maybe_unused]] const bool CollDir0,
355 [[maybe_unused]] const bool CollDir1)
356{
357 int nquad0 = m_base[0]->GetNumPoints();
358 int nquad1 = m_base[1]->GetNumPoints();
359 int order0 = m_base[0]->GetNumModes();
360 int order1 = m_base[1]->GetNumModes();
361
362 const bool isModified =
363 (m_base[0]->GetBasisType() == LibUtilities::eModified_A);
364
365 std::vector<vec_t, tinysimd::allocator<vec_t>> wsp0(nquad1);
366
367 // Swith statment using boost_pp and macros. This unfolls intwo a
368 // nested swtich statement where the outer swtich statement runs
369 // from SMIN to SMAX for modal order and the inner switch
370 // statemets run from the outer value of the case to 2*SMAX for
371 // the quadrature order. If you want to see it unwrapped compile
372 // in verbose mode and add --preprocess to the c++ command.
373 if (Deformed)
374 {
375 // Default case
376#undef IPRODUCTWRTBASE_DEF
377#define IPRODUCTWRTBASE_DEF \
378 IProductTriKernel<false, false, true>( \
379 order0, order1, nquad0, nquad1, isModified, \
380 (const vec_t *)inarray.data(), (const vec_t *)base0.data(), \
381 (const vec_t *)base1.data(), (const vec_t *)m_weights[0].data(), \
382 (const vec_t *)m_weights[1].data(), (const vec_t *)jac.data(), \
383 (vec_t *)wsp0.data(), (vec_t *)outarray.data())
384
385 // Inner loop case over quarature points
386#undef IPRODUCTWRTBASE_Q
387#define IPRODUCTWRTBASE_Q(r, i) \
388 case NQ(i): \
389 IProductTriKernel<false, false, true>( \
390 NM(i), NM(i), NQ(i), NQ_M1(i), isModified, \
391 (const vec_t *)inarray.data(), (const vec_t *)base0.data(), \
392 (const vec_t *)base1.data(), (const vec_t *)m_weights[0].data(), \
393 (const vec_t *)m_weights[1].data(), (const vec_t *)jac.data(), \
394 (vec_t *)wsp0.data(), (vec_t *)outarray.data()); \
395 break;
396
397 // outer loop case over modes
398#undef IPRODUCTWRTBASE_M
399#define IPRODUCTWRTBASE_M(r, i) \
400 case NM(i): \
401 { \
402 switch (nquad0) \
403 { \
404 BOOST_PP_FOR_##r((NM(i), NM_P1(i), BOOST_PP_MUL(2, NM(i))), \
405 STDLEV2TEST1, STDLEV2UPDATE1, \
406 IPRODUCTWRTBASE_Q) default : IPRODUCTWRTBASE_DEF; \
407 break; \
408 } \
409 } \
410 break;
411
412 // templated cases on equi-ordered modes and standard quad usage
413 // where quad order goes from mode order to 2(*mode order)
414 if ((order0 == order1) && (nquad0 == nquad1 + 1))
415 {
416 switch (order0)
417 {
418 BOOST_PP_FOR((SMIN, 0, SMAX), STDLEV2TEST, STDLEV2UPDATE,
420 default:
422 break;
423 }
424 }
425 else
426 {
428 }
429 }
430 else // non-deformed case
431 {
432 // Default case
433#undef IPRODUCTWRTBASE_DEF
434#define IPRODUCTWRTBASE_DEF \
435 IProductTriKernel<false, false, false>( \
436 order0, order1, nquad0, nquad1, isModified, \
437 (const vec_t *)inarray.data(), (const vec_t *)base0.data(), \
438 (const vec_t *)base1.data(), (const vec_t *)m_weights[0].data(), \
439 (const vec_t *)m_weights[1].data(), (const vec_t *)jac.data(), \
440 (vec_t *)wsp0.data(), (vec_t *)outarray.data())
441
442 // Inner loop case over quarature points
443#undef IPRODUCTWRTBASE_Q
444#define IPRODUCTWRTBASE_Q(r, i) \
445 case NQ(i): \
446 IProductTriKernel<false, false, false>( \
447 NM(i), NM(i), NQ(i), NQ_M1(i), isModified, \
448 (const vec_t *)inarray.data(), (const vec_t *)base0.data(), \
449 (const vec_t *)base1.data(), (const vec_t *)m_weights[0].data(), \
450 (const vec_t *)m_weights[1].data(), (const vec_t *)jac.data(), \
451 (vec_t *)wsp0.data(), (vec_t *)outarray.data()); \
452 break;
453
454 // outer loop case over modes
455#undef IPRODUCTWRTBASE_M
456#define IPRODUCTWRTBASE_M(r, i) \
457 case NM(i): \
458 { \
459 switch (nquad0) \
460 { \
461 BOOST_PP_FOR_##r((NM(i), NM_P1(i), BOOST_PP_MUL(2, NM(i))), \
462 STDLEV2TEST1, STDLEV2UPDATE1, \
463 IPRODUCTWRTBASE_Q) default : IPRODUCTWRTBASE_DEF; \
464 break; \
465 } \
466 } \
467 break;
468
469 // templated cases on equi-ordered modes and standard quad usage
470 // where quad order goes from mode order to 2(*mode order)
471 if ((order0 == order1) && (nquad0 == nquad1 + 1))
472 {
473 switch (order0)
474 {
475 BOOST_PP_FOR((SMIN, 0, SMAX), STDLEV2TEST, STDLEV2UPDATE,
477 default:
479 break;
480 }
481 }
482 else
483 {
485 }
486 }
487}
488
490 const int dir, const Array<OneD, const NekDouble> &inarray,
491 Array<OneD, NekDouble> &outarray)
492{
493 int nquad0 = m_base[0]->GetNumPoints();
494 int nquad1 = m_base[1]->GetNumPoints();
495 int nqtot = nquad0 * nquad1;
496 Array<OneD, NekDouble> tmpQuad(nqtot);
497
498 // multiply by 2/(1-z1)
499 StdFacKey fackey(eTwoOverOneMinusZ1, m_base[1]->GetBasisKey());
501 for (int i = 0; i < nquad1; ++i)
502 {
503 Vmath::Smul(nquad0, gfac[i], &inarray[0] + i * nquad0, 1,
504 &tmpQuad[0] + i * nquad0, 1);
505 }
506
507 const Array<OneD, const NekDouble> one(1, 1.0);
508 switch (dir)
509 {
510 case 0:
511 v_IProductWRTBaseKernel(m_base[0]->GetDbdata(),
512 m_base[1]->GetBdata(), tmpQuad, outarray,
513 one, false);
514 break;
515 case 1:
516 {
518
519 // multiply by 0.5*(1-z0)
520 StdFacKey fackey1(eHalfMultOnePlusZ0, m_base[0]->GetBasisKey());
521 gfac = GetStdFac(fackey1);
522 for (int i = 0; i < nquad1; ++i)
523 {
524 Vmath::Vmul(nquad0, &gfac[0], 1, &tmpQuad[0] + i * nquad0, 1,
525 &tmpQuad[0] + i * nquad0, 1);
526 }
527
528 v_IProductWRTBaseKernel(m_base[0]->GetDbdata(),
529 m_base[1]->GetBdata(), tmpQuad, tmpCoeff,
530 one, false);
531
532 v_IProductWRTBaseKernel(m_base[0]->GetBdata(),
533 m_base[1]->GetDbdata(), inarray, outarray,
534 one, false);
535
536 Vmath::Vadd(m_ncoeffs, &tmpCoeff[0], 1, &outarray[0], 1,
537 &outarray[0], 1);
538 break;
539 }
540 default:
541 {
542 ASSERTL1(false, "input dir is out of range");
543 break;
544 }
545 }
546}
547
548//---------------------------------------
549// Evaluation functions
550//---------------------------------------
551
554{
555 NekDouble d1 = 1. - xi[1];
556 if (fabs(d1) < NekConstants::kNekZeroTol)
557 {
558 if (d1 >= 0.)
559 {
561 }
562 else
563 {
565 }
566 }
567 eta[0] = 2. * (1. + xi[0]) / d1 - 1.0;
568 eta[1] = xi[1];
569}
570
573{
574 xi[0] = (1.0 + eta[0]) * (1.0 - eta[1]) * 0.5 - 1.0;
575 xi[1] = eta[1];
576}
577
578void StdTriExp::v_FillMode(const int mode, Array<OneD, NekDouble> &outarray)
579{
580 int i, m;
581 int nquad0 = m_base[0]->GetNumPoints();
582 int nquad1 = m_base[1]->GetNumPoints();
583 int order0 = m_base[0]->GetNumModes();
584 int order1 = m_base[1]->GetNumModes();
585 int mode0 = 0;
586 Array<OneD, const NekDouble> base0 = m_base[0]->GetBdata();
587 Array<OneD, const NekDouble> base1 = m_base[1]->GetBdata();
588
589 ASSERTL2(mode <= m_ncoeffs, "calling argument mode is larger than "
590 "total expansion order");
591
592 m = order1;
593 for (i = 0; i < order0; ++i, m += order1 - i)
594 {
595 if (m > mode)
596 {
597 mode0 = i;
598 break;
599 }
600 }
601
602 // deal with top vertex mode in modified basis
603 if (mode == 1 && m_base[0]->GetBasisType() == LibUtilities::eModified_A)
604 {
605 Vmath::Fill(nquad0 * nquad1, 1.0, outarray, 1);
606 }
607 else
608 {
609 for (i = 0; i < nquad1; ++i)
610 {
611 Vmath::Vcopy(nquad0, (NekDouble *)(base0.data() + mode0 * nquad0),
612 1, &outarray[0] + i * nquad0, 1);
613 }
614 }
615
616 for (i = 0; i < nquad0; ++i)
617 {
618 Vmath::Vmul(nquad1, (NekDouble *)(base1.data() + mode * nquad1), 1,
619 &outarray[0] + i, nquad0, &outarray[0] + i, nquad0);
620 }
621}
622
624 const Array<OneD, const NekDouble> &coords, int mode)
625{
627 LocCoordToLocCollapsed(coords, coll);
628
629 // From mode we need to determine mode0 and mode1 in the (p,q)
630 // direction. mode1 can be directly inferred from mode.
631 const int nm1 = m_base[1]->GetNumModes();
632 const double c = 1 + 2 * nm1;
633 const int mode0 = floor(0.5 * (c - sqrt(c * c - 8 * mode)));
634
635 if (mode == 1 && m_base[0]->GetBasisType() == LibUtilities::eModified_A)
636 {
637 // Account for collapsed vertex.
638 return StdExpansion::BaryEvaluateBasis<1>(coll[1], 1);
639 }
640 else
641 {
642 return StdExpansion::BaryEvaluateBasis<0>(coll[0], mode0) *
643 StdExpansion::BaryEvaluateBasis<1>(coll[1], mode);
644 }
645}
646
648 const Array<OneD, NekDouble> &coord,
649 const Array<OneD, const NekDouble> &inarray,
650 std::array<NekDouble, 3> &firstOrderDerivs)
651{
652 // Collapse coordinates
653 Array<OneD, NekDouble> coll(2, 0.0);
654 LocCoordToLocCollapsed(coord, coll);
655
656 // If near singularity do the old interpolation matrix method
657 if ((1 - coll[1]) < 1e-5)
658 {
659 int totPoints = GetTotPoints();
660 Array<OneD, NekDouble> EphysDeriv0(totPoints), EphysDeriv1(totPoints);
661 v_PhysDeriv(inarray, EphysDeriv0, EphysDeriv1, NullNekDouble1DArray);
662
664 I[0] = GetBase()[0]->GetI(coll);
665 I[1] = GetBase()[1]->GetI(coll + 1);
666
667 firstOrderDerivs[0] = PhysEvaluate(I, EphysDeriv0);
668 firstOrderDerivs[1] = PhysEvaluate(I, EphysDeriv1);
669 return PhysEvaluate(I, inarray);
670 }
671
672 // set up geometric factor: 2.0/(1.0-z1)
673 NekDouble fac0 = 2 / (1 - coll[1]);
674
675 NekDouble val = BaryTensorDeriv(coll, inarray, firstOrderDerivs);
676
677 // Copy d0 into temp for d1
678 NekDouble temp;
679 temp = firstOrderDerivs[0];
680
681 // Multiply by geometric factor
682 firstOrderDerivs[0] = firstOrderDerivs[0] * fac0;
683
684 // set up geometric factor: (1+z0)/(1-z1)
685 NekDouble fac1 = fac0 * (coll[0] + 1) / 2;
686
687 // Multiply out_d0 by geometric factor and add to out_d1
688 firstOrderDerivs[1] += fac1 * temp;
689
690 return val;
691}
692
694{
695 return 3;
696}
697
699{
700 return 3;
701}
702
707
709{
711 "BasisType is not a boundary interior form");
713 "BasisType is not a boundary interior form");
714
715 return 3 + (GetBasisNumModes(0) - 2) + 2 * (GetBasisNumModes(1) - 2);
716}
717
719{
721 "BasisType is not a boundary interior form");
723 "BasisType is not a boundary interior form");
724
725 return GetBasisNumModes(0) + 2 * GetBasisNumModes(1);
726}
727
728int StdTriExp::v_GetTraceNcoeffs(const int i) const
729{
730 ASSERTL2(i >= 0 && i <= 2, "edge id is out of range");
731
732 if (i == 0)
733 {
734 return GetBasisNumModes(0);
735 }
736 else
737 {
738 return GetBasisNumModes(1);
739 }
740}
741
743{
744 ASSERTL2(i >= 0 && i <= 2, "edge id is out of range");
745
746 if (i == 0)
747 {
748 return GetBasisNumModes(0) - 2;
749 }
750 else
751 {
752 return GetBasisNumModes(1) - 2;
753 }
754}
755
756int StdTriExp::v_GetTraceNumPoints(const int i) const
757{
758 ASSERTL2((i >= 0) && (i <= 2), "edge id is out of range");
759
760 if (i == 0)
761 {
762 return GetNumPoints(0);
763 }
764 else
765 {
766 return GetNumPoints(1);
767 }
768}
769
771 const std::vector<unsigned int> &nummodes, int &modes_offset)
772{
774 nummodes[modes_offset], nummodes[modes_offset + 1]);
775 modes_offset += 2;
776
777 return nmodes;
778}
779
781 Array<OneD, NekDouble> &coords_1,
782 [[maybe_unused]] Array<OneD, NekDouble> &coords_2)
783{
784 Array<OneD, const NekDouble> z0 = m_base[0]->GetZ();
785 Array<OneD, const NekDouble> z1 = m_base[1]->GetZ();
786 int nq0 = GetNumPoints(0);
787 int nq1 = GetNumPoints(1);
788 int i, j;
789
790 for (i = 0; i < nq1; ++i)
791 {
792 for (j = 0; j < nq0; ++j)
793 {
794 coords_0[i * nq0 + j] = (1 + z0[j]) * (1 - z1[i]) / 2.0 - 1.0;
795 }
796 Vmath::Fill(nq0, z1[i], &coords_1[0] + i * nq0, 1);
797 }
798}
799
801{
802 return m_base[0]->GetBasisType() == LibUtilities::eModified_A &&
803 m_base[1]->GetBasisType() == LibUtilities::eModified_B;
804}
805
807 const int i, [[maybe_unused]] const int j,
808 [[maybe_unused]] bool UseGLL) const
809{
810 ASSERTL2(i >= 0 && i <= 2, "edge id is out of range");
811
812 // Get basiskey (0 or 1) according to edge id i
813 int dir = (i != 0);
814
815 switch (m_base[dir]->GetBasisType())
816 {
819 {
820 switch (m_base[dir]->GetPointsType())
821 {
824 {
825 return m_base[dir]->GetBasisKey();
826 }
827 break;
828 default:
829 {
831 "Unexpected points distribution " +
833 [m_base[dir]->GetPointsType()] +
834 " in StdTriExp::v_GetTraceBasisKey");
835 }
836 }
837 }
838 break;
840 {
841 switch (m_base[dir]->GetPointsType())
842 {
845 {
847 m_base[dir]->GetNumModes(),
848 m_base[dir]->GetPointsKey());
849 }
850 break;
852 {
854 m_base[dir]
855 ->GetBasisKey()
856 .GetPointsKey()
857 .GetNumPoints() +
858 1,
861 m_base[dir]->GetNumModes(),
862 pkey);
863 }
864 break;
865 case LibUtilities::eGaussRadauMAlpha1Beta0:
866 {
868 m_base[dir]
869 ->GetBasisKey()
870 .GetPointsKey()
871 .GetNumPoints() +
872 1,
875 m_base[dir]->GetNumModes(),
876 pkey);
877 }
878 break;
879 // Currently this does not increase the points by
880 // 1 since when using this quadrature we are
881 // presuming it is already been increased by one
882 // when comopared to
883 // GaussRadauMAlpha1Beta0. Currently used in the
884 // GJP option
885 //
886 // Note have put down it back to numpoints +1 to
887 // test for use on tri faces and GJP.
889 {
891 m_base[dir]
892 ->GetBasisKey()
893 .GetPointsKey()
894 .GetNumPoints() +
895 1,
898 m_base[dir]->GetNumModes(),
899 pkey);
900 }
901 break;
903 {
905 m_base[dir]
906 ->GetBasisKey()
907 .GetPointsKey()
908 .GetNumPoints() +
909 1,
912 m_base[dir]->GetNumModes(),
913 pkey);
914 }
915 break;
916 default:
917 {
919 "Unexpected points distribution " +
921 [m_base[dir]->GetPointsType()] +
922 " in StdTriExp::v_GetTraceBasisKey");
923 }
924 }
925 }
926 break;
928 {
929 switch (m_base[dir]->GetPointsType())
930 {
933 {
935 m_base[dir]->GetNumModes(),
936 m_base[dir]->GetPointsKey());
937 }
938 break;
939 default:
940 {
942 "Unexpected points distribution " +
944 [m_base[dir]->GetPointsType()] +
945 " in StdTriExp::v_GetTraceBasisKey");
946 }
947 }
948 }
949 break;
951 {
952 switch (m_base[dir]->GetPointsType())
953 {
956 {
958 m_base[dir]->GetNumModes(),
959 m_base[dir]->GetPointsKey());
960 }
961 break;
963 {
965 m_base[dir]
966 ->GetBasisKey()
967 .GetPointsKey()
968 .GetNumPoints() +
969 1,
972 m_base[dir]->GetNumModes(),
973 pkey);
974 }
975 break;
976 case LibUtilities::eGaussRadauMAlpha1Beta0:
977 {
979 m_base[dir]
980 ->GetBasisKey()
981 .GetPointsKey()
982 .GetNumPoints() +
983 1,
986 m_base[dir]->GetNumModes(),
987 pkey);
988 }
989 break;
990 default:
991 {
993 "Unexpected points distribution " +
995 [m_base[dir]->GetPointsType()] +
996 " in StdTriExp::v_GetTraceBasisKey");
997 }
998 }
999 }
1000 break;
1001 default:
1002 {
1004 "Information not available to set edge key");
1005 }
1006 }
1008}
1009
1010//--------------------------
1011// Mappings
1012//--------------------------
1013
1014int StdTriExp::v_GetVertexMap(const int localVertexId, bool useCoeffPacking)
1015{
1018 "Mapping not defined for this type of basis");
1019
1020 int localDOF = 0;
1021 if (useCoeffPacking == true)
1022 {
1023 switch (localVertexId)
1024 {
1025 case 0:
1026 {
1027 localDOF = 0;
1028 break;
1029 }
1030 case 1:
1031 {
1032 localDOF = 1;
1033 break;
1034 }
1035 case 2:
1036 {
1037 localDOF = m_base[1]->GetNumModes();
1038 break;
1039 }
1040 default:
1041 {
1042 ASSERTL0(false, "eid must be between 0 and 2");
1043 break;
1044 }
1045 }
1046 }
1047 else // follow book format for vertex indexing.
1048 {
1049 switch (localVertexId)
1050 {
1051 case 0:
1052 {
1053 localDOF = 0;
1054 break;
1055 }
1056 case 1:
1057 {
1058 localDOF = m_base[1]->GetNumModes();
1059 break;
1060 }
1061 case 2:
1062 {
1063 localDOF = 1;
1064 break;
1065 }
1066 default:
1067 {
1068 ASSERTL0(false, "eid must be between 0 and 2");
1069 break;
1070 }
1071 }
1072 }
1073
1074 return localDOF;
1075}
1076
1078{
1081 "Expansion not of a proper type");
1082
1083 int i, j;
1084 int cnt = 0;
1085 int nummodes0, nummodes1;
1086 int startvalue;
1087 if (outarray.size() != GetNcoeffs() - NumBndryCoeffs())
1088 {
1090 }
1091
1092 nummodes0 = m_base[0]->GetNumModes();
1093 nummodes1 = m_base[1]->GetNumModes();
1094
1095 startvalue = 2 * nummodes1;
1096
1097 for (i = 0; i < nummodes0 - 2; i++)
1098 {
1099 for (j = 0; j < nummodes1 - 3 - i; j++)
1100 {
1101 outarray[cnt++] = startvalue + j;
1102 }
1103 startvalue += nummodes1 - 2 - i;
1104 }
1105}
1106
1108{
1111 "Expansion not of expected type");
1112 int i;
1113 int cnt;
1114 int nummodes0, nummodes1;
1115 int value;
1116
1117 if (outarray.size() != NumBndryCoeffs())
1118 {
1120 }
1121
1122 nummodes0 = m_base[0]->GetNumModes();
1123 nummodes1 = m_base[1]->GetNumModes();
1124
1125 value = 2 * nummodes1 - 1;
1126 for (i = 0; i < value; i++)
1127 {
1128 outarray[i] = i;
1129 }
1130 cnt = value;
1131
1132 for (i = 0; i < nummodes0 - 2; i++)
1133 {
1134 outarray[cnt++] = value;
1135 value += nummodes1 - 2 - i;
1136 }
1137}
1138
1139void StdTriExp::v_GetTraceCoeffMap(const unsigned int eid,
1140 Array<OneD, unsigned int> &maparray)
1141{
1142
1145 "Mapping not defined for this type of basis");
1146
1147 ASSERTL1(eid < 3, "eid must be between 0 and 2");
1148
1149 int i;
1150 int order0 = m_base[0]->GetNumModes();
1151 int order1 = m_base[1]->GetNumModes();
1152 int numModes = (eid == 0) ? order0 : order1;
1153
1154 if (maparray.size() != numModes)
1155 {
1156 maparray = Array<OneD, unsigned int>(numModes);
1157 }
1158
1159 switch (eid)
1160 {
1161 case 0:
1162 {
1163 int cnt = 0;
1164 for (i = 0; i < numModes; cnt += order1 - i, ++i)
1165 {
1166 maparray[i] = cnt;
1167 }
1168 break;
1169 }
1170 case 1:
1171 {
1172 maparray[0] = order1;
1173 maparray[1] = 1;
1174 for (i = 2; i < numModes; i++)
1175 {
1176 maparray[i] = order1 - 1 + i;
1177 }
1178 break;
1179 }
1180 case 2:
1181 {
1182 for (i = 0; i < numModes; i++)
1183 {
1184 maparray[i] = i;
1185 }
1186 break;
1187 }
1188 default:
1189 ASSERTL0(false, "eid must be between 0 and 2");
1190 break;
1191 }
1192}
1193
1195 const int eid, Array<OneD, unsigned int> &maparray,
1196 Array<OneD, int> &signarray, const Orientation edgeOrient)
1197{
1200 "Mapping not defined for this type of basis");
1201 int i;
1202 const int nummodes1 = m_base[1]->GetNumModes();
1203 const int nEdgeIntCoeffs = GetTraceNcoeffs(eid) - 2;
1204
1205 if (maparray.size() != nEdgeIntCoeffs)
1206 {
1207 maparray = Array<OneD, unsigned int>(nEdgeIntCoeffs);
1208 }
1209
1210 if (signarray.size() != nEdgeIntCoeffs)
1211 {
1212 signarray = Array<OneD, int>(nEdgeIntCoeffs, 1);
1213 }
1214 else
1215 {
1216 fill(signarray.data(), signarray.data() + nEdgeIntCoeffs, 1);
1217 }
1218
1219 switch (eid)
1220 {
1221 case 0:
1222 {
1223 int cnt = 2 * nummodes1 - 1;
1224 for (i = 0; i < nEdgeIntCoeffs; cnt += nummodes1 - 2 - i, ++i)
1225 {
1226 maparray[i] = cnt;
1227 }
1228 break;
1229 }
1230 case 1:
1231 {
1232 for (i = 0; i < nEdgeIntCoeffs; i++)
1233 {
1234 maparray[i] = nummodes1 + 1 + i;
1235 }
1236 break;
1237 }
1238 case 2:
1239 {
1240 for (i = 0; i < nEdgeIntCoeffs; i++)
1241 {
1242 maparray[i] = 2 + i;
1243 }
1244 break;
1245 }
1246 default:
1247 {
1248 ASSERTL0(false, "eid must be between 0 and 2");
1249 break;
1250 }
1251 }
1252
1253 if (edgeOrient == eBackwards)
1254 {
1255 for (i = 1; i < nEdgeIntCoeffs; i += 2)
1256 {
1257 signarray[i] = -1;
1258 }
1259 }
1260}
1261
1262//---------------------------------------
1263// Wrapper functions
1264//---------------------------------------
1265
1267{
1268
1269 MatrixType mtype = mkey.GetMatrixType();
1270
1271 DNekMatSharedPtr Mat;
1272
1273 switch (mtype)
1274 {
1276 {
1277 int nq0, nq1, nq;
1278
1279 nq0 = m_base[0]->GetNumPoints();
1280 nq1 = m_base[1]->GetNumPoints();
1281
1282 // take definition from key
1284 {
1285 nq = (int)mkey.GetConstFactor(eFactorConst);
1286 }
1287 else
1288 {
1289 nq = max(nq0, nq1);
1290 }
1291
1294 Array<OneD, NekDouble> coll(2);
1296 Array<OneD, NekDouble> tmp(nq0);
1297
1298 Mat = MemoryManager<DNekMat>::AllocateSharedPtr(neq, nq0 * nq1);
1299 int cnt = 0;
1300
1301 for (int i = 0; i < nq; ++i)
1302 {
1303 for (int j = 0; j < nq - i; ++j, ++cnt)
1304 {
1305 coords[cnt] = Array<OneD, NekDouble>(2);
1306 coords[cnt][0] = -1.0 + 2 * j / (NekDouble)(nq - 1);
1307 coords[cnt][1] = -1.0 + 2 * i / (NekDouble)(nq - 1);
1308 }
1309 }
1310
1311 for (int i = 0; i < neq - 1; ++i)
1312 {
1313 LocCoordToLocCollapsed(coords[i], coll);
1314
1315 I[0] = m_base[0]->GetI(coll);
1316 I[1] = m_base[1]->GetI(coll + 1);
1317
1318 // interpolate first coordinate direction
1319 for (int j = 0; j < nq1; ++j)
1320 {
1321 NekDouble fac = (I[1]->GetPtr())[j];
1322 Vmath::Smul(nq0, fac, I[0]->GetPtr(), 1, tmp, 1);
1323
1324 Vmath::Vcopy(nq0, &tmp[0], 1,
1325 Mat->GetRawPtr() + j * nq0 * neq + i, neq);
1326 }
1327 }
1328
1329 // evaluate top vertex as average of all interpolation
1330 // along collapsed coordinates at singular vertex
1331 coll[1] = 1.0;
1332 I[1] = m_base[1]->GetI(coll + 1);
1333
1334 // interpolate first coordinate direction
1335 for (int j = 0; j < nq1; ++j)
1336 {
1337 NekDouble fac = (I[1]->GetPtr())[j] / ((NekDouble)nq0);
1338
1339 Vmath::Fill(nq0, fac,
1340 Mat->GetRawPtr() + j * nq0 * neq + neq - 1, neq);
1341 }
1342
1343 break;
1344 }
1345 case ePhysInterpToGLL:
1346 {
1347 int nq0, nq1, nq;
1348
1349 nq0 = m_base[0]->GetNumPoints();
1350 nq1 = m_base[1]->GetNumPoints();
1351
1352 // take definition from key
1354 {
1355 nq = (int)mkey.GetConstFactor(eFactorConst);
1356 }
1357 else
1358 {
1359 nq = max(nq0, nq1);
1360 }
1361
1363 Array<OneD, NekDouble> coords(2);
1364 Array<OneD, NekDouble> coll(2);
1366 Array<OneD, NekDouble> tmp(nq0);
1367
1368 Mat = MemoryManager<DNekMat>::AllocateSharedPtr(neq, nq0 * nq1);
1369
1371
1373 LibUtilities::PointsManager()[key]->GetPoints(x, y);
1374
1375 // set up nodal points in a similar mannger to equispaced
1376 // points startign at bottom and working upwards left to
1377 // right
1378
1379 int row = 0;
1380 // First Vertex
1381 coords[0] = x[0];
1382 coords[1] = y[0];
1383 LocCoordToLocCollapsed(coords, coll);
1384
1385 I[0] = m_base[0]->GetI(coll);
1386 I[1] = m_base[1]->GetI(coll + 1);
1387
1388 // interpolate first coordinate direction
1389 for (int j = 0; j < nq1; ++j)
1390 {
1391 NekDouble fac = (I[1]->GetPtr())[j];
1392 Vmath::Smul(nq0, fac, I[0]->GetPtr(), 1, tmp, 1);
1393
1394 Vmath::Vcopy(nq0, &tmp[0], 1,
1395 Mat->GetRawPtr() + j * nq0 * neq + row, neq);
1396 }
1397 row++;
1398
1399 // First edge
1400 for (int i = 0; i < nq - 2; ++i)
1401 {
1402 coords[0] = x[3 + i];
1403 coords[1] = y[3 + i];
1404 LocCoordToLocCollapsed(coords, coll);
1405
1406 I[0] = m_base[0]->GetI(coll);
1407 I[1] = m_base[1]->GetI(coll + 1);
1408
1409 // interpolate first coordinate direction
1410 for (int j = 0; j < nq1; ++j)
1411 {
1412 NekDouble fac = (I[1]->GetPtr())[j];
1413 Vmath::Smul(nq0, fac, I[0]->GetPtr(), 1, tmp, 1);
1414
1415 Vmath::Vcopy(nq0, &tmp[0], 1,
1416 Mat->GetRawPtr() + j * nq0 * neq + row, neq);
1417 }
1418 row++;
1419 }
1420
1421 // Second Vertex
1422 coords[0] = x[1];
1423 coords[1] = y[1];
1424 LocCoordToLocCollapsed(coords, coll);
1425
1426 I[0] = m_base[0]->GetI(coll);
1427 I[1] = m_base[1]->GetI(coll + 1);
1428
1429 // interpolate first coordinate direction
1430 for (int j = 0; j < nq1; ++j)
1431 {
1432 NekDouble fac = (I[1]->GetPtr())[j];
1433 Vmath::Smul(nq0, fac, I[0]->GetPtr(), 1, tmp, 1);
1434
1435 Vmath::Vcopy(nq0, &tmp[0], 1,
1436 Mat->GetRawPtr() + j * nq0 * neq + row, neq);
1437 }
1438 row++;
1439
1440 int cnt = 0;
1441 // other edges and interior
1442 for (int i = 0; i < nq - 2; ++i)
1443 {
1444
1445 // edge 3 (reversing counter-clockwise ordering)
1446 coords[0] = x[3 * (nq - 1) - i - 1];
1447 coords[1] = y[3 * (nq - 1) - i - 1];
1448 // coords[0] = x[3 + 2*(nq-2)+i]; coords[1] = y[3 + 2*(nq-2)+i];
1449 LocCoordToLocCollapsed(coords, coll);
1450
1451 I[0] = m_base[0]->GetI(coll);
1452 I[1] = m_base[1]->GetI(coll + 1);
1453
1454 // interpolate first coordinate direction
1455 for (int j = 0; j < nq1; ++j)
1456 {
1457 NekDouble fac = (I[1]->GetPtr())[j];
1458 Vmath::Smul(nq0, fac, I[0]->GetPtr(), 1, tmp, 1);
1459
1460 Vmath::Vcopy(nq0, &tmp[0], 1,
1461 Mat->GetRawPtr() + j * nq0 * neq + row, neq);
1462 }
1463 row++;
1464
1465 for (int j = 0; j < nq - 3 - i; ++j)
1466 {
1467 coords[0] = x[3 * (nq - 1) + cnt];
1468 coords[1] = y[3 * (nq - 1) + cnt];
1469 LocCoordToLocCollapsed(coords, coll);
1470
1471 I[0] = m_base[0]->GetI(coll);
1472 I[1] = m_base[1]->GetI(coll + 1);
1473
1474 // interpolate first coordinate direction
1475 for (int j = 0; j < nq1; ++j)
1476 {
1477 NekDouble fac = (I[1]->GetPtr())[j];
1478 Vmath::Smul(nq0, fac, I[0]->GetPtr(), 1, tmp, 1);
1479
1480 Vmath::Vcopy(nq0, &tmp[0], 1,
1481 Mat->GetRawPtr() + j * nq0 * neq + row,
1482 neq);
1483 }
1484 row++;
1485 cnt++;
1486 }
1487
1488 // edge 2
1489 coords[0] = x[3 + (nq - 2) + i];
1490 coords[1] = y[3 + (nq - 2) + i];
1491 LocCoordToLocCollapsed(coords, coll);
1492
1493 I[0] = m_base[0]->GetI(coll);
1494 I[1] = m_base[1]->GetI(coll + 1);
1495
1496 // interpolate first coordinate direction
1497 for (int j = 0; j < nq1; ++j)
1498 {
1499 NekDouble fac = (I[1]->GetPtr())[j];
1500 Vmath::Smul(nq0, fac, I[0]->GetPtr(), 1, tmp, 1);
1501
1502 Vmath::Vcopy(nq0, &tmp[0], 1,
1503 Mat->GetRawPtr() + j * nq0 * neq + row, neq);
1504 }
1505 row++;
1506 }
1507
1508 // evaluate top vertex as average of all interpolation
1509 // along collapsed coordinates at singular vertex
1510 coll[1] = 1.0;
1511 I[1] = m_base[1]->GetI(coll + 1);
1512
1513 // interpolate first coordinate direction
1514 for (int j = 0; j < nq1; ++j)
1515 {
1516 NekDouble fac = (I[1]->GetPtr())[j] / ((NekDouble)nq0);
1517
1518 Vmath::Fill(nq0, fac,
1519 Mat->GetRawPtr() + j * nq0 * neq + neq - 1, neq);
1520 }
1521
1522 break;
1523 }
1524 case eEquiSpacedToPhys:
1525 {
1526 int nm0 = m_base[0]->GetNumPoints();
1527 int nm1 = m_base[1]->GetNumPoints();
1528 int neq;
1529
1530 // take definition from key
1532 {
1533 neq = (int)mkey.GetConstFactor(eFactorConst);
1534 }
1535 else
1536 {
1537 neq = max(nm0, nm1);
1538 }
1539
1540 // set up an exansion with the same number of modes as neq;
1542 m_base[0]->GetPointsKey());
1544 m_base[1]->GetPointsKey());
1545
1546 StdTriExp Exp2D(ba, bb);
1547 int ncoeffs = Exp2D.GetNcoeffs();
1548
1549 // Get hold of equispaced to coeff matrix
1550 ConstFactorMap cmap;
1551 cmap[eFactorConst] = neq;
1552 StdMatrixKey Ikey(eEquiSpacedToCoeffs, DetShapeType(), *this, cmap);
1553 DNekMatSharedPtr intmat = Exp2D.GetStdMatrix(Ikey);
1554
1555 int nqtot = GetTotPoints();
1556
1557 // generate a matrix
1558 Mat = MemoryManager<DNekMat>::AllocateSharedPtr(nqtot, ncoeffs);
1559 NekDouble *ptr = Mat->GetRawPtr();
1560
1561 Array<OneD, NekDouble> qmode(nqtot);
1562
1563 // Get first mode at quadrature points
1564 Exp2D.FillMode(0, qmode);
1565
1566 // first part of matrix-matrix multiply intiailising out matrix
1567 for (int j = 0; j < ncoeffs; ++j)
1568 {
1569 NekDouble val = (*intmat)(0, j);
1570 Vmath::Smul(nqtot, val, qmode.data(), 1, ptr + j * nqtot, 1);
1571 }
1572
1573 for (int i = 1; i < ncoeffs; ++i)
1574 {
1575 // Get mode at quadrature points
1576 Exp2D.FillMode(i, qmode);
1577
1578 for (int j = 0; j < ncoeffs; ++j)
1579 {
1580 NekDouble val = (*intmat)(i, j);
1581 Vmath::Svtvp(nqtot, val, qmode.data(), 1, ptr + j * nqtot,
1582 1, ptr + j * nqtot, 1);
1583 }
1584 }
1585 }
1586 break;
1587 default:
1588 {
1590 break;
1591 }
1592 }
1593
1594 return Mat;
1595}
1596
1598{
1599 return v_GenMatrix(mkey);
1600}
1601
1602//---------------------------------------
1603// Operator evaluation functions
1604//---------------------------------------
1605
1607 Array<OneD, NekDouble> &outarray,
1608 const StdMatrixKey &mkey)
1609{
1610 StdExpansion::MassMatrixOp_MatFree(inarray, outarray, mkey);
1611}
1612
1614 Array<OneD, NekDouble> &outarray,
1615 const StdMatrixKey &mkey)
1616{
1617 StdTriExp::v_LaplacianMatrixOp_MatFree(inarray, outarray, mkey);
1618}
1619
1620void StdTriExp::v_LaplacianMatrixOp(const int k1, const int k2,
1621 const Array<OneD, const NekDouble> &inarray,
1622 Array<OneD, NekDouble> &outarray,
1623 const StdMatrixKey &mkey)
1624{
1625 StdExpansion::LaplacianMatrixOp_MatFree(k1, k2, inarray, outarray, mkey);
1626}
1627
1629 const Array<OneD, const NekDouble> &inarray,
1630 Array<OneD, NekDouble> &outarray,
1631 const StdMatrixKey &mkey)
1632{
1633 StdExpansion::WeakDerivMatrixOp_MatFree(i, inarray, outarray, mkey);
1634}
1635
1637 Array<OneD, NekDouble> &outarray,
1638 const StdMatrixKey &mkey)
1639{
1640 StdTriExp::v_HelmholtzMatrixOp_MatFree(inarray, outarray, mkey);
1641}
1642
1644 const StdMatrixKey &mkey)
1645{
1646 int qa = m_base[0]->GetNumPoints();
1647 int qb = m_base[1]->GetNumPoints();
1648 int nmodes_a = m_base[0]->GetNumModes();
1649 int nmodes_b = m_base[1]->GetNumModes();
1650
1651 // Declare orthogonal basis.
1654
1657 StdTriExp OrthoExp(Ba, Bb);
1658
1659 Array<OneD, NekDouble> orthocoeffs(OrthoExp.GetNcoeffs());
1660
1661 // project onto physical space.
1662 OrthoExp.FwdTrans(array, orthocoeffs);
1663
1664 if (mkey.ConstFactorExists(
1665 eFactorSVVPowerKerDiffCoeff)) // Rodrigo's power kern
1666 {
1668 NekDouble SvvDiffCoeff =
1671
1672 int cnt = 0;
1673 for (int j = 0; j < nmodes_a; ++j)
1674 {
1675 for (int k = 0; k < nmodes_b - j; ++k, ++cnt)
1676 {
1677 NekDouble fac = std::max(
1678 pow((1.0 * j) / (nmodes_a - 1), cutoff * nmodes_a),
1679 pow((1.0 * k) / (nmodes_b - 1), cutoff * nmodes_b));
1680
1681 orthocoeffs[cnt] *= (SvvDiffCoeff * fac);
1682 }
1683 }
1684 }
1685 else if (mkey.ConstFactorExists(
1686 eFactorSVVDGKerDiffCoeff)) // Rodrigo/mansoor's DG kernel
1687 {
1690 int max_ab = max(nmodes_a - kSVVDGFiltermodesmin,
1691 nmodes_b - kSVVDGFiltermodesmin);
1692 max_ab = max(max_ab, 0);
1693 max_ab = min(max_ab, kSVVDGFiltermodesmax - kSVVDGFiltermodesmin);
1694
1695 int cnt = 0;
1696 for (int j = 0; j < nmodes_a; ++j)
1697 {
1698 for (int k = 0; k < nmodes_b - j; ++k, ++cnt)
1699 {
1700 int maxjk = max(j, k);
1701 maxjk = min(maxjk, kSVVDGFiltermodesmax - 1);
1702
1703 orthocoeffs[cnt] *= SvvDiffCoeff * kSVVDGFilter[max_ab][maxjk];
1704 }
1705 }
1706 }
1707 else
1708 {
1709 NekDouble SvvDiffCoeff = mkey.GetConstFactor(eFactorSVVDiffCoeff);
1710
1711 int cutoff = (int)(mkey.GetConstFactor(eFactorSVVCutoffRatio) *
1712 min(nmodes_a, nmodes_b));
1713
1714 NekDouble epsilon = 1.0;
1715 int nmodes = min(nmodes_a, nmodes_b);
1716
1717 int cnt = 0;
1718
1719 // apply SVV filter (JEL)
1720 for (int j = 0; j < nmodes_a; ++j)
1721 {
1722 for (int k = 0; k < nmodes_b - j; ++k)
1723 {
1724 if (j + k >= cutoff)
1725 {
1726 orthocoeffs[cnt] *=
1727 (SvvDiffCoeff *
1728 exp(-(j + k - nmodes) * (j + k - nmodes) /
1729 ((NekDouble)((j + k - cutoff + epsilon) *
1730 (j + k - cutoff + epsilon)))));
1731 }
1732 else
1733 {
1734 orthocoeffs[cnt] *= 0.0;
1735 }
1736 cnt++;
1737 }
1738 }
1739 }
1740
1741 // backward transform to physical space
1742 OrthoExp.BwdTrans(orthocoeffs, array);
1743}
1744
1746 const Array<OneD, const NekDouble> &inarray,
1747 Array<OneD, NekDouble> &outarray)
1748{
1749 int n_coeffs = inarray.size();
1750 int nquad0 = m_base[0]->GetNumPoints();
1751 int nquad1 = m_base[1]->GetNumPoints();
1752 Array<OneD, NekDouble> coeff(n_coeffs);
1753 Array<OneD, NekDouble> coeff_tmp(n_coeffs, 0.0);
1756 int nqtot = nquad0 * nquad1;
1757 Array<OneD, NekDouble> phys_tmp(nqtot, 0.0);
1758
1759 int nmodes0 = m_base[0]->GetNumModes();
1760 int nmodes1 = m_base[1]->GetNumModes();
1761 int numMin2 = nmodes0;
1762 int i;
1763
1764 const LibUtilities::PointsKey Pkey0(nmodes0,
1766 const LibUtilities::PointsKey Pkey1(nmodes1,
1768
1769 LibUtilities::BasisKey b0(m_base[0]->GetBasisType(), nmodes0, Pkey0);
1770 LibUtilities::BasisKey b1(m_base[1]->GetBasisType(), nmodes1, Pkey1);
1771
1772 LibUtilities::BasisKey bortho0(LibUtilities::eOrtho_A, nmodes0, Pkey0);
1773 LibUtilities::BasisKey bortho1(LibUtilities::eOrtho_B, nmodes1, Pkey1);
1774
1775 StdRegions::StdTriExpSharedPtr m_OrthoTriExp;
1777
1780 bortho0, bortho1);
1781
1782 m_TriExp->BwdTrans(inarray, phys_tmp);
1783 m_OrthoTriExp->FwdTrans(phys_tmp, coeff);
1784
1785 for (i = 0; i < n_coeffs; i++)
1786 {
1787 if (i == numMin)
1788 {
1789 coeff[i] = 0.0;
1790 numMin += numMin2 - 1;
1791 numMin2 -= 1.0;
1792 }
1793 }
1794
1795 m_OrthoTriExp->BwdTrans(coeff, phys_tmp);
1796 m_TriExp->FwdTrans(phys_tmp, outarray);
1797}
1798
1799//---------------------------------------
1800// Private helper functions
1801//---------------------------------------
1802
1804 Array<OneD, int> &conn, [[maybe_unused]] bool standard)
1805{
1806 int np1 = m_base[0]->GetNumPoints();
1807 int np2 = m_base[1]->GetNumPoints();
1808 int np = max(np1, np2);
1809
1810 conn = Array<OneD, int>(3 * (np - 1) * (np - 1));
1811
1812 int row = 0;
1813 int rowp1 = 0;
1814 int cnt = 0;
1815 for (int i = 0; i < np - 1; ++i)
1816 {
1817 rowp1 += np - i;
1818 for (int j = 0; j < np - i - 2; ++j)
1819 {
1820 conn[cnt++] = row + j;
1821 conn[cnt++] = row + j + 1;
1822 conn[cnt++] = rowp1 + j;
1823
1824 conn[cnt++] = rowp1 + j + 1;
1825 conn[cnt++] = rowp1 + j;
1826 conn[cnt++] = row + j + 1;
1827 }
1828
1829 conn[cnt++] = row + np - i - 2;
1830 conn[cnt++] = row + np - i - 1;
1831 conn[cnt++] = rowp1 + np - i - 2;
1832
1833 row += np - i;
1834 }
1835}
1836} // namespace Nektar::StdRegions
#define ASSERTL0(condition, msg)
#define NEKERROR(type, msg)
Assert Level 0 – Fundamental assert which is used whether in FULLDEBUG, DEBUG or OPT compilation mode...
#define ASSERTL1(condition, msg)
Assert Level 1 – Debugging which is used whether in FULLDEBUG or DEBUG compilation mode....
#define ASSERTL2(condition, msg)
Assert Level 2 – Debugging which is used FULLDEBUG compilation mode. This level assert is designed to...
#define sign(a, b)
return the sign(b)*a
Definition Polylib.cpp:47
#define BWDTRANS_M(r, i)
#define IPRODUCTWRTBASE_DEF
#define BWDTRANS_DEF
#define IPRODUCTWRTBASE_M(r, i)
#define STDLEV2TEST(r, state)
#define STDLEV2UPDATE(r, state)
Describes the specification for a Basis.
Definition Basis.h:45
int GetNumModes() const
Returns the order of the basis.
Definition Basis.h:74
Defines a specification for a set of points.
Definition Points.h:50
static std::shared_ptr< DataType > AllocateSharedPtr(const Args &...args)
Allocate a shared pointer from the memory pool.
void PhysTensorDeriv(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray_d0, Array< OneD, NekDouble > &outarray_d1)
Calculate the 2D derivative in the local tensor/collapsed coordinate at the physical points.
void v_IProductWRTBase(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray) override
Calculate the inner product of inarray with respect to the basis B=base0*base1 and put into outarray.
NekDouble BaryTensorDeriv(const Array< OneD, NekDouble > &coord, const Array< OneD, const NekDouble > &inarray, std::array< NekDouble, 3 > &firstOrderDerivs)
void v_PhysDeriv(const int dir, const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray) override
Calculate the derivative of the physical points in a given direction.
The base class for all shapes.
virtual void v_LaplacianMatrixOp_MatFree(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray, const StdMatrixKey &mkey)
int GetNcoeffs(void) const
This function returns the total number of coefficients used in the expansion.
int GetTotPoints() const
This function returns the total number of quadrature points used in the element.
void FillMode(const int mode, Array< OneD, NekDouble > &outarray)
This function fills the array outarray with the mode-th mode of the expansion.
void WeakDerivMatrixOp_MatFree(const int i, const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray, const StdMatrixKey &mkey)
LibUtilities::BasisType GetBasisType(const int dir) const
This function returns the type of basis used in the dir direction.
DNekMatSharedPtr GetStdMatrix(const StdMatrixKey &mkey)
void LocCoordToLocCollapsed(const Array< OneD, const NekDouble > &xi, Array< OneD, NekDouble > &eta)
Convert local cartesian coordinate xi into local collapsed coordinates eta.
void MassMatrixOp(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray, const StdMatrixKey &mkey)
virtual void v_HelmholtzMatrixOp_MatFree(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray, const StdMatrixKey &mkey)
const Array< OneD, const LibUtilities::BasisSharedPtr > & GetBase() const
This function gets the shared point to basis.
DNekMatSharedPtr CreateGeneralMatrix(const StdMatrixKey &mkey)
this function generates the mass matrix
void LaplacianMatrixOp_MatFree(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray, const StdMatrixKey &mkey)
NekDouble PhysEvaluate(const Array< OneD, const NekDouble > &coords, const Array< OneD, const NekDouble > &physvals)
This function evaluates the expansion at a single (arbitrary) point of the domain.
void GetTraceToElementMap(const int tid, Array< OneD, unsigned int > &maparray, Array< OneD, int > &signarray, Orientation traceOrient=eForwards, int P=-1, int Q=-1)
LibUtilities::ShapeType DetShapeType() const
This function returns the shape of the expansion domain.
void BwdTrans(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray)
This function performs the Backward transformation from coefficient space to physical space.
int GetTraceNcoeffs(const int i) const
This function returns the number of expansion coefficients belonging to the i-th trace.
LibUtilities::PointsType GetPointsType(const int dir) const
This function returns the type of quadrature points used in the dir direction.
void FwdTrans(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray)
LibUtilities::NekManager< StdMatrixKey, DNekBlkMat, StdMatrixKey::opLess > m_stdStaticCondMatrixManager
int GetNumPoints(const int dir) const
This function returns the number of quadrature points in the dir direction.
Array< OneD, const NekDouble > GetStdFac(const StdFacKey &mkey)
int GetBasisNumModes(const int dir) const
This function returns the number of expansion modes in the dir direction.
Array< OneD, LibUtilities::BasisSharedPtr > m_base
std::vector< Array< OneD, const NekDouble > > m_weights
void MassMatrixOp_MatFree(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray, const StdMatrixKey &mkey)
MatrixType GetMatrixType() const
NekDouble GetConstFactor(const ConstFactorType &factor) const
bool ConstFactorExists(const ConstFactorType &factor) const
void v_WeakDerivMatrixOp(const int i, const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray, const StdMatrixKey &mkey) override
int v_GetTraceNumPoints(const int i) const override
void v_BwdTrans(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray) override
Backward tranform for triangular elements.
void v_IProductWRTDerivBase(const int dir, const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray) override
void v_LocCollapsedToLocCoord(const Array< OneD, const NekDouble > &eta, Array< OneD, NekDouble > &xi) override
void v_GetCoords(Array< OneD, NekDouble > &coords_x, Array< OneD, NekDouble > &coords_y, Array< OneD, NekDouble > &coords_z) override
int v_CalcNumberOfCoefficients(const std::vector< unsigned int > &nummodes, int &modes_offset) override
const LibUtilities::BasisKey v_GetTraceBasisKey(const int i, const int j, bool UseGLL=false) const override
void v_GetSimplexEquiSpacedConnectivity(Array< OneD, int > &conn, bool standard=true) override
void v_MassMatrixOp(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray, const StdMatrixKey &mkey) override
void v_GetBoundaryMap(Array< OneD, unsigned int > &outarray) override
int v_GetNtraces() const final
void v_StdPhysDeriv(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &out_d0, Array< OneD, NekDouble > &out_d1, Array< OneD, NekDouble > &out_d2=NullNekDouble1DArray) override
Calculate the derivative of the physical points.
Definition StdTriExp.cpp:89
void v_GetTraceInteriorToElementMap(const int eid, Array< OneD, unsigned int > &maparray, Array< OneD, int > &signarray, const Orientation edgeOrient=eForwards) override
int v_GetVertexMap(int localVertexId, bool useCoeffPacking=false) override
DNekMatSharedPtr v_CreateStdMatrix(const StdMatrixKey &mkey) override
DNekMatSharedPtr v_GenMatrix(const StdMatrixKey &mkey) override
int v_GetTraceNcoeffs(const int i) const override
void v_GetTraceCoeffMap(const unsigned int traceid, Array< OneD, unsigned int > &maparray) override
bool v_IsBoundaryInteriorExpansion() const override
void v_FillMode(const int mode, Array< OneD, NekDouble > &outarray) override
void v_ReduceOrderCoeffs(int numMin, const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray) override
void v_FwdTransBndConstrained(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray) override
LibUtilities::ShapeType v_DetShapeType() const override
int v_GetTraceIntNcoeffs(const int i) const override
int v_NumDGBndryCoeffs() const override
void v_LocCoordToLocCollapsed(const Array< OneD, const NekDouble > &xi, Array< OneD, NekDouble > &eta) override
NekDouble v_PhysEvaluateBasis(const Array< OneD, const NekDouble > &coords, int mode) final
void v_HelmholtzMatrixOp(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray, const StdMatrixKey &mkey) override
NekDouble v_PhysEvalFirstDeriv(const Array< OneD, NekDouble > &coord, const Array< OneD, const NekDouble > &inarray, std::array< NekDouble, 3 > &firstOrderDerivs) override
void v_GetInteriorMap(Array< OneD, unsigned int > &outarray) override
int v_GetNverts() const final
void v_LaplacianMatrixOp(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray, const StdMatrixKey &mkey) override
void v_IProductWRTBaseKernel(const Array< OneD, const NekDouble > &base0, const Array< OneD, const NekDouble > &base1, const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray, const Array< OneD, NekDouble > &jac, const bool Deformed, const bool CollDir0=false, const bool CollDir1=false) override
Inner product of inarray over region with respect to the expansion basis (this)->m_base[0] and return...
void v_SVVLaplacianFilter(Array< OneD, NekDouble > &array, const StdMatrixKey &mkey) override
int v_NumBndryCoeffs() const override
static void Dgemv(const char &trans, const int &m, const int &n, const double &alpha, const double *a, const int &lda, const double *x, const int &incx, const double &beta, double *y, const int &incy)
BLAS level 2: Matrix vector multiply y = alpha A x plus beta y where A[m x n].
Definition Blas.hpp:152
static void Dscal(const int &n, const double &alpha, double *x, const int &incx)
BLAS level 1: x = alpha x.
Definition Blas.hpp:124
constexpr int getNumberOfCoefficients(int Na, int Nb)
static const BasisKey NullBasisKey(eNoBasisType, 0, NullPointsKey)
Defines a null basis with no type or points.
const std::string kPointsTypeStr[]
PointsManagerT & PointsManager(void)
@ eGaussRadauMLegendre
1D Gauss-Radau-Legendre quadrature points, pinned at x=-1
Definition PointsType.h:47
@ eGaussLegendreWithMP
1D Gauss-Legendre quadrature points with additional x=-1 and x=1 end points
Definition PointsType.h:95
@ eNodalTriElec
2D Nodal Electrostatic Points on a Triangle
Definition PointsType.h:81
@ eGaussLobattoLegendre
1D Gauss-Lobatto-Legendre quadrature points
Definition PointsType.h:51
@ eGaussLegendreWithM
1D Gauss-Legendre quadrature points with additional x=-1 point
Definition PointsType.h:97
@ ePolyEvenlySpaced
1D Evenly-spaced points using Lagrange polynomial
Definition PointsType.h:73
@ eModified_B
Principle Modified Functions .
Definition BasisType.h:49
@ eOrtho_A
Principle Orthogonal Functions .
Definition BasisType.h:42
@ eGLL_Lagrange
Lagrange for SEM basis .
Definition BasisType.h:56
@ eOrtho_B
Principle Orthogonal Functions .
Definition BasisType.h:44
@ eModified_A
Principle Modified Functions .
Definition BasisType.h:48
static const NekDouble kNekZeroTol
const int kSVVDGFiltermodesmin
tinysimd::scalarT< double > vec_t
const int kSVVDGFiltermodesmax
const NekDouble kSVVDGFilter[9][11]
std::shared_ptr< StdTriExp > StdTriExpSharedPtr
Definition StdTriExp.h:177
std::map< ConstFactorType, NekDouble > ConstFactorMap
std::shared_ptr< StdSegExp > StdSegExpSharedPtr
Definition StdSegExp.h:182
static Array< OneD, NekDouble > NullNekDouble1DArray
std::shared_ptr< DNekMat > DNekMatSharedPtr
void Vmul(int n, const T *x, const int incx, const T *y, const int incy, T *z, const int incz)
Multiply vector z = x*y.
Definition Vmath.hpp:72
void Svtvp(int n, const T alpha, const T *x, const int incx, const T *y, const int incy, T *z, const int incz)
Svtvp (scalar times vector plus vector): z = alpha*x + y.
Definition Vmath.hpp:396
void Vvtvp(int n, const T *w, const int incw, const T *x, const int incx, const T *y, const int incy, T *z, const int incz)
vvtvp (vector times vector plus vector): z = w*x + y
Definition Vmath.hpp:366
void Vadd(int n, const T *x, const int incx, const T *y, const int incy, T *z, const int incz)
Add vector z = x+y.
Definition Vmath.hpp:180
void Smul(int n, const T alpha, const T *x, const int incx, T *y, const int incy)
Scalar multiply y = alpha*x.
Definition Vmath.hpp:100
void Sdiv(int n, const T alpha, const T *x, const int incx, T *y, const int incy)
Scalar multiply y = alpha/x.
Definition Vmath.hpp:154
void Fill(int n, const T alpha, T *x, const int incx)
Fill a vector with a constant value.
Definition Vmath.hpp:54
void Sadd(int n, const T alpha, const T *x, const int incx, T *y, const int incy)
Add vector y = alpha + x.
Definition Vmath.hpp:194
void Vcopy(int n, const T *x, const int incx, T *y, const int incy)
Definition Vmath.hpp:825
void Vsub(int n, const T *x, const int incx, const T *y, const int incy, T *z, const int incz)
Subtract vector z = x-y.
Definition Vmath.hpp:220
STL namespace.
scalarT< T > max(scalarT< T > lhs, scalarT< T > rhs)
Definition scalar.hpp:305
scalarT< T > min(scalarT< T > lhs, scalarT< T > rhs)
Definition scalar.hpp:300
scalarT< T > sqrt(scalarT< T > in)
Definition scalar.hpp:290