Nektar++
Loading...
Searching...
No Matches
Expansion2D.cpp
Go to the documentation of this file.
1///////////////////////////////////////////////////////////////////////////////
2//
3// File: Expansion2D.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: File for Expansion2D routines
32//
33///////////////////////////////////////////////////////////////////////////////
34
42#include <LocalRegions/SegExp.h>
45
46using namespace std;
47
49{
51 : StdExpansion(), Expansion(pGeom), StdExpansion2D()
52{
53}
54
56{
57 DNekScalMatSharedPtr returnval;
59
61 "Geometric information is not set up");
62
63 switch (mkey.GetMatrixType())
64 {
66 {
67 if ((m_metricinfo->GetGtype() == SpatialDomains::eDeformed) ||
69 {
70 NekDouble one = 1.0;
71 DNekMatSharedPtr mat = GenMatrix(mkey);
72
73 returnval =
75 }
76 else
77 {
78 NekDouble jac = (m_metricinfo->GetJac(ptsKeys))[0];
80
81 returnval =
83 }
84 }
85 break;
87 {
88 MatrixKey masskey(mkey, StdRegions::eMass);
89 DNekScalMat &MassMat = *GetLocMatrix(masskey);
90
91 // Generate a local copy of traceMat
94
96 "Need to specify eFactorGJP to construct "
97 "a HelmholtzGJP matrix");
98
100
101 factor /= MassMat.Scale();
102
103 int ntot = MassMat.GetRows() * MassMat.GetColumns();
104
105 Vmath::Svtvp(ntot, factor, &NDTraceMat->GetPtr()[0], 1,
106 MassMat.GetRawPtr(), 1, &NDTraceMat->GetPtr()[0], 1);
107
109 MassMat.Scale(), NDTraceMat);
110 }
111 break;
113 {
114 if (m_metricinfo->GetGtype() == SpatialDomains::eDeformed)
115 {
116 NekDouble one = 1.0;
118 DetShapeType(), *this);
119 DNekMatSharedPtr mat = GenMatrix(masskey);
120 mat->Invert();
121
122 returnval =
124 }
125 else
126 {
127 NekDouble fac = 1.0 / (m_metricinfo->GetJac(ptsKeys))[0];
128 DNekMatSharedPtr mat = GetStdMatrix(mkey);
129
130 returnval =
132 }
133 }
134 break;
138 {
139 if (m_metricinfo->GetGtype() == SpatialDomains::eDeformed ||
147 {
148 NekDouble one = 1.0;
149 DNekMatSharedPtr mat = GenMatrix(mkey);
150
151 returnval =
153 }
154 else
155 {
156 NekDouble jac = (m_metricinfo->GetJac(ptsKeys))[0];
158 m_metricinfo->GetDerivFactors(ptsKeys);
159 int dir = 0;
161 {
162 dir = 0;
163 }
165 {
166 dir = 1;
167 }
169 {
170 dir = 2;
171 }
172
174 mkey.GetShapeType(), *this);
176 mkey.GetShapeType(), *this);
177
178 DNekMat &deriv0 = *GetStdMatrix(deriv0key);
179 DNekMat &deriv1 = *GetStdMatrix(deriv1key);
180
181 int rows = deriv0.GetRows();
182 int cols = deriv1.GetColumns();
183
184 DNekMatSharedPtr WeakDeriv =
186 (*WeakDeriv) =
187 df[2 * dir][0] * deriv0 + df[2 * dir + 1][0] * deriv1;
188
190 jac, WeakDeriv);
191 }
192 }
193 break;
195 {
196 if (m_metricinfo->GetGtype() == SpatialDomains::eDeformed ||
197 mkey.GetNVarCoeff())
198 {
199 NekDouble one = 1.0;
200 DNekMatSharedPtr mat = GenMatrix(mkey);
201
202 returnval =
204 }
205 else
206 {
207 int shapedim = 2;
208
209 // dfdirxi = tan_{xi_x} * d \xi/dx
210 // + tan_{xi_y} * d \xi/dy
211 // + tan_{xi_z} * d \xi/dz
212 // dfdireta = tan_{eta_x} * d \eta/dx
213 // + tan_{xi_y} * d \xi/dy
214 // + tan_{xi_z} * d \xi/dz
215 NekDouble jac = (m_metricinfo->GetJac(ptsKeys))[0];
217 m_metricinfo->GetDerivFactors(ptsKeys);
218
219 Array<OneD, NekDouble> direction =
221
222 // d / dx = df[0]*deriv0 + df[1]*deriv1
223 // d / dy = df[2]*deriv0 + df[3]*deriv1
224 // d / dz = df[4]*deriv0 + df[5]*deriv1
225
226 // dfdir[dir] = e \cdot (d/dx, d/dy, d/dz)
227 // = (e^0 * df[0] + e^1 * df[2]
228 // + e^2 * df[4]) * deriv0
229 // + (e^0 * df[1] + e^1 * df[3]
230 // + e^2 * df[5]) * deriv1
231 // dfdir[dir] = e^0 * df[2 * 0 + dir]
232 // + e^1 * df[2 * 1 + dir]
233 // + e^2 * df [ 2 * 2 + dir]
234 Array<OneD, Array<OneD, NekDouble>> dfdir(shapedim);
235 Expansion::ComputeGmatcdotMF(df, direction, dfdir);
236
239
240 dfdirxi[StdRegions::eVarCoeffWeakDeriv] = dfdir[0];
241 dfdireta[StdRegions::eVarCoeffWeakDeriv] = dfdir[1];
242
244 mkey.GetShapeType(), *this,
247 mkey.GetShapeType(), *this,
249
250 DNekMat &derivxi = *GetStdMatrix(derivxikey);
251 DNekMat &deriveta = *GetStdMatrix(derivetakey);
252
253 int rows = derivxi.GetRows();
254 int cols = deriveta.GetColumns();
255
256 DNekMatSharedPtr WeakDirDeriv =
258
259 (*WeakDirDeriv) = derivxi + deriveta;
260
261 // Add (\nabla \cdot e^k ) Mass
263 DiveMass[StdRegions::eVarCoeffMass] =
265 StdRegions::StdMatrixKey stdmasskey(
266 StdRegions::eMass, mkey.GetShapeType(), *this,
268
269 DNekMatSharedPtr DiveMassmat = GetStdMatrix(stdmasskey);
270
271 (*WeakDirDeriv) = (*WeakDirDeriv) + (*DiveMassmat);
272
274 jac, WeakDirDeriv);
275 }
276 break;
277 }
279 {
280 if (m_metricinfo->GetGtype() == SpatialDomains::eDeformed ||
292 {
293 NekDouble one = 1.0;
294 DNekMatSharedPtr mat = GenMatrix(mkey);
295
296 returnval =
298 }
299 else
300 {
302 mkey.GetShapeType(), *this);
304 mkey.GetShapeType(), *this);
306 mkey.GetShapeType(), *this);
307
308 DNekMat &lap00 = *GetStdMatrix(lap00key);
309 DNekMat &lap01 = *GetStdMatrix(lap01key);
310 DNekMat &lap11 = *GetStdMatrix(lap11key);
311
312 NekDouble jac = (m_metricinfo->GetJac(ptsKeys))[0];
314 m_metricinfo->GetGmat(ptsKeys);
315
316 int rows = lap00.GetRows();
317 int cols = lap00.GetColumns();
318
319 DNekMatSharedPtr lap =
321
322 (*lap) = gmat[0][0] * lap00 +
323 gmat[1][0] * (lap01 + Transpose(lap01)) +
324 gmat[3][0] * lap11;
325
326 returnval =
328 }
329 }
330 break;
332 {
333 DNekMatSharedPtr mat = GenMatrix(mkey);
334
336 }
337 break;
339 {
341
342 MatrixKey masskey(mkey, StdRegions::eMass);
343 DNekScalMat &MassMat = *GetLocMatrix(masskey);
344
345 MatrixKey lapkey(mkey, StdRegions::eLaplacian);
346 DNekScalMat &LapMat = *GetLocMatrix(lapkey);
347
348 int rows = LapMat.GetRows();
349 int cols = LapMat.GetColumns();
350
351 DNekMatSharedPtr helm =
353
354 NekDouble one = 1.0;
355 (*helm) = LapMat + factor * MassMat;
356
357 returnval =
359 }
360 break;
362 {
363 MatrixKey helmkey(mkey, StdRegions::eHelmholtz);
364 DNekScalMat &HelmMat = *GetLocMatrix(helmkey);
365
366 // Generate a local copy of traceMat
369
371 "Need to specify eFactorGJP to construct "
372 "a HelmholtzGJP matrix");
373
375
376 factor /= HelmMat.Scale();
377
378 int ntot = HelmMat.GetRows() * HelmMat.GetColumns();
379
380 Vmath::Svtvp(ntot, factor, &NDTraceMat->GetPtr()[0], 1,
381 HelmMat.GetRawPtr(), 1, &NDTraceMat->GetPtr()[0], 1);
382
384 HelmMat.Scale(), NDTraceMat);
385 }
386 break;
388 {
390
391 // Construct mass matrix
392 // Check for mass-specific varcoeffs to avoid unncessary
393 // re-computation of the elemental matrix every time step
396 {
397 massVarcoeffs[StdRegions::eVarCoeffMass] =
399 }
400 MatrixKey masskey(StdRegions::eMass, mkey.GetShapeType(), *this,
401 mkey.GetConstFactors(), massVarcoeffs);
402 DNekScalMat &MassMat = *GetLocMatrix(masskey);
403
404 // Construct advection matrix
405 // Check for varcoeffs not required;
406 // assume advection velocity is always time-dependent
408 DNekScalMat &AdvMat = *GetLocMatrix(advkey);
409
410 int rows = MassMat.GetRows();
411 int cols = MassMat.GetColumns();
412
413 DNekMatSharedPtr adr =
415
416 NekDouble one = 1.0;
417 (*adr) = -lambda * MassMat + AdvMat;
418
420
421 // Clear memory for time-dependent matrices
422 DropLocMatrix(advkey);
423 if (!massVarcoeffs.empty())
424 {
425 DropLocMatrix(masskey);
426 }
427 }
428 break;
430 {
432
433 // Construct mass matrix
434 // Check for mass-specific varcoeffs to avoid unncessary
435 // re-computation of the elemental matrix every time step
438 {
439 massVarcoeffs[StdRegions::eVarCoeffMass] =
441 }
442 MatrixKey masskey(StdRegions::eMass, mkey.GetShapeType(), *this,
443 mkey.GetConstFactors(), massVarcoeffs);
444 DNekScalMat &MassMat = *GetLocMatrix(masskey);
445
446 // Construct laplacian matrix (Check for varcoeffs)
447 // Take all varcoeffs if one or more are detected
448 // TODO We might want to have a map
449 // from MatrixType to Vector of Varcoeffs and vice-versa
461 {
462 lapVarcoeffs = mkey.GetVarCoeffs();
463 }
464 MatrixKey lapkey(StdRegions::eLaplacian, mkey.GetShapeType(), *this,
465 mkey.GetConstFactors(), lapVarcoeffs);
466 DNekScalMat &LapMat = *GetLocMatrix(lapkey);
467
468 // Construct advection matrix
469 // Check for varcoeffs not required;
470 // assume advection velocity is always time-dependent
472 DNekScalMat &AdvMat = *GetLocMatrix(advkey);
473
474 int rows = LapMat.GetRows();
475 int cols = LapMat.GetColumns();
476
477 DNekMatSharedPtr adr =
479
480 NekDouble one = 1.0;
481 (*adr) = LapMat - lambda * MassMat + AdvMat;
482
484
485 // Clear memory for time-dependent matrices
486 DropLocMatrix(advkey);
487 if (!massVarcoeffs.empty())
488 {
489 DropLocMatrix(masskey);
490 }
491 if (!lapVarcoeffs.empty())
492 {
493 DropLocMatrix(lapkey);
494 }
495 }
496 break;
498 {
499 // Copied mostly from ADR solve to have fine-grain control
500 // over updating only advection matrix, relevant for performance!
502
503 // Construct mass matrix (Check for varcoeffs)
506 {
507 massVarcoeffs[StdRegions::eVarCoeffMass] =
509 }
510 MatrixKey masskey(StdRegions::eMass, mkey.GetShapeType(), *this,
511 mkey.GetConstFactors(), massVarcoeffs);
512 DNekScalMat &MassMat = *GetLocMatrix(masskey);
513
514 // Construct laplacian matrix (Check for varcoeffs)
526 {
527 lapVarcoeffs = mkey.GetVarCoeffs();
528 }
529 MatrixKey lapkey(StdRegions::eLaplacian, mkey.GetShapeType(), *this,
530 mkey.GetConstFactors(), lapVarcoeffs);
531 DNekScalMat &LapMat = *GetLocMatrix(lapkey);
532
533 // Construct advection matrix
534 // (assume advection velocity defined and non-zero)
535 // Could check L2(AdvectionVelocity) or HasVarCoeff
537 DNekScalMat &AdvMat = *GetLocMatrix(advkey);
538
539 // Generate a local copy of traceMat
541 *this, mkey.GetConstFactors());
542 DNekScalMat &NDTraceMat = *GetLocMatrix(gjpkey);
543
546 "Need to specify eFactorGJP to construct "
547 "a LinearAdvectionDiffusionReactionGJP matrix");
548
549 int rows = LapMat.GetRows();
550 int cols = LapMat.GetColumns();
551
552 DNekMatSharedPtr adr =
554
555 NekDouble one = 1.0;
556 (*adr) =
557 LapMat - lambda * MassMat + AdvMat + gjpfactor * NDTraceMat;
558
560
561 // Clear memory
562 DropLocMatrix(advkey);
563 DropLocMatrix(masskey);
564 DropLocMatrix(lapkey);
565 }
566 break;
568 {
569 NekDouble one = 1.0;
571
573 }
574 break;
576 {
577 if (m_metricinfo->GetGtype() == SpatialDomains::eDeformed)
578 {
579 NekDouble one = 1.0;
580 DNekMatSharedPtr mat = GenMatrix(mkey);
581
582 returnval =
584 }
585 else
586 {
587 NekDouble jac = (m_metricinfo->GetJac(ptsKeys))[0];
588 DNekMatSharedPtr mat = GetStdMatrix(mkey);
589
590 returnval =
592 }
593 }
594 break;
598 {
599 if (m_metricinfo->GetGtype() == SpatialDomains::eDeformed)
600 {
601 NekDouble one = 1.0;
602 DNekMatSharedPtr mat = GenMatrix(mkey);
603
604 returnval =
606 }
607 else
608 {
609 NekDouble jac = (m_metricinfo->GetJac(ptsKeys))[0];
610
612 m_metricinfo->GetDerivFactors(ptsKeys);
613 int dir = 0;
615 {
616 dir = 0;
617 }
619 {
620 dir = 1;
621 }
623 {
624 dir = 2;
625 }
626
628 mkey.GetShapeType(), *this);
630 mkey.GetShapeType(), *this);
631
632 DNekMat &stdiprod0 = *GetStdMatrix(iProdDeriv0Key);
633 DNekMat &stdiprod1 = *GetStdMatrix(iProdDeriv0Key);
634
635 int rows = stdiprod0.GetRows();
636 int cols = stdiprod1.GetColumns();
637
638 DNekMatSharedPtr mat =
640 (*mat) =
641 df[2 * dir][0] * stdiprod0 + df[2 * dir + 1][0] * stdiprod1;
642
643 returnval =
645 }
646 }
647 break;
648
650 {
651 NekDouble one = 1.0;
652
654 *this, mkey.GetConstFactors(), mkey.GetVarCoeffs());
655
656 DNekMatSharedPtr mat = GenMatrix(hkey);
657
658 mat->Invert();
659
661 }
662 break;
664 {
666 "Matrix only setup for quad elements currently");
667 DNekMatSharedPtr m_Ix;
668 Array<OneD, NekDouble> coords(1, 0.0);
670 int edge = static_cast<int>(factors[StdRegions::eFactorGaussEdge]);
671
672 coords[0] = (edge == 0 || edge == 3) ? -1.0 : 1.0;
673
674 m_Ix = m_base[(edge + 1) % 2]->GetI(coords);
675
676 returnval =
678 }
679 break;
681 {
682 NekDouble one = 1.0;
684 *this, mkey.GetConstFactors(),
685 mkey.GetVarCoeffs());
686 DNekScalBlkMatSharedPtr helmStatCond =
687 GetLocStaticCondMatrix(helmkey);
688 DNekScalMatSharedPtr A = helmStatCond->GetBlock(0, 0);
690
692 }
693 break;
694 default:
695 {
696 NekDouble one = 1.0;
697 DNekMatSharedPtr mat = GenMatrix(mkey);
698
700 }
701 break;
702 }
703
704 return returnval;
705}
706
708 const int edge, const ExpansionSharedPtr &EdgeExp,
711{
712 ASSERTL1(GetCoordim() == 2, "Routine only set up for two-dimensions");
713
715 GetTraceNormal(edge);
716
717 if (m_requireNeg.size() == 0)
718 {
719 int nedges = GetNtraces();
720 m_requireNeg.resize(nedges);
721
722 for (int i = 0; i < nedges; ++i)
723 {
724 m_requireNeg[i] = false;
725
726 ExpansionSharedPtr edgeExp = m_traceExp[i].lock();
727
728 if (edgeExp->GetRightAdjacentElementExp())
729 {
730 if (edgeExp->GetRightAdjacentElementExp()
731 ->GetGeom()
732 ->GetGlobalID() == GetGeom()->GetGlobalID())
733 {
734 m_requireNeg[i] = true;
735 }
736 }
737 }
738 }
739
740 // We allow the case of mixed polynomial order by supporting only
741 // those modes on the edge common to both adjoining elements. This
742 // is enforced here by taking the minimum size and padding with
743 // zeros.
744 int nquad_e = min(EdgeExp->GetNumPoints(0), int(normals[0].size()));
745
746 int nEdgePts = EdgeExp->GetTotPoints();
747 Array<OneD, NekDouble> edgePhys(nEdgePts);
748 Vmath::Vmul(nquad_e, normals[0], 1, Fx, 1, edgePhys, 1);
749 Vmath::Vvtvp(nquad_e, normals[1], 1, Fy, 1, edgePhys, 1, edgePhys, 1);
750
751 Expansion1DSharedPtr locExp = EdgeExp->as<Expansion1D>();
752
753 if (m_requireNeg[edge])
754 {
755 if (locExp->GetRightAdjacentElementExp()->GetGeom()->GetGlobalID() ==
757 {
758 Vmath::Neg(nquad_e, edgePhys, 1);
759 }
760 }
761
762 AddEdgeNormBoundaryInt(edge, EdgeExp, edgePhys, outarray);
763}
764
766 const int edge, const ExpansionSharedPtr &EdgeExp,
768{
769 int i;
770
771 if (m_requireNeg.size() == 0)
772 {
773 int nedges = GetNtraces();
774 m_requireNeg.resize(nedges);
775
776 for (i = 0; i < nedges; ++i)
777 {
778 m_requireNeg[i] = false;
779
780 ExpansionSharedPtr edgeExp = m_traceExp[i].lock();
781
782 if (edgeExp->GetRightAdjacentElementExp())
783 {
784 if (edgeExp->GetRightAdjacentElementExp()
785 ->GetGeom()
786 ->GetGlobalID() == GetGeom()->GetGlobalID())
787 {
788 m_requireNeg[i] = true;
789 }
790 }
791 }
792 }
793
795 GetBasisNumModes(1), 0, edge, GetTraceOrient(edge));
796
798
799 // Order of the element
800 int order_e = map->size();
801 // Order of the trace
802 int n_coeffs = EdgeExp->GetNcoeffs();
803
804 Array<OneD, NekDouble> edgeCoeffs(n_coeffs);
805 if (n_coeffs != order_e) // Going to orthogonal space
806 {
807 EdgeExp->FwdTrans(Fn, edgeCoeffs);
808 Expansion1DSharedPtr locExp = EdgeExp->as<Expansion1D>();
809
810 if (m_requireNeg[edge])
811 {
812 Vmath::Neg(n_coeffs, edgeCoeffs, 1);
813 }
814
815 Array<OneD, NekDouble> coeff(n_coeffs, 0.0);
817 ((LibUtilities::BasisType)1); // 1-->Ortho_A
818 LibUtilities::BasisKey bkey_ortho(btype,
819 EdgeExp->GetBasis(0)->GetNumModes(),
820 EdgeExp->GetBasis(0)->GetPointsKey());
821 LibUtilities::BasisKey bkey(EdgeExp->GetBasis(0)->GetBasisType(),
822 EdgeExp->GetBasis(0)->GetNumModes(),
823 EdgeExp->GetBasis(0)->GetPointsKey());
824 LibUtilities::InterpCoeff1D(bkey, edgeCoeffs, bkey_ortho, coeff);
825
826 // Cutting high frequencies
827 for (i = order_e; i < n_coeffs; i++)
828 {
829 coeff[i] = 0.0;
830 }
831
832 LibUtilities::InterpCoeff1D(bkey_ortho, coeff, bkey, edgeCoeffs);
833
835 LibUtilities::eSegment, *EdgeExp);
836 EdgeExp->MassMatrixOp(edgeCoeffs, edgeCoeffs, masskey);
837 }
838 else
839 {
840 EdgeExp->IProductWRTBase(Fn, edgeCoeffs);
841
842 Expansion1DSharedPtr locExp = EdgeExp->as<Expansion1D>();
843
844 if (m_requireNeg[edge])
845 {
846 Vmath::Neg(n_coeffs, edgeCoeffs, 1);
847 }
848 }
849
850 // Implementation for all the basis except Gauss points
851 if (EdgeExp->GetBasis(0)->GetBasisType() != LibUtilities::eGauss_Lagrange)
852 {
853 // add data to outarray if forward edge normal is outwards
854 for (i = 0; i < order_e; ++i)
855 {
856 outarray[(*map)[i].index] += (*map)[i].sign * edgeCoeffs[i];
857 }
858 }
859 else
860 {
861 int nCoeffs0, nCoeffs1;
862 int j;
863
865 factors[StdRegions::eFactorGaussEdge] = edge;
867 *this, factors);
868
869 DNekMatSharedPtr mat_gauss = m_stdMatrixManager[key];
870
871 switch (edge)
872 {
873 case 0:
874 {
875 nCoeffs1 = m_base[1]->GetNumModes();
876
877 for (i = 0; i < order_e; ++i)
878 {
879 for (j = 0; j < nCoeffs1; j++)
880 {
881 outarray[(*map)[i].index + j * order_e] +=
882 mat_gauss->GetPtr()[j] * (*map)[i].sign *
883 edgeCoeffs[i];
884 }
885 }
886 break;
887 }
888 case 1:
889 {
890 nCoeffs0 = m_base[0]->GetNumModes();
891
892 for (i = 0; i < order_e; ++i)
893 {
894 for (j = 0; j < nCoeffs0; j++)
895 {
896 outarray[(*map)[i].index - j] +=
897 mat_gauss->GetPtr()[order_e - 1 - j] *
898 (*map)[i].sign * edgeCoeffs[i];
899 }
900 }
901 break;
902 }
903 case 2:
904 {
905 nCoeffs1 = m_base[1]->GetNumModes();
906
907 for (i = 0; i < order_e; ++i)
908 {
909 for (j = 0; j < nCoeffs1; j++)
910 {
911 outarray[(*map)[i].index - j * order_e] +=
912 mat_gauss->GetPtr()[order_e - 1 - j] *
913 (*map)[i].sign * edgeCoeffs[i];
914 }
915 }
916 break;
917 }
918 case 3:
919 {
920 nCoeffs0 = m_base[0]->GetNumModes();
921
922 for (i = 0; i < order_e; ++i)
923 {
924 for (j = 0; j < nCoeffs0; j++)
925 {
926 outarray[(*map)[i].index + j] +=
927 mat_gauss->GetPtr()[j] * (*map)[i].sign *
928 edgeCoeffs[i];
929 }
930 }
931 break;
932 }
933 default:
934 ASSERTL0(false, "edge value (< 3) is out of range");
935 break;
936 }
937 }
938}
939
942{
943 int i, cnt = 0;
944 int nedges = GetNtraces();
946
947 for (i = 0; i < nedges; ++i)
948 {
949 EdgeExp[i]->SetCoeffsToOrientation(
950 GetTraceOrient(i), e_tmp = inout + cnt, e_tmp = inout + cnt);
951 cnt += GetTraceNcoeffs(i);
952 }
953}
954
955/**
956 * Computes the C matrix entries due to the presence of the identity
957 * matrix in Eqn. 32.
958 */
962 Array<OneD, NekDouble> &outarray,
963 const StdRegions::VarCoeffMap &varcoeffs)
964{
965 int i, e, cnt;
966 int order_e, nquad_e;
967 int nedges = GetNtraces();
968
969 cnt = 0;
970 for (e = 0; e < nedges; ++e)
971 {
972 order_e = EdgeExp[e]->GetNcoeffs();
973 nquad_e = EdgeExp[e]->GetNumPoints(0);
974
977 Array<OneD, NekDouble> edgeCoeffs(order_e);
978 Array<OneD, NekDouble> edgePhys(nquad_e);
979
980 for (i = 0; i < order_e; ++i)
981 {
982 edgeCoeffs[i] = inarray[i + cnt];
983 }
984 cnt += order_e;
985
986 EdgeExp[e]->BwdTrans(edgeCoeffs, edgePhys);
987
988 // Multiply by variable coefficient
989 /// @TODO: Document this
990 // StdRegions::VarCoeffType VarCoeff[3] = {StdRegions::eVarCoeffD00,
991 // StdRegions::eVarCoeffD11,
992 // StdRegions::eVarCoeffD22};
993 // StdRegions::VarCoeffMap::const_iterator x;
994 // Array<OneD, NekDouble> varcoeff_work(nquad_e);
995
996 // if ((x = varcoeffs.find(VarCoeff[dir])) != varcoeffs.end())
997 // {
998 // GetPhysEdgeVarCoeffsFromElement(e,EdgeExp[e],x->second,varcoeff_work);
999 // Vmath::Vmul(nquad_e,varcoeff_work,1,EdgeExp[e]->GetPhys(),1,EdgeExp[e]->UpdatePhys(),1);
1000 // }
1001
1002 if (varcoeffs.find(StdRegions::eVarCoeffMF1x) != varcoeffs.end())
1003 {
1004 // MMF case
1005 Array<OneD, NekDouble> ncdotMF_e =
1006 GetnEdgecdotMF(dir, e, EdgeExp[e], normals, varcoeffs);
1007
1008 Vmath::Vmul(nquad_e, ncdotMF_e, 1, edgePhys, 1, edgePhys, 1);
1009 }
1010 else
1011 {
1012 Vmath::Vmul(nquad_e, normals[dir], 1, edgePhys, 1, edgePhys, 1);
1013 }
1014
1015 AddEdgeBoundaryInt(e, EdgeExp[e], edgePhys, outarray, varcoeffs);
1016 }
1017}
1018
1020 const int dir, Array<OneD, ExpansionSharedPtr> &EdgeExp,
1021 Array<OneD, Array<OneD, NekDouble>> &edgeCoeffs,
1022 Array<OneD, NekDouble> &outarray)
1023{
1024 int e;
1025 int nquad_e;
1026 int nedges = GetNtraces();
1027
1028 for (e = 0; e < nedges; ++e)
1029 {
1030 nquad_e = EdgeExp[e]->GetNumPoints(0);
1031
1032 Array<OneD, NekDouble> edgePhys(nquad_e);
1034 GetTraceNormal(e);
1035
1036 EdgeExp[e]->BwdTrans(edgeCoeffs[e], edgePhys);
1037
1038 Vmath::Vmul(nquad_e, normals[dir], 1, edgePhys, 1, edgePhys, 1);
1039
1040 AddEdgeBoundaryInt(e, EdgeExp[e], edgePhys, outarray);
1041 }
1042}
1043
1044/**
1045 * For a given edge add the \tilde{F}_1j contributions
1046 */
1048 ExpansionSharedPtr &EdgeExp,
1049 Array<OneD, NekDouble> &edgePhys,
1050 Array<OneD, NekDouble> &outarray,
1051 const StdRegions::VarCoeffMap &varcoeffs)
1052{
1053 int i;
1054 int order_e = EdgeExp->GetNcoeffs();
1055 int nquad_e = EdgeExp->GetNumPoints(0);
1058 Array<OneD, NekDouble> coeff(order_e);
1059
1060 GetTraceToElementMap(edge, map, sign, v_GetTraceOrient(edge));
1061
1065 StdRegions::VarCoeffMap::const_iterator x;
1066
1067 /// @TODO Variable coeffs
1068 if ((x = varcoeffs.find(VarCoeff[0])) != varcoeffs.end())
1069 {
1070 Array<OneD, NekDouble> work(nquad_e);
1071 GetPhysEdgeVarCoeffsFromElement(edge, EdgeExp, x->second.GetValue(),
1072 work);
1073 Vmath::Vmul(nquad_e, work, 1, edgePhys, 1, edgePhys, 1);
1074 }
1075
1076 EdgeExp->IProductWRTBase(edgePhys, coeff);
1077
1078 // add data to out array
1079 for (i = 0; i < order_e; ++i)
1080 {
1081 outarray[map[i]] += sign[i] * coeff[i];
1082 }
1083}
1084
1085// This method assumes that data in EdgeExp is orientated according to
1086// elemental counter clockwise format AddHDGHelmholtzTraceTerms with
1087// directions
1089 const NekDouble tau, const Array<OneD, const NekDouble> &inarray,
1091 const StdRegions::VarCoeffMap &dirForcing, Array<OneD, NekDouble> &outarray)
1092{
1093 ASSERTL0(&inarray[0] != &outarray[0],
1094 "Input and output arrays use the same memory");
1095
1096 int e, cnt, order_e, nedges = GetNtraces();
1098
1099 cnt = 0;
1100
1101 for (e = 0; e < nedges; ++e)
1102 {
1103 order_e = EdgeExp[e]->GetNcoeffs();
1104 Array<OneD, NekDouble> edgeCoeffs(order_e);
1105 Array<OneD, NekDouble> edgePhys(EdgeExp[e]->GetTotPoints());
1106
1107 Vmath::Vcopy(order_e, tmp = inarray + cnt, 1, edgeCoeffs, 1);
1108 EdgeExp[e]->BwdTrans(edgeCoeffs, edgePhys);
1109 AddHDGHelmholtzEdgeTerms(tau, e, EdgeExp, edgePhys, dirForcing,
1110 outarray);
1111
1112 cnt += order_e;
1113 }
1114}
1115
1116// evaluate additional terms in HDG edges. Not that this assumes that
1117// edges are unpacked into local cartesian order.
1119 const NekDouble tau, const int edge,
1121 const StdRegions::VarCoeffMap &varcoeffs, Array<OneD, NekDouble> &outarray)
1122{
1123 bool mmf = (varcoeffs.find(StdRegions::eVarCoeffMF1x) != varcoeffs.end());
1124 int i, j, n;
1125 int nquad_e = EdgeExp[edge]->GetNumPoints(0);
1126 int order_e = EdgeExp[edge]->GetNcoeffs();
1127 int coordim = mmf ? 2 : GetCoordim();
1128 int ncoeffs = GetNcoeffs();
1129
1130 Array<OneD, NekDouble> inval(nquad_e);
1131 Array<OneD, NekDouble> outcoeff(order_e);
1132 Array<OneD, NekDouble> tmpcoeff(ncoeffs);
1133
1135 GetTraceNormal(edge);
1136
1139
1141
1142 DNekVec Coeffs(ncoeffs, outarray, eWrapper);
1143 DNekVec Tmpcoeff(ncoeffs, tmpcoeff, eWrapper);
1144
1145 GetTraceToElementMap(edge, emap, sign, edgedir);
1146
1150
1154
1155 StdRegions::VarCoeffMap::const_iterator x;
1156 /// @TODO: What direction to use here??
1157 if ((x = varcoeffs.find(VarCoeff[0])) != varcoeffs.end())
1158 {
1159 Array<OneD, NekDouble> work(nquad_e);
1160 GetPhysEdgeVarCoeffsFromElement(edge, EdgeExp[edge],
1161 x->second.GetValue(), work);
1162 Vmath::Vmul(nquad_e, work, 1, edgePhys, 1, edgePhys, 1);
1163 }
1164
1165 //================================================================
1166 // Add F = \tau <phi_i,in_phys>
1167 // Fill edge and take inner product
1168 EdgeExp[edge]->IProductWRTBase(edgePhys, outcoeff);
1169 // add data to out array
1170 for (i = 0; i < order_e; ++i)
1171 {
1172 outarray[emap[i]] += sign[i] * tau * outcoeff[i];
1173 }
1174 //================================================================
1175
1176 //===============================================================
1177 // Add -\sum_i D_i^T M^{-1} G_i + E_i M^{-1} G_i =
1178 // \sum_i D_i M^{-1} G_i term
1179
1180 // Two independent direction
1181 DNekScalMatSharedPtr invMass;
1182 for (n = 0; n < coordim; ++n)
1183 {
1184 if (mmf)
1185 {
1187 Weight[StdRegions::eVarCoeffMass] = GetMFMag(n, varcoeffs);
1188
1189 MatrixKey invMasskey(StdRegions::eInvMass, DetShapeType(), *this,
1191
1192 invMass = GetLocMatrix(invMasskey);
1193
1194 Array<OneD, NekDouble> ncdotMF_e =
1195 GetnEdgecdotMF(n, edge, EdgeExp[edge], normals, varcoeffs);
1196
1197 Vmath::Vmul(nquad_e, ncdotMF_e, 1, edgePhys, 1, inval, 1);
1198 }
1199 else
1200 {
1201 Vmath::Vmul(nquad_e, normals[n], 1, edgePhys, 1, inval, 1);
1203 }
1204
1205 // Multiply by variable coefficient
1206 /// @TODO: Document this (probably not needed)
1207 // StdRegions::VarCoeffMap::const_iterator x;
1208 // if ((x = varcoeffs.find(VarCoeff[n])) !=
1209 // varcoeffs.end())
1210 // {
1211 // GetPhysEdgeVarCoeffsFromElement(edge,EdgeExp[edge],x->second,varcoeff_work);
1212 // Vmath::Vmul(nquad_e,varcoeff_work,1,EdgeExp[edge]->GetPhys(),1,EdgeExp[edge]->UpdatePhys(),1);
1213 // }
1214
1215 EdgeExp[edge]->IProductWRTBase(inval, outcoeff);
1216
1217 // M^{-1} G
1218 for (i = 0; i < ncoeffs; ++i)
1219 {
1220 tmpcoeff[i] = 0;
1221 for (j = 0; j < order_e; ++j)
1222 {
1223 tmpcoeff[i] += (*invMass)(i, emap[j]) * sign[j] * outcoeff[j];
1224 }
1225 }
1226
1227 if (mmf)
1228 {
1229 StdRegions::VarCoeffMap VarCoeffDirDeriv;
1230 VarCoeffDirDeriv[StdRegions::eVarCoeffMF] =
1231 GetMF(n, coordim, varcoeffs);
1232 VarCoeffDirDeriv[StdRegions::eVarCoeffMFDiv] =
1233 GetMFDiv(n, varcoeffs);
1234
1237 VarCoeffDirDeriv);
1238
1239 DNekScalMat &Dmat = *GetLocMatrix(Dmatkey);
1240
1241 Coeffs = Coeffs + Dmat * Tmpcoeff;
1242 }
1243 else
1244 {
1245 if (varcoeffs.find(VarCoeff[n]) != varcoeffs.end())
1246 {
1247 MatrixKey mkey(DerivType[n], DetShapeType(), *this,
1249
1250 DNekScalMat &Dmat = *GetLocMatrix(mkey);
1251 Coeffs = Coeffs + Dmat * Tmpcoeff;
1252 }
1253 else
1254 {
1255 DNekScalMat &Dmat = *GetLocMatrix(DerivType[n]);
1256 Coeffs = Coeffs + Dmat * Tmpcoeff;
1257 }
1258 }
1259 }
1260}
1261
1262/**
1263 * Extracts the variable coefficients along an edge
1264 */
1266 const int edge, ExpansionSharedPtr &EdgeExp,
1267 const Array<OneD, const NekDouble> &varcoeff,
1268 Array<OneD, NekDouble> &outarray)
1269{
1271 Array<OneD, NekDouble> edgetmp(EdgeExp->GetNcoeffs());
1272
1273 // FwdTrans varcoeffs
1274 FwdTrans(varcoeff, tmp);
1275
1276 // Map to edge
1280 GetTraceToElementMap(edge, emap, sign, edgedir);
1281
1282 for (unsigned int i = 0; i < EdgeExp->GetNcoeffs(); ++i)
1283 {
1284 edgetmp[i] = tmp[emap[i]];
1285 }
1286
1287 // BwdTrans
1288 EdgeExp->BwdTrans(edgetmp, outarray);
1289}
1290
1291/**
1292 * Computes matrices needed for the HDG formulation. References to
1293 * equations relate to the following paper:
1294 * R. M. Kirby, S. J. Sherwin, B. Cockburn, To CG or to HDG: A
1295 * Comparative Study, J. Sci. Comp P1-30
1296 * DOI 10.1007/s10915-011-9501-7
1297 */
1299{
1300 DNekMatSharedPtr returnval;
1301
1302 switch (mkey.GetMatrixType())
1303 {
1304 // (Z^e)^{-1} (Eqn. 33, P22)
1306 {
1308 "HybridDGHelmholtz matrix not set up "
1309 "for non boundary-interior expansions");
1310
1311 int i, j, k;
1312 NekDouble lambdaval =
1315 int ncoeffs = GetNcoeffs();
1316 int nedges = GetNtraces();
1317 int shapedim = 2;
1318 const StdRegions::VarCoeffMap &varcoeffs = mkey.GetVarCoeffs();
1319 bool mmf =
1320 (varcoeffs.find(StdRegions::eVarCoeffMF1x) != varcoeffs.end());
1321
1325 ExpansionSharedPtr EdgeExp;
1326
1327 int order_e, coordim = GetCoordim();
1332 DNekMat LocMat(ncoeffs, ncoeffs);
1333
1334 returnval =
1336 DNekMat &Mat = *returnval;
1337 Vmath::Zero(ncoeffs * ncoeffs, Mat.GetPtr(), 1);
1338
1342
1343 StdRegions::VarCoeffMap::const_iterator x;
1344
1345 for (i = 0; i < coordim; ++i)
1346 {
1347 if (mmf)
1348 {
1349 if (i < shapedim)
1350 {
1351 StdRegions::VarCoeffMap VarCoeffDirDeriv;
1352 VarCoeffDirDeriv[StdRegions::eVarCoeffMF] =
1353 GetMF(i, shapedim, varcoeffs);
1354 VarCoeffDirDeriv[StdRegions::eVarCoeffMFDiv] =
1355 GetMFDiv(i, varcoeffs);
1356
1358 DetShapeType(), *this,
1360 VarCoeffDirDeriv);
1361
1362 DNekScalMat &Dmat = *GetLocMatrix(Dmatkey);
1363
1366 GetMFMag(i, mkey.GetVarCoeffs());
1367
1368 MatrixKey invMasskey(
1371
1372 DNekScalMat &invMass = *GetLocMatrix(invMasskey);
1373
1374 Mat = Mat + Dmat * invMass * Transpose(Dmat);
1375 }
1376 }
1377 else if (mkey.HasVarCoeff(Coeffs[i]))
1378 {
1379 MatrixKey DmatkeyL(DerivType[i], DetShapeType(), *this,
1381 mkey.GetVarCoeffAsMap(Coeffs[i]));
1382
1383 MatrixKey DmatkeyR(DerivType[i], DetShapeType(), *this);
1384
1385 DNekScalMat &DmatL = *GetLocMatrix(DmatkeyL);
1386 DNekScalMat &DmatR = *GetLocMatrix(DmatkeyR);
1387 Mat = Mat + DmatL * invMass * Transpose(DmatR);
1388 }
1389 else
1390 {
1391 DNekScalMat &Dmat = *GetLocMatrix(DerivType[i]);
1392 Mat = Mat + Dmat * invMass * Transpose(Dmat);
1393 }
1394 }
1395
1396 // Add Mass Matrix Contribution for Helmholtz problem
1398 Mat = Mat + lambdaval * Mass;
1399
1400 // Add tau*E_l using elemental mass matrices on each edge
1401 for (i = 0; i < nedges; ++i)
1402 {
1403 EdgeExp = GetTraceExp(i);
1404 order_e = EdgeExp->GetNcoeffs();
1405
1406 int nq = EdgeExp->GetNumPoints(0);
1407 GetTraceToElementMap(i, emap, sign, edgedir);
1408
1409 // @TODO: Document
1410 StdRegions::VarCoeffMap edgeVarCoeffs;
1412 {
1415 i, EdgeExp, mkey.GetVarCoeff(StdRegions::eVarCoeffD00),
1416 mu);
1417 edgeVarCoeffs[StdRegions::eVarCoeffMass] = mu;
1418 }
1419 DNekScalMat &eMass = *EdgeExp->GetLocMatrix(
1421 edgeVarCoeffs);
1422 // DNekScalMat &eMass =
1423 // *EdgeExp->GetLocMatrix(StdRegions::eMass);
1424
1425 for (j = 0; j < order_e; ++j)
1426 {
1427 for (k = 0; k < order_e; ++k)
1428 {
1429 Mat(emap[j], emap[k]) =
1430 Mat(emap[j], emap[k]) +
1431 tau * sign[j] * sign[k] * eMass(j, k);
1432 }
1433 }
1434 }
1435 }
1436 break;
1437 // U^e (P22)
1439 {
1440 int i, j, k;
1441 int nbndry = NumDGBndryCoeffs();
1442 int ncoeffs = GetNcoeffs();
1443 int nedges = GetNtraces();
1445
1446 Array<OneD, NekDouble> lambda(nbndry);
1447 DNekVec Lambda(nbndry, lambda, eWrapper);
1448 Array<OneD, NekDouble> ulam(ncoeffs);
1449 DNekVec Ulam(ncoeffs, ulam, eWrapper);
1450 Array<OneD, NekDouble> f(ncoeffs);
1451 DNekVec F(ncoeffs, f, eWrapper);
1452
1453 Array<OneD, ExpansionSharedPtr> EdgeExp(nedges);
1454 // declare matrix space
1455 returnval =
1457 DNekMat &Umat = *returnval;
1458
1459 // Z^e matrix
1461 *this, mkey.GetConstFactors(),
1462 mkey.GetVarCoeffs());
1463 DNekScalMat &invHmat = *GetLocMatrix(newkey);
1464
1467
1468 for (i = 0; i < nedges; ++i)
1469 {
1470 EdgeExp[i] = GetTraceExp(i);
1471 }
1472
1473 // for each degree of freedom of the lambda space
1474 // calculate Umat entry
1475 // Generate Lambda to U_lambda matrix
1476 for (j = 0; j < nbndry; ++j)
1477 {
1478 // standard basis vectors e_j
1479 Vmath::Zero(nbndry, &lambda[0], 1);
1480 Vmath::Zero(ncoeffs, &f[0], 1);
1481 lambda[j] = 1.0;
1482
1483 SetTraceToGeomOrientation(EdgeExp, lambda);
1484
1485 // Compute F = [I D_1 M^{-1} D_2 M^{-1}] C e_j
1486 AddHDGHelmholtzTraceTerms(tau, lambda, EdgeExp,
1487 mkey.GetVarCoeffs(), f);
1488
1489 // Compute U^e_j
1490 Ulam = invHmat * F; // generate Ulam from lambda
1491
1492 // fill column of matrix
1493 for (k = 0; k < ncoeffs; ++k)
1494 {
1495 Umat(k, j) = Ulam[k];
1496 }
1497 }
1498 }
1499 break;
1500 // Q_0, Q_1, Q_2 matrices (P23)
1501 // Each are a product of a row of Eqn 32 with the C matrix.
1502 // Rather than explicitly computing all of Eqn 32, we note each
1503 // row is almost a multiple of U^e, so use that as our starting
1504 // point.
1508 {
1509 int i = 0;
1510 int j = 0;
1511 int k = 0;
1512 int dir = 0;
1513 int nbndry = NumDGBndryCoeffs();
1514 int ncoeffs = GetNcoeffs();
1515 int nedges = GetNtraces();
1516 int shapedim = 2;
1517
1518 Array<OneD, NekDouble> lambda(nbndry);
1519 DNekVec Lambda(nbndry, lambda, eWrapper);
1520 Array<OneD, ExpansionSharedPtr> EdgeExp(nedges);
1521
1522 Array<OneD, NekDouble> ulam(ncoeffs);
1523 DNekVec Ulam(ncoeffs, ulam, eWrapper);
1524 Array<OneD, NekDouble> f(ncoeffs);
1525 DNekVec F(ncoeffs, f, eWrapper);
1526
1527 // declare matrix space
1528 returnval =
1530 DNekMat &Qmat = *returnval;
1531
1532 // Lambda to U matrix
1534 *this, mkey.GetConstFactors(),
1535 mkey.GetVarCoeffs());
1536 DNekScalMat &lamToU = *GetLocMatrix(lamToUkey);
1537
1538 // Inverse mass matrix
1540
1541 for (i = 0; i < nedges; ++i)
1542 {
1543 EdgeExp[i] = GetTraceExp(i);
1544 }
1545
1546 // Weak Derivative matrix
1548 switch (mkey.GetMatrixType())
1549 {
1551 dir = 0;
1553 break;
1555 dir = 1;
1557 break;
1559 dir = 2;
1561 break;
1562 default:
1563 ASSERTL0(false, "Direction not known");
1564 break;
1565 }
1566
1567 const StdRegions::VarCoeffMap &varcoeffs = mkey.GetVarCoeffs();
1568 if (varcoeffs.find(StdRegions::eVarCoeffMF1x) != varcoeffs.end())
1569 {
1570 StdRegions::VarCoeffMap VarCoeffDirDeriv;
1571 VarCoeffDirDeriv[StdRegions::eVarCoeffMF] =
1572 GetMF(dir, shapedim, varcoeffs);
1573 VarCoeffDirDeriv[StdRegions::eVarCoeffMFDiv] =
1574 GetMFDiv(dir, varcoeffs);
1575
1576 MatrixKey Dmatkey(
1578 StdRegions::NullConstFactorMap, VarCoeffDirDeriv);
1579
1580 Dmat = GetLocMatrix(Dmatkey);
1581
1584 GetMFMag(dir, mkey.GetVarCoeffs());
1585
1588 Weight);
1589
1590 invMass = *GetLocMatrix(invMasskey);
1591 }
1592 else
1593 {
1597
1598 Dmat = GetLocMatrix(DerivType[dir]);
1599
1601 *this);
1602 invMass = *GetLocMatrix(invMasskey);
1603 }
1604
1605 // for each degree of freedom of the lambda space
1606 // calculate Qmat entry
1607 // Generate Lambda to Q_lambda matrix
1608 for (j = 0; j < nbndry; ++j)
1609 {
1610 Vmath::Zero(nbndry, &lambda[0], 1);
1611 lambda[j] = 1.0;
1612
1613 // for lambda[j] = 1 this is the solution to ulam
1614 for (k = 0; k < ncoeffs; ++k)
1615 {
1616 Ulam[k] = lamToU(k, j);
1617 }
1618
1619 // -D^T ulam
1620 Vmath::Neg(ncoeffs, &ulam[0], 1);
1621 F = Transpose(*Dmat) * Ulam;
1622
1623 SetTraceToGeomOrientation(EdgeExp, lambda);
1624
1625 // Add the C terms resulting from the I's on the
1626 // diagonals of Eqn 32
1627 AddNormTraceInt(dir, lambda, EdgeExp, f, mkey.GetVarCoeffs());
1628
1629 // finally multiply by inverse mass matrix
1630 Ulam = invMass * F;
1631
1632 // fill column of matrix (Qmat is in column major format)
1633 Vmath::Vcopy(ncoeffs, &ulam[0], 1,
1634 &(Qmat.GetPtr())[0] + j * ncoeffs, 1);
1635 }
1636 }
1637 break;
1638 // Matrix K (P23)
1640 {
1641 int i, j, e, cnt;
1642 int order_e, nquad_e;
1643 int nbndry = NumDGBndryCoeffs();
1644 int coordim = GetCoordim();
1645 int nedges = GetNtraces();
1647 StdRegions::VarCoeffMap::const_iterator x;
1648 const StdRegions::VarCoeffMap &varcoeffs = mkey.GetVarCoeffs();
1649 bool mmf =
1650 (varcoeffs.find(StdRegions::eVarCoeffMF1x) != varcoeffs.end());
1651
1652 Array<OneD, NekDouble> work, varcoeff_work;
1654 Array<OneD, ExpansionSharedPtr> EdgeExp(nedges);
1655 Array<OneD, NekDouble> lam(nbndry);
1656
1660
1661 // declare matrix space
1662 returnval =
1664 DNekMat &BndMat = *returnval;
1665
1666 DNekScalMatSharedPtr LamToQ[3];
1667
1668 // Matrix to map Lambda to U
1670 *this, mkey.GetConstFactors(),
1671 mkey.GetVarCoeffs());
1672 DNekScalMat &LamToU = *GetLocMatrix(LamToUkey);
1673
1674 // Matrix to map Lambda to Q0
1676 *this, mkey.GetConstFactors(),
1677 mkey.GetVarCoeffs());
1678 LamToQ[0] = GetLocMatrix(LamToQ0key);
1679
1680 // Matrix to map Lambda to Q1
1682 *this, mkey.GetConstFactors(),
1683 mkey.GetVarCoeffs());
1684 LamToQ[1] = GetLocMatrix(LamToQ1key);
1685
1686 // Matrix to map Lambda to Q2 for 3D coordinates
1687 if (coordim == 3)
1688 {
1689 MatrixKey LamToQ2key(
1691 mkey.GetConstFactors(), mkey.GetVarCoeffs());
1692 LamToQ[2] = GetLocMatrix(LamToQ2key);
1693 }
1694
1695 // Set up edge segment expansions from local geom info
1696 for (i = 0; i < nedges; ++i)
1697 {
1698 EdgeExp[i] = GetTraceExp(i);
1699 }
1700
1701 // Set up matrix derived from <mu, Q_lam.n - \tau (U_lam - Lam) >
1702 for (i = 0; i < nbndry; ++i)
1703 {
1704 cnt = 0;
1705
1706 Vmath::Zero(nbndry, lam, 1);
1707 lam[i] = 1.0;
1708 SetTraceToGeomOrientation(EdgeExp, lam);
1709
1710 for (e = 0; e < nedges; ++e)
1711 {
1712 order_e = EdgeExp[e]->GetNcoeffs();
1713 nquad_e = EdgeExp[e]->GetNumPoints(0);
1714
1715 normals = GetTraceNormal(e);
1716 edgedir = GetTraceOrient(e);
1717
1718 work = Array<OneD, NekDouble>(nquad_e);
1719 varcoeff_work = Array<OneD, NekDouble>(nquad_e);
1720
1721 GetTraceToElementMap(e, emap, sign, edgedir);
1722
1723 StdRegions::VarCoeffType VarCoeff[3] = {
1726
1727 // Q0 * n0 (BQ_0 terms)
1728 Array<OneD, NekDouble> edgeCoeffs(order_e);
1729 Array<OneD, NekDouble> edgePhys(nquad_e);
1730 for (j = 0; j < order_e; ++j)
1731 {
1732 edgeCoeffs[j] = sign[j] * (*LamToQ[0])(emap[j], i);
1733 }
1734
1735 EdgeExp[e]->BwdTrans(edgeCoeffs, edgePhys);
1736 // @TODO Var coeffs
1737 // Multiply by variable coefficient
1738 // if ((x =
1739 // varcoeffs.find(VarCoeff[0]))
1740 // != varcoeffs.end())
1741 // {
1742 // GetPhysEdgeVarCoeffsFromElement(e,EdgeExp[e],x->second,varcoeff_work);
1743 // Vmath::Vmul(nquad_e,varcoeff_work,1,EdgeExp[e]->GetPhys(),1,EdgeExp[e]->UpdatePhys(),1);
1744 // }
1745 if (mmf)
1746 {
1748 0, e, EdgeExp[e], normals, varcoeffs);
1749 Vmath::Vmul(nquad_e, ncdotMF, 1, edgePhys, 1, work, 1);
1750 }
1751 else
1752 {
1753 Vmath::Vmul(nquad_e, normals[0], 1, edgePhys, 1, work,
1754 1);
1755 }
1756
1757 // Q1 * n1 (BQ_1 terms)
1758 for (j = 0; j < order_e; ++j)
1759 {
1760 edgeCoeffs[j] = sign[j] * (*LamToQ[1])(emap[j], i);
1761 }
1762
1763 EdgeExp[e]->BwdTrans(edgeCoeffs, edgePhys);
1764
1765 // @TODO var coeffs
1766 // Multiply by variable coefficients
1767 // if ((x =
1768 // varcoeffs.find(VarCoeff[1]))
1769 // != varcoeffs.end())
1770 // {
1771 // GetPhysEdgeVarCoeffsFromElement(e,EdgeExp[e],x->second,varcoeff_work);
1772 // Vmath::Vmul(nquad_e,varcoeff_work,1,EdgeExp[e]->GetPhys(),1,EdgeExp[e]->UpdatePhys(),1);
1773 // }
1774
1775 if (mmf)
1776 {
1778 1, e, EdgeExp[e], normals, varcoeffs);
1779 Vmath::Vvtvp(nquad_e, ncdotMF, 1, edgePhys, 1, work, 1,
1780 work, 1);
1781 }
1782 else
1783 {
1784 Vmath::Vvtvp(nquad_e, normals[1], 1, edgePhys, 1, work,
1785 1, work, 1);
1786 }
1787
1788 // Q2 * n2 (BQ_2 terms)
1789 if (coordim == 3)
1790 {
1791 for (j = 0; j < order_e; ++j)
1792 {
1793 edgeCoeffs[j] = sign[j] * (*LamToQ[2])(emap[j], i);
1794 }
1795
1796 EdgeExp[e]->BwdTrans(edgeCoeffs, edgePhys);
1797 // @TODO var coeffs
1798 // Multiply by variable coefficients
1799 // if ((x =
1800 // varcoeffs.find(VarCoeff[2]))
1801 // != varcoeffs.end())
1802 // {
1803 // GetPhysEdgeVarCoeffsFromElement(e,EdgeExp[e],x->second,varcoeff_work);
1804 // Vmath::Vmul(nquad_e,varcoeff_work,1,EdgeExp[e]->GetPhys(),1,EdgeExp[e]->UpdatePhys(),1);
1805 // }
1806
1807 Vmath::Vvtvp(nquad_e, normals[2], 1, edgePhys, 1, work,
1808 1, work, 1);
1809 }
1810
1811 // - tau (ulam - lam)
1812 // Corresponds to the G and BU terms.
1813 for (j = 0; j < order_e; ++j)
1814 {
1815 edgeCoeffs[j] =
1816 sign[j] * LamToU(emap[j], i) - lam[cnt + j];
1817 }
1818
1819 EdgeExp[e]->BwdTrans(edgeCoeffs, edgePhys);
1820
1821 // Multiply by variable coefficients
1822 if ((x = varcoeffs.find(VarCoeff[0])) != varcoeffs.end())
1823 {
1825 e, EdgeExp[e], x->second.GetValue(), varcoeff_work);
1826 Vmath::Vmul(nquad_e, varcoeff_work, 1, edgePhys, 1,
1827 edgePhys, 1);
1828 }
1829
1830 Vmath::Svtvp(nquad_e, -tau, edgePhys, 1, work, 1, work, 1);
1831 /// TODO: Add variable coeffs
1832 EdgeExp[e]->IProductWRTBase(work, edgeCoeffs);
1833
1834 EdgeExp[e]->SetCoeffsToOrientation(edgedir, edgeCoeffs,
1835 edgeCoeffs);
1836
1837 for (j = 0; j < order_e; ++j)
1838 {
1839 BndMat(cnt + j, i) = edgeCoeffs[j];
1840 }
1841
1842 cnt += order_e;
1843 }
1844 }
1845 }
1846 break;
1847 // HDG postprocessing
1849 {
1851 mkey.GetConstFactors(), mkey.GetVarCoeffs());
1852 DNekScalMat &LapMat = *GetLocMatrix(lapkey);
1853
1855 LapMat.GetRows(), LapMat.GetColumns());
1856 DNekMatSharedPtr lmat = returnval;
1857
1858 (*lmat) = LapMat;
1859
1860 // replace first column with inner product wrt 1
1861 int nq = GetTotPoints();
1862 Array<OneD, NekDouble> tmp(nq);
1864 Vmath::Fill(nq, 1.0, tmp, 1);
1865 IProductWRTBase(tmp, outarray);
1866
1867 Vmath::Vcopy(m_ncoeffs, &outarray[0], 1, &(lmat->GetPtr())[0], 1);
1868 lmat->Invert();
1869 }
1870 break;
1872 {
1873 int ntraces = GetNtraces();
1874 int ncoords = GetCoordim();
1875 int nphys = GetTotPoints();
1877 Array<OneD, NekDouble> phys(nphys);
1878 returnval =
1880 DNekMat &Mat = *returnval;
1881 Vmath::Zero(m_ncoeffs * m_ncoeffs, Mat.GetPtr(), 1);
1882
1884
1885 for (int d = 0; d < ncoords; ++d)
1886 {
1887 Deriv[d] = Array<OneD, NekDouble>(nphys);
1888 }
1889
1890 Array<OneD, int> tracepts(ntraces);
1891 Array<OneD, ExpansionSharedPtr> traceExp(ntraces);
1892 int maxtpts = 0;
1893 for (int t = 0; t < ntraces; ++t)
1894 {
1895 traceExp[t] = GetTraceExp(t);
1896 tracepts[t] = traceExp[t]->GetTotPoints();
1897 maxtpts = (maxtpts > tracepts[t]) ? maxtpts : tracepts[t];
1898 }
1899
1900 Array<OneD, NekDouble> val(maxtpts), tmp, tmp1;
1901
1902 Array<OneD, Array<OneD, NekDouble>> dphidn(ntraces);
1903 for (int t = 0; t < ntraces; ++t)
1904 {
1905 dphidn[t] =
1906 Array<OneD, NekDouble>(m_ncoeffs * tracepts[t], 0.0);
1907 }
1908
1909 for (int i = 0; i < m_ncoeffs; ++i)
1910 {
1911 FillMode(i, phys);
1912 PhysDeriv(phys, Deriv[0], Deriv[1], Deriv[2]);
1913
1914 for (int t = 0; t < ntraces; ++t)
1915 {
1916 const NormalVector norm = GetTraceNormal(t);
1917
1920 traceExp[t]->GetBasis(0)->GetBasisKey();
1921 bool DoInterp = (fromkey != tokey);
1922
1923 Array<OneD, NekDouble> n(tracepts[t]);
1924 ;
1925 for (int d = 0; d < ncoords; ++d)
1926 {
1927 // if variable p may need to interpolate
1928 if (DoInterp)
1929 {
1930 LibUtilities::Interp1D(fromkey, norm[d], tokey, n);
1931 }
1932 else
1933 {
1934 n = norm[d];
1935 }
1936
1937 GetTracePhysVals(t, traceExp[t], Deriv[d], val,
1938 v_GetTraceOrient(t));
1939
1940 Vmath::Vvtvp(tracepts[t], n, 1, val, 1,
1941 tmp = dphidn[t] + i * tracepts[t], 1,
1942 tmp1 = dphidn[t] + i * tracepts[t], 1);
1943 }
1944 }
1945 }
1946
1947 for (int t = 0; t < ntraces; ++t)
1948 {
1949 int nt = tracepts[t];
1950 NekDouble h, p;
1951 TraceNormLen(t, h, p);
1952
1953 // scaling from GJP paper
1954 NekDouble scale =
1955 (p == 1) ? 0.02 * h * h : 0.8 * pow(p + 1, -4.0) * h * h;
1956
1957 for (int i = 0; i < m_ncoeffs; ++i)
1958 {
1959 for (int j = i; j < m_ncoeffs; ++j)
1960 {
1961 Vmath::Vmul(nt, dphidn[t] + i * nt, 1,
1962 dphidn[t] + j * nt, 1, val, 1);
1963 Mat(i, j) =
1964 Mat(i, j) + scale * traceExp[t]->Integral(val);
1965 }
1966 }
1967 }
1968
1969 // fill in symmetric components.
1970 for (int i = 0; i < m_ncoeffs; ++i)
1971 {
1972 for (int j = 0; j < i; ++j)
1973 {
1974 Mat(i, j) = Mat(j, i);
1975 }
1976 }
1977 }
1978 break;
1979 default:
1980 ASSERTL0(false,
1981 "This matrix type cannot be generated from this class");
1982 break;
1983 }
1984
1985 return returnval;
1986}
1987
1988// Evaluate Coefficients of weak deriviative in the direction dir
1989// given the input coefficicents incoeffs and the imposed
1990// boundary values in EdgeExp (which will have its phys space updated);
1992 const Array<OneD, const NekDouble> &incoeffs,
1994 Array<OneD, Array<OneD, NekDouble>> &edgeCoeffs,
1996{
2000
2001 int ncoeffs = GetNcoeffs();
2002
2004 DNekScalMat &Dmat = *GetLocMatrix(DerivType[dir]);
2005
2006 Array<OneD, NekDouble> coeffs = incoeffs;
2007 DNekVec Coeffs(ncoeffs, coeffs, eWrapper);
2008
2009 Coeffs = Transpose(Dmat) * Coeffs;
2010 Vmath::Neg(ncoeffs, coeffs, 1);
2011
2012 // Add the boundary integral including the relevant part of
2013 // the normal
2014 AddNormTraceInt(dir, EdgeExp, edgeCoeffs, coeffs);
2015
2016 DNekVec Out_d(ncoeffs, out_d, eWrapper);
2017
2018 Out_d = InvMass * Coeffs;
2019}
2020
2027
2029 const int edge, const Array<OneD, const NekDouble> &primCoeffs,
2030 DNekMatSharedPtr &inoutmat)
2031{
2033 "Not set up for non boundary-interior expansions");
2034 ASSERTL1(inoutmat->GetRows() == inoutmat->GetColumns(),
2035 "Assuming that input matrix was square");
2036 int i, j;
2037 int id1, id2;
2038 ExpansionSharedPtr edgeExp = m_traceExp[edge].lock();
2039 int order_e = edgeExp->GetNcoeffs();
2040
2043
2044 StdRegions::VarCoeffMap varcoeffs;
2045 varcoeffs[StdRegions::eVarCoeffMass] = primCoeffs;
2046
2049 varcoeffs);
2050 DNekScalMat &edgemat = *edgeExp->GetLocMatrix(mkey);
2051
2052 // Now need to identify a map which takes the local edge
2053 // mass matrix to the matrix stored in inoutmat;
2054 // This can currently be deduced from the size of the matrix
2055
2056 // - if inoutmat.m_rows() == v_NCoeffs() it is a full
2057 // matrix system
2058
2059 // - if inoutmat.m_rows() == v_NumBndCoeffs() it is a
2060 // boundary CG system
2061
2062 // - if inoutmat.m_rows() == v_NumDGBndCoeffs() it is a
2063 // trace DG system
2064 int rows = inoutmat->GetRows();
2065
2066 if (rows == GetNcoeffs())
2067 {
2068 GetTraceToElementMap(edge, map, sign, v_GetTraceOrient(edge));
2069 }
2070 else if (rows == NumBndryCoeffs())
2071 {
2072 int nbndry = NumBndryCoeffs();
2073 Array<OneD, unsigned int> bmap(nbndry);
2074
2075 GetTraceToElementMap(edge, map, sign, v_GetTraceOrient(edge));
2076
2077 GetBoundaryMap(bmap);
2078
2079 for (i = 0; i < order_e; ++i)
2080 {
2081 for (j = 0; j < nbndry; ++j)
2082 {
2083 if (map[i] == bmap[j])
2084 {
2085 map[i] = j;
2086 break;
2087 }
2088 }
2089 ASSERTL1(j != nbndry, "Did not find number in map");
2090 }
2091 }
2092 else if (rows == NumDGBndryCoeffs())
2093 {
2094 // possibly this should be a separate method
2095 int cnt = 0;
2096 map = Array<OneD, unsigned int>(order_e);
2097 sign = Array<OneD, int>(order_e, 1);
2098
2099 for (i = 0; i < edge; ++i)
2100 {
2101 cnt += GetTraceNcoeffs(i);
2102 }
2103
2104 for (i = 0; i < order_e; ++i)
2105 {
2106 map[i] = cnt++;
2107 }
2108 // check for mapping reversal
2110 {
2111 switch (edgeExp->GetBasis(0)->GetBasisType())
2112 {
2114 reverse(map.data(), map.data() + order_e);
2115 break;
2117 reverse(map.data(), map.data() + order_e);
2118 break;
2120 {
2121 swap(map[0], map[1]);
2122 for (i = 3; i < order_e; i += 2)
2123 {
2124 sign[i] = -1;
2125 }
2126 }
2127 break;
2128 default:
2129 ASSERTL0(false,
2130 "Edge boundary type not valid for this method");
2131 }
2132 }
2133 }
2134 else
2135 {
2136 ASSERTL0(false, "Could not identify matrix type from dimension");
2137 }
2138
2139 for (i = 0; i < order_e; ++i)
2140 {
2141 id1 = map[i];
2142 for (j = 0; j < order_e; ++j)
2143 {
2144 id2 = map[j];
2145 (*inoutmat)(id1, id2) += edgemat(i, j) * sign[i] * sign[j];
2146 }
2147 }
2148}
2149
2150/**
2151 * Given an edge and vector of element coefficients:
2152 * - maps those elemental coefficients corresponding to the edge into
2153 * an edge-vector.
2154 * - resets the element coefficients
2155 * - multiplies the edge vector by the edge mass matrix
2156 * - maps the edge coefficients back onto the elemental coefficients
2157 */
2159 const int edgeid, const Array<OneD, const NekDouble> &primCoeffs,
2160 const Array<OneD, NekDouble> &incoeffs, Array<OneD, NekDouble> &coeffs)
2161{
2163 "Not set up for non boundary-interior expansions");
2164 int i;
2165 ExpansionSharedPtr edgeExp = m_traceExp[edgeid].lock();
2166 int order_e = edgeExp->GetNcoeffs();
2167
2170
2171 StdRegions::VarCoeffMap varcoeffs;
2172 varcoeffs[StdRegions::eVarCoeffMass] = primCoeffs;
2173
2176 varcoeffs);
2177 DNekScalMat &edgemat = *edgeExp->GetLocMatrix(mkey);
2178
2179 NekVector<NekDouble> vEdgeCoeffs(order_e);
2180
2181 GetTraceToElementMap(edgeid, map, sign, v_GetTraceOrient(edgeid));
2182
2183 for (i = 0; i < order_e; ++i)
2184 {
2185 vEdgeCoeffs[i] = incoeffs[map[i]] * sign[i];
2186 }
2187
2188 vEdgeCoeffs = edgemat * vEdgeCoeffs;
2189
2190 for (i = 0; i < order_e; ++i)
2191 {
2192 coeffs[map[i]] += vEdgeCoeffs[i] * sign[i];
2193 }
2194}
2195
2197 const DNekScalMatSharedPtr &r_bnd)
2198{
2199 MatrixStorage storage = eFULL;
2200 DNekMatSharedPtr m_vertexmatrix;
2201
2202 int nVerts, vid1, vid2, vMap1, vMap2;
2203 NekDouble VertexValue;
2204
2205 nVerts = GetNverts();
2206
2207 m_vertexmatrix =
2208 MemoryManager<DNekMat>::AllocateSharedPtr(nVerts, nVerts, 0.0, storage);
2209 DNekMat &VertexMat = (*m_vertexmatrix);
2210
2211 for (vid1 = 0; vid1 < nVerts; ++vid1)
2212 {
2213 vMap1 = GetVertexMap(vid1);
2214
2215 for (vid2 = 0; vid2 < nVerts; ++vid2)
2216 {
2217 vMap2 = GetVertexMap(vid2);
2218 VertexValue = (*r_bnd)(vMap1, vMap2);
2219 VertexMat.SetValue(vid1, vid2, VertexValue);
2220 }
2221 }
2222
2223 return m_vertexmatrix;
2224}
2225
2231
2233{
2234 int n, j;
2235 int nEdgeCoeffs;
2236 int nBndCoeffs = NumBndryCoeffs();
2237
2238 Array<OneD, unsigned int> bmap(nBndCoeffs);
2239 GetBoundaryMap(bmap);
2240
2241 // Map from full system to statically condensed system (i.e reverse
2242 // GetBoundaryMap)
2243 map<int, int> invmap;
2244 for (j = 0; j < nBndCoeffs; ++j)
2245 {
2246 invmap[bmap[j]] = j;
2247 }
2248
2249 // Number of interior edge coefficients
2250 nEdgeCoeffs = GetTraceNcoeffs(eid) - 2;
2251
2252 const SpatialDomains::Geometry2D *geom = GetGeom2D();
2253
2254 Array<OneD, unsigned int> edgemaparray(nEdgeCoeffs);
2255 Array<OneD, unsigned int> maparray(nEdgeCoeffs);
2256 Array<OneD, int> signarray(nEdgeCoeffs, 1);
2257 StdRegions::Orientation eOrient = geom->GetEorient(eid);
2258
2259 // maparray is the location of the edge within the matrix
2260 GetTraceInteriorToElementMap(eid, maparray, signarray, eOrient);
2261
2262 for (n = 0; n < nEdgeCoeffs; ++n)
2263 {
2264 edgemaparray[n] = invmap[maparray[n]];
2265 }
2266
2267 return edgemaparray;
2268}
2269
2271{
2273}
2274
2276 Array<OneD, int> &idmap, const int nq0,
2277 [[maybe_unused]] const int nq1)
2278{
2279 if (idmap.size() != nq0)
2280 {
2281 idmap = Array<OneD, int>(nq0);
2282 }
2283 switch (orient)
2284 {
2286 // Fwd
2287 for (int i = 0; i < nq0; ++i)
2288 {
2289 idmap[i] = i;
2290 }
2291 break;
2293 {
2294 // Bwd
2295 for (int i = 0; i < nq0; ++i)
2296 {
2297 idmap[i] = nq0 - 1 - i;
2298 }
2299 }
2300 break;
2301 default:
2302 ASSERTL0(false, "Unknown orientation");
2303 break;
2304 }
2305}
2306
2307// Compute edgenormal \cdot vector
2309 const int dir, const int edge, ExpansionSharedPtr &EdgeExp_e,
2310 const Array<OneD, const Array<OneD, NekDouble>> &normals,
2311 const StdRegions::VarCoeffMap &varcoeffs)
2312{
2313 int nquad_e = EdgeExp_e->GetNumPoints(0);
2314 int coordim = GetCoordim();
2315 int nquad0 = m_base[0]->GetNumPoints();
2316 int nquad1 = m_base[1]->GetNumPoints();
2317 int nqtot = nquad0 * nquad1;
2318
2319 StdRegions::VarCoeffType MMFCoeffs[15] = {
2328
2329 StdRegions::VarCoeffMap::const_iterator MFdir;
2330
2331 Array<OneD, NekDouble> ncdotMF(nqtot, 0.0);
2332 Array<OneD, NekDouble> tmp(nqtot);
2333 Array<OneD, NekDouble> tmp_e(nquad_e);
2334 for (int k = 0; k < coordim; k++)
2335 {
2336 MFdir = varcoeffs.find(MMFCoeffs[dir * 5 + k]);
2337 tmp = MFdir->second.GetValue();
2338
2339 GetPhysEdgeVarCoeffsFromElement(edge, EdgeExp_e, tmp, tmp_e);
2340
2341 Vmath::Vvtvp(nquad_e, &tmp_e[0], 1, &normals[k][0], 1, &ncdotMF[0], 1,
2342 &ncdotMF[0], 1);
2343 }
2344 return ncdotMF;
2345}
2346
2348 const Array<OneD, Array<OneD, NekDouble>> &vec)
2349{
2351 GetLeftAdjacentElementExp()->GetTraceNormal(
2353
2354 int nq = GetTotPoints();
2356 Vmath::Vmul(nq, &vec[0][0], 1, &normals[0][0], 1, &Fn[0], 1);
2357 Vmath::Vvtvp(nq, &vec[1][0], 1, &normals[1][0], 1, &Fn[0], 1, &Fn[0], 1);
2358 Vmath::Vvtvp(nq, &vec[2][0], 1, &normals[2][0], 1, &Fn[0], 1, &Fn[0], 1);
2359
2360 return StdExpansion::Integral(Fn);
2361}
2362
2363void Expansion2D::v_TraceNormLen(const int traceid, NekDouble &h, NekDouble &p)
2364{
2366
2367 int nverts = geom->GetNumVerts();
2368
2369 // vertices on edges
2370 SpatialDomains::PointGeom ev0 = *geom->GetVertex(traceid);
2371 SpatialDomains::PointGeom ev1 = *geom->GetVertex((traceid + 1) % nverts);
2372
2373 // vertex on adjacent edge to ev0
2375 *geom->GetVertex((traceid + (nverts - 1)) % nverts);
2376
2377 // calculate perpendicular distance of normal length
2378 // from first vertex
2379 NekDouble h1 = ev0.dist(vadj);
2381
2382 Dx.Sub(ev1, ev0);
2383 Dx1.Sub(vadj, ev0);
2384
2385 NekDouble d1 = Dx.dot(Dx1);
2386 NekDouble lenDx = Dx.dot(Dx);
2387 h = sqrt(h1 * h1 - d1 * d1 / lenDx);
2388
2389 // perpendicular distanace from second vertex
2390 SpatialDomains::PointGeom vadj1 = *geom->GetVertex((traceid + 2) % nverts);
2391
2392 h1 = ev1.dist(vadj1);
2393 Dx1.Sub(vadj1, ev1);
2394 d1 = Dx.dot(Dx1);
2395
2396 h = (h + sqrt(h1 * h1 - d1 * d1 / lenDx)) * 0.5;
2397
2398 int dirn = (geom->GetDir(traceid) == 0) ? 1 : 0;
2399
2400 p = (NekDouble)(GetBasisNumModes(dirn) - 1);
2401}
2402} // namespace Nektar::LocalRegions
#define ASSERTL0(condition, msg)
#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
Describes the specification for a Basis.
Definition Basis.h:45
void v_AddEdgeNormBoundaryInt(const int edge, const ExpansionSharedPtr &EdgeExp, const Array< OneD, const NekDouble > &Fx, const Array< OneD, const NekDouble > &Fy, Array< OneD, NekDouble > &outarray) override
DNekMatSharedPtr v_GenMatrix(const StdRegions::StdMatrixKey &mkey) override
SpatialDomains::Geometry2D * GetGeom2D() const
std::vector< bool > m_requireNeg
void v_AddRobinTraceContribution(const int traceid, const Array< OneD, const NekDouble > &primCoeffs, const Array< OneD, NekDouble > &incoeffs, Array< OneD, NekDouble > &coeffs) override
void v_SetUpPhysNormals(const int edge) override
void v_AddRobinMassMatrix(const int edgeid, const Array< OneD, const NekDouble > &primCoeffs, DNekMatSharedPtr &inoutmat) override
Array< OneD, NekDouble > GetnEdgecdotMF(const int dir, const int edge, ExpansionSharedPtr &EdgeExp_e, const Array< OneD, const Array< OneD, NekDouble > > &normals, const StdRegions::VarCoeffMap &varcoeffs)
void SetTraceToGeomOrientation(Array< OneD, ExpansionSharedPtr > &EdgeExp, Array< OneD, NekDouble > &inout)
DNekMatSharedPtr v_BuildVertexMatrix(const DNekScalMatSharedPtr &r_bnd) override
NekDouble v_VectorFlux(const Array< OneD, Array< OneD, NekDouble > > &vec) override
DNekScalMatSharedPtr CreateMatrix(const MatrixKey &mkey)
Array< OneD, unsigned int > GetTraceInverseBoundaryMap(int eid)
Expansion2D(SpatialDomains::Geometry2D *pGeom)
void v_ReOrientTracePhysMap(const StdRegions::Orientation orient, Array< OneD, int > &idmap, const int nq0, const int nq1) override
void AddNormTraceInt(const int dir, Array< OneD, ExpansionSharedPtr > &EdgeExp, Array< OneD, Array< OneD, NekDouble > > &edgeCoeffs, Array< OneD, NekDouble > &outarray)
void AddHDGHelmholtzEdgeTerms(const NekDouble tau, const int edge, Array< OneD, ExpansionSharedPtr > &EdgeExp, Array< OneD, NekDouble > &edgePhys, const StdRegions::VarCoeffMap &dirForcing, Array< OneD, NekDouble > &outarray)
void v_DGDeriv(const int dir, const Array< OneD, const NekDouble > &incoeffs, Array< OneD, ExpansionSharedPtr > &EdgeExp, Array< OneD, Array< OneD, NekDouble > > &edgeCoeffs, Array< OneD, NekDouble > &out_d) override
void v_TraceNormLen(const int traceid, NekDouble &h, NekDouble &p) override
void GetPhysEdgeVarCoeffsFromElement(const int edge, ExpansionSharedPtr &EdgeExp, const Array< OneD, const NekDouble > &varcoeff, Array< OneD, NekDouble > &outarray)
void AddEdgeBoundaryInt(const int edge, ExpansionSharedPtr &EdgeExp, Array< OneD, NekDouble > &edgePhys, Array< OneD, NekDouble > &outarray, const StdRegions::VarCoeffMap &varcoeffs=StdRegions::NullVarCoeffMap)
void AddHDGHelmholtzTraceTerms(const NekDouble tau, const Array< OneD, const NekDouble > &inarray, Array< OneD, ExpansionSharedPtr > &EdgeExp, const StdRegions::VarCoeffMap &dirForcing, Array< OneD, NekDouble > &outarray)
void v_GenTraceExp(const int traceid, ExpansionSharedPtr &exp) override
void DropLocMatrix(const LocalRegions::MatrixKey &mkey)
Definition Expansion.cpp:90
SpatialDomains::Geometry * GetGeom() const
ExpansionSharedPtr GetLeftAdjacentElementExp() const
Definition Expansion.h:447
DNekMatSharedPtr BuildVertexMatrix(const DNekScalMatSharedPtr &r_bnd)
SpatialDomains::Geometry * m_geom
Definition Expansion.h:279
void ComputeGmatcdotMF(const Array< TwoD, const NekDouble > &df, const Array< OneD, const NekDouble > &direction, Array< OneD, Array< OneD, NekDouble > > &dfdir)
virtual void v_ComputeTraceNormal(const int id)
Array< OneD, NekDouble > GetMFMag(const int dir, const StdRegions::VarCoeffMap &varcoeffs)
int GetLeftAdjacentElementTrace() const
Definition Expansion.h:460
void GetTracePhysVals(const int trace, const StdRegions::StdExpansionSharedPtr &TraceExp, const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray, StdRegions::Orientation orient=StdRegions::eNoOrientation)
Definition Expansion.h:200
std::map< int, ExpansionWeakPtr > m_traceExp
Definition Expansion.h:278
void AddEdgeNormBoundaryInt(const int edge, const std::shared_ptr< Expansion > &EdgeExp, const Array< OneD, const NekDouble > &Fx, const Array< OneD, const NekDouble > &Fy, Array< OneD, NekDouble > &outarray)
SpatialDomains::GeomFactorsSharedPtr m_metricinfo
Definition Expansion.h:280
virtual StdRegions::Orientation v_GetTraceOrient(int trace)
ExpansionSharedPtr GetTraceExp(const int traceid)
Definition Expansion.h:420
StdRegions::Orientation GetTraceOrient(int trace)
Definition Expansion.h:168
IndexMapValuesSharedPtr GetIndexMap(const IndexMapKey &ikey)
Definition Expansion.h:146
DNekScalMatSharedPtr GetLocMatrix(const LocalRegions::MatrixKey &mkey)
Definition Expansion.cpp:84
Array< OneD, NekDouble > GetMFDiv(const int dir, const StdRegions::VarCoeffMap &varcoeffs)
void TraceNormLen(const int traceid, NekDouble &h, NekDouble &p)
Definition Expansion.h:250
const NormalVector & GetTraceNormal(const int id)
Array< OneD, NekDouble > GetMF(const int dir, const int shapedim, const StdRegions::VarCoeffMap &varcoeffs)
static std::shared_ptr< DataType > AllocateSharedPtr(const Args &...args)
Allocate a shared pointer from the memory pool.
2D geometry information
Definition Geometry2D.h:50
Base class for shape geometry information.
Definition Geometry.h:74
int GetGlobalID(void) const
Get the ID of this object.
Definition Geometry.h:322
PointGeom * GetVertex(int i) const
Returns vertex i of this object.
Definition Geometry.h:361
int GetDir(const int i, const int j=0) const
Returns the element coordinate direction corresponding to a given face coordinate direction.
Definition Geometry.h:661
int GetNumVerts() const
Get the number of vertices of this object.
Definition Geometry.h:403
Geometry1D * GetEdge(int i) const
Returns edge i of this object.
Definition Geometry.h:369
StdRegions::Orientation GetEorient(const int i) const
Returns the orientation of edge i with respect to the ordering of edges in the standard element.
Definition Geometry.h:386
void Sub(PointGeom &a, PointGeom &b)
NekDouble dot(PointGeom &a)
retun the dot product between this and input a
NekDouble dist(PointGeom &a)
return distance between this and input a
void GetBoundaryMap(Array< OneD, unsigned int > &outarray)
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.
DNekMatSharedPtr GetStdMatrix(const StdMatrixKey &mkey)
const LibUtilities::PointsKeyVector GetPointsKeys() const
DNekScalBlkMatSharedPtr GetLocStaticCondMatrix(const LocalRegions::MatrixKey &mkey)
int GetVertexMap(const int localVertexId, bool useCoeffPacking=false)
void IProductWRTBase(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray)
this function calculates the inner product of a given function f with the different modes of the expa...
int GetNtraces() const
Returns the number of trace elements connected to this element.
int GetNverts() const
This function returns the number of vertices of the expansion 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 GetTraceInteriorToElementMap(const int tid, Array< OneD, unsigned int > &maparray, Array< OneD, int > &signarray, const Orientation traceOrient=eForwards)
int GetTraceNcoeffs(const int i) const
This function returns the number of expansion coefficients belonging to the i-th trace.
DNekMatSharedPtr GenMatrix(const StdMatrixKey &mkey)
void FwdTrans(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray)
This function performs the Forward transformation from physical space to coefficient space.
const LibUtilities::BasisKey GetTraceBasisKey(const int i, int k=-1, bool UseGLL=false) const
This function returns the basis key belonging to the i-th trace.
LibUtilities::NekManager< StdMatrixKey, DNekMat, StdMatrixKey::opLess > m_stdMatrixManager
int GetBasisNumModes(const int dir) const
This function returns the number of expansion modes in the dir direction.
void PhysDeriv(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &out_d0, Array< OneD, NekDouble > &out_d1=NullNekDouble1DArray, Array< OneD, NekDouble > &out_d2=NullNekDouble1DArray)
Array< OneD, LibUtilities::BasisSharedPtr > m_base
LibUtilities::ShapeType GetShapeType() const
const VarCoeffMap & GetVarCoeffs() const
MatrixType GetMatrixType() const
bool HasVarCoeff(const StdRegions::VarCoeffType &coeff) const
const ConstFactorMap & GetConstFactors() const
const Array< OneD, const NekDouble > & GetVarCoeff(const StdRegions::VarCoeffType &coeff) const
NekDouble GetConstFactor(const ConstFactorType &factor) const
bool ConstFactorExists(const ConstFactorType &factor) const
const VarCoeffMap GetVarCoeffAsMap(const VarCoeffType &coeff) const
void Interp1D(const BasisKey &fbasis0, const Array< OneD, const NekDouble > &from, const BasisKey &tbasis0, Array< OneD, NekDouble > &to)
this function interpolates a 1D function evaluated at the quadrature points of the basis fbasis0 to ...
Definition Interp.cpp:47
void InterpCoeff1D(const BasisKey &fbasis0, const Array< OneD, const NekDouble > &from, const BasisKey &tbasis0, Array< OneD, NekDouble > &to)
std::vector< PointsKey > PointsKeyVector
Definition Points.h:231
@ eGauss_Lagrange
Lagrange Polynomials using the Gauss points.
Definition BasisType.h:57
@ eGLL_Lagrange
Lagrange for SEM basis .
Definition BasisType.h:56
@ eModified_A
Principle Modified Functions .
Definition BasisType.h:48
std::shared_ptr< Expansion > ExpansionSharedPtr
Definition Expansion.h:66
std::shared_ptr< IndexMapValues > IndexMapValuesSharedPtr
std::shared_ptr< Expansion1D > Expansion1DSharedPtr
Definition Expansion1D.h:50
@ eNoGeomType
No type defined.
@ eDeformed
Geometry is curved or has non-constant factors.
std::map< ConstFactorType, NekDouble > ConstFactorMap
static ConstFactorMap NullConstFactorMap
static VarCoeffMap NullVarCoeffMap
std::map< StdRegions::VarCoeffType, VarCoeffEntry > VarCoeffMap
std::shared_ptr< DNekScalMat > DNekScalMatSharedPtr
std::shared_ptr< DNekScalBlkMat > DNekScalBlkMatSharedPtr
static Array< OneD, NekDouble > NullNekDouble1DArray
NekMatrix< InnerMatrixType, BlockMatrixTag > Transpose(NekMatrix< InnerMatrixType, BlockMatrixTag > &rhs)
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 Neg(int n, T *x, const int incx)
Negate x = -x.
Definition Vmath.hpp:292
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 Zero(int n, T *x, const int incx)
Zero vector.
Definition Vmath.hpp:273
void Fill(int n, const T alpha, T *x, const int incx)
Fill a vector with a constant value.
Definition Vmath.hpp:54
void Vcopy(int n, const T *x, const int incx, T *y, const int incy)
Definition Vmath.hpp:825
STL namespace.
scalarT< T > min(scalarT< T > lhs, scalarT< T > rhs)
Definition scalar.hpp:300
scalarT< T > sqrt(scalarT< T > in)
Definition scalar.hpp:290