Nektar++
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 
35 #include <boost/core/ignore_unused.hpp>
36 
43 #include <LocalRegions/MatrixKey.h>
45 using namespace std;
46 
47 namespace Nektar
48 {
49  namespace LocalRegions
50  {
51  Expansion2D::Expansion2D(SpatialDomains::Geometry2DSharedPtr pGeom) :
52  StdExpansion(), Expansion(pGeom), StdExpansion2D()
53  {
54  }
55 
57  const int edge,
58  const ExpansionSharedPtr &EdgeExp,
61  Array<OneD, NekDouble> &outarray)
62  {
63  ASSERTL1(GetCoordim() == 2,
64  "Routine only set up for two-dimensions");
65 
67  = GetTraceNormal(edge);
68 
69  if (m_requireNeg.size() == 0)
70  {
71  int nedges = GetNtraces();
72  m_requireNeg.resize(nedges);
73 
74  for (int i = 0; i < nedges;++i)
75  {
76  m_requireNeg[i] = false;
77 
78  ExpansionSharedPtr edgeExp = m_traceExp[i].lock();
79 
80  if (edgeExp->GetRightAdjacentElementExp())
81  {
82  if (edgeExp->GetRightAdjacentElementExp()->GetGeom()
83  ->GetGlobalID() == GetGeom()->GetGlobalID())
84  {
85  m_requireNeg[i] = true;
86  }
87  }
88  }
89  }
90 
91  // We allow the case of mixed polynomial order by supporting only
92  // those modes on the edge common to both adjoining elements. This
93  // is enforced here by taking the minimum size and padding with
94  // zeros.
95  int nquad_e = min(EdgeExp->GetNumPoints(0),
96  int(normals[0].size()));
97 
98  int nEdgePts = EdgeExp->GetTotPoints();
99  Array<OneD, NekDouble> edgePhys(nEdgePts);
100  Vmath::Vmul (nquad_e, normals[0], 1, Fx, 1, edgePhys, 1);
101  Vmath::Vvtvp(nquad_e, normals[1], 1, Fy, 1, edgePhys, 1,
102  edgePhys, 1);
103 
104  Expansion1DSharedPtr locExp = EdgeExp->as<Expansion1D>();
105 
106  if (m_requireNeg[edge])
107  {
108  if (locExp->GetRightAdjacentElementExp()->GetGeom()->GetGlobalID()
109  == m_geom->GetGlobalID())
110  {
111  Vmath::Neg(nquad_e, edgePhys, 1);
112  }
113  }
114 
115  AddEdgeNormBoundaryInt(edge, EdgeExp, edgePhys, outarray);
116  }
117 
119  const int edge,
120  const ExpansionSharedPtr &EdgeExp,
122  Array<OneD, NekDouble> &outarray)
123  {
124  int i;
125 
126  if (m_requireNeg.size() == 0)
127  {
128  int nedges = GetNtraces();
129  m_requireNeg.resize(nedges);
130 
131  for (i = 0; i < nedges; ++i)
132  {
133  m_requireNeg[i] = false;
134 
135  ExpansionSharedPtr edgeExp = m_traceExp[i].lock();
136 
137  if (edgeExp->GetRightAdjacentElementExp())
138  {
139  if (edgeExp->GetRightAdjacentElementExp()->GetGeom()
140  ->GetGlobalID() == GetGeom()->GetGlobalID())
141  {
142  m_requireNeg[i] = true;
143  }
144  }
145  }
146  }
147 
150  edge, GetTraceOrient(edge));
151 
153 
154  // Order of the element
155  int order_e = map->size();
156  // Order of the trace
157  int n_coeffs = EdgeExp->GetNcoeffs();
158 
159  Array<OneD, NekDouble> edgeCoeffs(n_coeffs);
160  if(n_coeffs!=order_e) // Going to orthogonal space
161  {
162  EdgeExp->FwdTrans(Fn, edgeCoeffs);
163  Expansion1DSharedPtr locExp = EdgeExp->as<Expansion1D>();
164 
165  if (m_requireNeg[edge])
166  {
167  Vmath::Neg(n_coeffs, edgeCoeffs, 1);
168  }
169 
170  Array<OneD, NekDouble> coeff(n_coeffs,0.0);
171  LibUtilities::BasisType btype = ((LibUtilities::BasisType) 1); //1-->Ortho_A
172  LibUtilities::BasisKey bkey_ortho(btype,EdgeExp->GetBasis(0)->GetNumModes(),EdgeExp->GetBasis(0)->GetPointsKey());
173  LibUtilities::BasisKey bkey(EdgeExp->GetBasis(0)->GetBasisType(),EdgeExp->GetBasis(0)->GetNumModes(),EdgeExp->GetBasis(0)->GetPointsKey());
174  LibUtilities::InterpCoeff1D(bkey,edgeCoeffs,bkey_ortho,coeff);
175 
176  // Cutting high frequencies
177  for(i = order_e; i < n_coeffs; i++)
178  {
179  coeff[i] = 0.0;
180  }
181 
182  LibUtilities::InterpCoeff1D(bkey_ortho,coeff,bkey,edgeCoeffs);
183 
185  EdgeExp->MassMatrixOp(edgeCoeffs, edgeCoeffs, masskey);
186  }
187  else
188  {
189  EdgeExp->IProductWRTBase(Fn, edgeCoeffs);
190 
191  Expansion1DSharedPtr locExp = EdgeExp->as<Expansion1D>();
192 
193  if (m_requireNeg[edge])
194  {
195  Vmath::Neg(n_coeffs, edgeCoeffs, 1);
196  }
197  }
198 
199  // Implementation for all the basis except Gauss points
200  if(EdgeExp->GetBasis(0)->GetBasisType() !=
202  {
203  // add data to outarray if forward edge normal is outwards
204  for(i = 0; i < order_e; ++i)
205  {
206  outarray[(*map)[i].index] +=
207  (*map)[i].sign * edgeCoeffs[i];
208  }
209  }
210  else
211  {
212  int nCoeffs0, nCoeffs1;
213  int j;
214 
216  factors[StdRegions::eFactorGaussEdge] = edge;
218  DetShapeType(),*this,factors);
219 
220  DNekMatSharedPtr mat_gauss = m_stdMatrixManager[key];
221 
222  switch(edge)
223  {
224  case 0:
225  {
226  nCoeffs1 = m_base[1]->GetNumModes();
227 
228  for(i = 0; i < order_e; ++i)
229  {
230  for(j = 0; j < nCoeffs1; j++)
231  {
232  outarray[(*map)[i].index + j*order_e] +=
233  mat_gauss->GetPtr()[j]*
234  (*map)[i].sign*edgeCoeffs[i];
235  }
236  }
237  break;
238  }
239  case 1:
240  {
241  nCoeffs0 = m_base[0]->GetNumModes();
242 
243  for(i = 0; i < order_e; ++i)
244  {
245  for(j = 0; j < nCoeffs0; j++)
246  {
247  outarray[(*map)[i].index - j] +=
248  mat_gauss->GetPtr()[order_e - 1 -j]*
249  (*map)[i].sign*edgeCoeffs[i];
250  }
251  }
252  break;
253  }
254  case 2:
255  {
256  nCoeffs1 = m_base[1]->GetNumModes();
257 
258  for(i = 0; i < order_e; ++i)
259  {
260  for(j = 0; j < nCoeffs1; j++)
261  {
262  outarray[(*map)[i].index - j*order_e] +=
263  mat_gauss->GetPtr()[order_e - 1 - j]*
264  (*map)[i].sign*edgeCoeffs[i];
265  }
266  }
267  break;
268  }
269  case 3:
270  {
271  nCoeffs0 = m_base[0]->GetNumModes();
272 
273  for(i = 0; i < order_e; ++i)
274  {
275  for(j = 0; j < nCoeffs0; j++)
276  {
277  outarray[(*map)[i].index + j] +=
278  mat_gauss->GetPtr()[j]*
279  (*map)[i].sign*edgeCoeffs[i];
280  }
281  }
282  break;
283  }
284  default:
285  ASSERTL0(false,"edge value (< 3) is out of range");
286  break;
287  }
288  }
289  }
290 
293  Array<OneD, NekDouble> &inout)
294  {
295  int i, cnt = 0;
296  int nedges = GetNtraces();
298 
299  for(i = 0; i < nedges; ++i)
300  {
301  EdgeExp[i]->SetCoeffsToOrientation(GetTraceOrient(i),
302  e_tmp = inout + cnt,
303  e_tmp = inout + cnt);
304  cnt += GetTraceNcoeffs(i);
305  }
306  }
307 
308  /**
309  * Computes the C matrix entries due to the presence of the identity
310  * matrix in Eqn. 32.
311  */
313  const int dir,
316  Array<OneD, NekDouble> &outarray,
317  const StdRegions::VarCoeffMap &varcoeffs)
318  {
319  int i,e,cnt;
320  int order_e,nquad_e;
321  int nedges = GetNtraces();
322 
323  cnt = 0;
324  for(e = 0; e < nedges; ++e)
325  {
326  order_e = EdgeExp[e]->GetNcoeffs();
327  nquad_e = EdgeExp[e]->GetNumPoints(0);
328 
330  = GetTraceNormal(e);
331  Array<OneD, NekDouble> edgeCoeffs(order_e);
332  Array<OneD, NekDouble> edgePhys (nquad_e);
333 
334  for(i = 0; i < order_e; ++i)
335  {
336  edgeCoeffs[i] = inarray[i+cnt];
337  }
338  cnt += order_e;
339 
340  EdgeExp[e]->BwdTrans(edgeCoeffs, edgePhys);
341 
342  // Multiply by variable coefficient
343  /// @TODO: Document this
344  // StdRegions::VarCoeffType VarCoeff[3] = {StdRegions::eVarCoeffD00,
345  // StdRegions::eVarCoeffD11,
346  // StdRegions::eVarCoeffD22};
347  // StdRegions::VarCoeffMap::const_iterator x;
348  // Array<OneD, NekDouble> varcoeff_work(nquad_e);
349 
350  // if ((x = varcoeffs.find(VarCoeff[dir])) != varcoeffs.end())
351  // {
352  // GetPhysEdgeVarCoeffsFromElement(e,EdgeExp[e],x->second,varcoeff_work);
353  // Vmath::Vmul(nquad_e,varcoeff_work,1,EdgeExp[e]->GetPhys(),1,EdgeExp[e]->UpdatePhys(),1);
354  // }
355 
356  if (varcoeffs.find(StdRegions::eVarCoeffMF1x) !=
357  varcoeffs.end())
358  {
359  // MMF case
360  Array<OneD, NekDouble> ncdotMF_e =
361  v_GetnEdgecdotMF(dir, e, EdgeExp[e], normals,
362  varcoeffs);
363 
364  Vmath::Vmul(nquad_e, ncdotMF_e, 1,
365  edgePhys, 1,
366  edgePhys, 1);
367  }
368  else
369  {
370  Vmath::Vmul(nquad_e, normals[dir], 1,
371  edgePhys, 1,
372  edgePhys, 1);
373  }
374 
375  AddEdgeBoundaryInt(e, EdgeExp[e], edgePhys, outarray, varcoeffs);
376  }
377  }
378 
380  const int dir,
382  Array<OneD, Array<OneD, NekDouble> > &edgeCoeffs,
383  Array<OneD, NekDouble> &outarray)
384  {
385  int e;
386  int nquad_e;
387  int nedges = GetNtraces();
388 
389  for(e = 0; e < nedges; ++e)
390  {
391  nquad_e = EdgeExp[e]->GetNumPoints(0);
392 
393  Array<OneD, NekDouble> edgePhys(nquad_e);
395  = GetTraceNormal(e);
396 
397  EdgeExp[e]->BwdTrans(edgeCoeffs[e], edgePhys);
398 
399  Vmath::Vmul(nquad_e, normals[dir], 1, edgePhys, 1, edgePhys, 1);
400 
401  AddEdgeBoundaryInt(e, EdgeExp[e], edgePhys, outarray);
402  }
403  }
404 
405 
406  /**
407  * For a given edge add the \tilde{F}_1j contributions
408  */
410  const int edge,
411  ExpansionSharedPtr &EdgeExp,
412  Array<OneD, NekDouble> &edgePhys,
413  Array<OneD, NekDouble> &outarray,
414  const StdRegions::VarCoeffMap &varcoeffs)
415  {
416  int i;
417  int order_e = EdgeExp->GetNcoeffs();
418  int nquad_e = EdgeExp->GetNumPoints(0);
421  Array<OneD, NekDouble> coeff(order_e);
422 
423  GetTraceToElementMap(edge, map, sign, v_GetTraceOrient(edge));
424 
428  StdRegions::VarCoeffMap::const_iterator x;
429 
430  /// @TODO Variable coeffs
431  if ((x = varcoeffs.find(VarCoeff[0])) != varcoeffs.end())
432  {
433  Array<OneD, NekDouble> work(nquad_e);
435  edge, EdgeExp, x->second, work);
436  Vmath::Vmul(nquad_e, work, 1, edgePhys, 1, edgePhys, 1);
437  }
438 
439  EdgeExp->IProductWRTBase(edgePhys, coeff);
440 
441  // add data to out array
442  for(i = 0; i < order_e; ++i)
443  {
444  outarray[map[i]] += sign[i]*coeff[i];
445  }
446  }
447 
448  // This method assumes that data in EdgeExp is orientated according to
449  // elemental counter clockwise format AddHDGHelmholtzTraceTerms with
450  // directions
452  const NekDouble tau,
453  const Array<OneD, const NekDouble> &inarray,
455  const StdRegions::VarCoeffMap &dirForcing,
456  Array<OneD,NekDouble> &outarray)
457  {
458  ASSERTL0(&inarray[0] != &outarray[0],
459  "Input and output arrays use the same memory");
460 
461  int e, cnt, order_e, nedges = GetNtraces();
463 
464  cnt = 0;
465 
466  for(e = 0; e < nedges; ++e)
467  {
468  order_e = EdgeExp[e]->GetNcoeffs();
469  Array<OneD, NekDouble> edgeCoeffs(order_e);
470  Array<OneD, NekDouble> edgePhys (EdgeExp[e]->GetTotPoints());
471 
472  Vmath::Vcopy(order_e, tmp = inarray + cnt, 1, edgeCoeffs, 1);
473  EdgeExp[e]->BwdTrans(edgeCoeffs, edgePhys);
475  tau, e, EdgeExp, edgePhys, dirForcing, outarray);
476 
477  cnt += order_e;
478  }
479  }
480 
481  // evaluate additional terms in HDG edges. Not that this assumes that
482  // edges are unpacked into local cartesian order.
484  const NekDouble tau,
485  const int edge,
487  Array<OneD, NekDouble> &edgePhys,
488  const StdRegions::VarCoeffMap &varcoeffs,
489  Array<OneD, NekDouble> &outarray)
490  {
491  bool mmf = (varcoeffs.find(StdRegions::eVarCoeffMF1x) !=
492  varcoeffs.end());
493  int i, j, n;
494  int nquad_e = EdgeExp[edge]->GetNumPoints(0);
495  int order_e = EdgeExp[edge]->GetNcoeffs();
496  int coordim = mmf ? 2 : GetCoordim();
497  int ncoeffs = GetNcoeffs();
498 
499  Array<OneD, NekDouble> inval (nquad_e);
500  Array<OneD, NekDouble> outcoeff(order_e);
501  Array<OneD, NekDouble> tmpcoeff(ncoeffs);
502 
504  = GetTraceNormal(edge);
505 
508 
509  StdRegions::Orientation edgedir = GetTraceOrient(edge);
510 
511  DNekVec Coeffs (ncoeffs,outarray,eWrapper);
512  DNekVec Tmpcoeff(ncoeffs,tmpcoeff,eWrapper);
513 
514  GetTraceToElementMap(edge,emap,sign,edgedir);
515 
516  StdRegions::MatrixType DerivType[3] =
517  {
521  };
522 
523  StdRegions::VarCoeffType VarCoeff[3] =
524  {
528  };
529 
530  StdRegions::VarCoeffMap::const_iterator x;
531  /// @TODO: What direction to use here??
532  if ((x = varcoeffs.find(VarCoeff[0])) != varcoeffs.end())
533  {
534  Array<OneD, NekDouble> work(nquad_e);
536  edge, EdgeExp[edge], x->second, work);
537  Vmath::Vmul(nquad_e, work, 1, edgePhys, 1, edgePhys, 1);
538  }
539 
540  //================================================================
541  // Add F = \tau <phi_i,in_phys>
542  // Fill edge and take inner product
543  EdgeExp[edge]->IProductWRTBase(edgePhys, outcoeff);
544  // add data to out array
545  for(i = 0; i < order_e; ++i)
546  {
547  outarray[emap[i]] += sign[i] * tau * outcoeff[i];
548  }
549  //================================================================
550 
551  //===============================================================
552  // Add -\sum_i D_i^T M^{-1} G_i + E_i M^{-1} G_i =
553  // \sum_i D_i M^{-1} G_i term
554 
555  // Two independent direction
556  DNekScalMatSharedPtr invMass;
557  for(n = 0; n < coordim; ++n)
558  {
559  if (mmf)
560  {
562  Weight[StdRegions::eVarCoeffMass] = v_GetMFMag(n,varcoeffs);
563 
564  MatrixKey invMasskey( StdRegions::eInvMass,
565  DetShapeType(), *this,
567  Weight);
568 
569  invMass = GetLocMatrix(invMasskey);
570 
571  Array<OneD, NekDouble> ncdotMF_e =
572  v_GetnEdgecdotMF(n, edge, EdgeExp[edge], normals,
573  varcoeffs);
574 
575  Vmath::Vmul(nquad_e, ncdotMF_e, 1, edgePhys, 1, inval, 1);
576  }
577  else
578  {
579  Vmath::Vmul(nquad_e, normals[n], 1, edgePhys, 1, inval, 1);
581  }
582 
583  // Multiply by variable coefficient
584  /// @TODO: Document this (probably not needed)
585 // StdRegions::VarCoeffMap::const_iterator x;
586 // if ((x = varcoeffs.find(VarCoeff[n])) != varcoeffs.end())
587 // {
588 // GetPhysEdgeVarCoeffsFromElement(edge,EdgeExp[edge],x->second,varcoeff_work);
589 // Vmath::Vmul(nquad_e,varcoeff_work,1,EdgeExp[edge]->GetPhys(),1,EdgeExp[edge]->UpdatePhys(),1);
590 // }
591 
592  EdgeExp[edge]->IProductWRTBase(inval, outcoeff);
593 
594  // M^{-1} G
595  for(i = 0; i < ncoeffs; ++i)
596  {
597  tmpcoeff[i] = 0;
598  for(j = 0; j < order_e; ++j)
599  {
600  tmpcoeff[i] += (*invMass)(i,emap[j]) * sign[j]
601  * outcoeff[j];
602  }
603  }
604 
605  if (mmf)
606  {
607  StdRegions::VarCoeffMap VarCoeffDirDeriv;
608  VarCoeffDirDeriv[StdRegions::eVarCoeffMF] =
609  v_GetMF(n,coordim,varcoeffs);
610  VarCoeffDirDeriv[StdRegions::eVarCoeffMFDiv] =
611  v_GetMFDiv(n,varcoeffs);
612 
614  DetShapeType(), *this,
616  VarCoeffDirDeriv);
617 
618  DNekScalMat &Dmat = *GetLocMatrix(Dmatkey);
619 
620  Coeffs = Coeffs + Dmat*Tmpcoeff;
621  }
622  else
623  {
624  if(varcoeffs.find(VarCoeff[n]) != varcoeffs.end())
625  {
626  MatrixKey mkey(DerivType[n], DetShapeType(), *this,
627  StdRegions::NullConstFactorMap, varcoeffs);
628 
629  DNekScalMat &Dmat = *GetLocMatrix(mkey);
630  Coeffs = Coeffs + Dmat*Tmpcoeff;
631  }
632  else
633  {
634  DNekScalMat &Dmat = *GetLocMatrix(DerivType[n]);
635  Coeffs = Coeffs + Dmat*Tmpcoeff;
636  }
637  }
638  }
639  }
640 
641 
642  /**
643  * Extracts the variable coefficients along an edge
644  */
646  const int edge,
647  ExpansionSharedPtr &EdgeExp,
648  const Array<OneD, const NekDouble> &varcoeff,
649  Array<OneD,NekDouble> &outarray)
650  {
652  Array<OneD, NekDouble> edgetmp(EdgeExp->GetNcoeffs());
653 
654  // FwdTrans varcoeffs
655  FwdTrans(varcoeff, tmp);
656 
657  // Map to edge
660  StdRegions::Orientation edgedir = GetTraceOrient(edge);
661  GetTraceToElementMap(edge,emap,sign,edgedir);
662 
663  for (unsigned int i = 0; i < EdgeExp->GetNcoeffs(); ++i)
664  {
665  edgetmp[i] = tmp[emap[i]];
666  }
667 
668  // BwdTrans
669  EdgeExp->BwdTrans(edgetmp, outarray);
670  }
671 
672 
673  /**
674  * Computes matrices needed for the HDG formulation. References to
675  * equations relate to the following paper:
676  * R. M. Kirby, S. J. Sherwin, B. Cockburn, To CG or to HDG: A
677  * Comparative Study, J. Sci. Comp P1-30
678  * DOI 10.1007/s10915-011-9501-7
679  */
681  {
682  DNekMatSharedPtr returnval;
683 
684  switch(mkey.GetMatrixType())
685  {
686  // (Z^e)^{-1} (Eqn. 33, P22)
688  {
690  "HybridDGHelmholtz matrix not set up "
691  "for non boundary-interior expansions");
692 
693  int i,j,k;
696  int ncoeffs = GetNcoeffs();
697  int nedges = GetNtraces();
698  int shapedim = 2;
699  const StdRegions::VarCoeffMap &varcoeffs
700  = mkey.GetVarCoeffs();
701  bool mmf =
702  (varcoeffs.find(StdRegions::eVarCoeffMF1x) !=
703  varcoeffs.end());
704 
708  ExpansionSharedPtr EdgeExp;
709 
710  int order_e, coordim = GetCoordim();
715  DNekMat LocMat(ncoeffs,ncoeffs);
716 
717  returnval = MemoryManager<DNekMat>::AllocateSharedPtr(ncoeffs,ncoeffs);
718  DNekMat &Mat = *returnval;
719  Vmath::Zero(ncoeffs*ncoeffs,Mat.GetPtr(),1);
720 
724 
725  StdRegions::VarCoeffMap::const_iterator x;
726 
727  for(i=0; i < coordim; ++i)
728  {
729  if (mmf)
730  {
731  if(i < shapedim)
732  {
733  StdRegions::VarCoeffMap VarCoeffDirDeriv;
734  VarCoeffDirDeriv[StdRegions::eVarCoeffMF] =
735  v_GetMF(i,shapedim,varcoeffs);
736  VarCoeffDirDeriv[StdRegions::eVarCoeffMFDiv] =
737  v_GetMFDiv(i,varcoeffs);
738 
739  MatrixKey Dmatkey(StdRegions::
741  DetShapeType(), *this,
742  StdRegions::
744  VarCoeffDirDeriv);
745 
746  DNekScalMat &Dmat = *GetLocMatrix(Dmatkey);
747 
749  Weight[StdRegions::eVarCoeffMass] =
750  v_GetMFMag(i,mkey.GetVarCoeffs());
751 
752  MatrixKey invMasskey( StdRegions::eInvMass,
753  DetShapeType(), *this,
754  StdRegions::
756  Weight);
757 
758  DNekScalMat &invMass =
759  *GetLocMatrix(invMasskey);
760 
761  Mat = Mat + Dmat*invMass*Transpose(Dmat);
762  }
763  }
764  else if(mkey.HasVarCoeff(Coeffs[i]))
765  {
766  MatrixKey DmatkeyL( DerivType[i],
767  DetShapeType(), *this,
769  mkey.GetVarCoeffAsMap(
770  Coeffs[i]));
771 
772  MatrixKey DmatkeyR( DerivType[i],
773  DetShapeType(), *this);
774 
775  DNekScalMat &DmatL = *GetLocMatrix(DmatkeyL);
776  DNekScalMat &DmatR = *GetLocMatrix(DmatkeyR);
777  Mat = Mat + DmatL*invMass*Transpose(DmatR);
778  }
779  else
780  {
781  DNekScalMat &Dmat = *GetLocMatrix(DerivType[i]);
782  Mat = Mat + Dmat*invMass*Transpose(Dmat);
783  }
784 
785  }
786 
787  // Add Mass Matrix Contribution for Helmholtz problem
789  Mat = Mat + lambdaval*Mass;
790 
791  // Add tau*E_l using elemental mass matrices on each edge
792  for(i = 0; i < nedges; ++i)
793  {
794  EdgeExp = GetTraceExp(i);
795  order_e = EdgeExp->GetNcoeffs();
796 
797  int nq = EdgeExp->GetNumPoints(0);
798  GetTraceToElementMap(i,emap,sign,edgedir);
799 
800  // @TODO: Document
801  StdRegions::VarCoeffMap edgeVarCoeffs;
803  {
804  Array<OneD, NekDouble> mu(nq);
806  edgeVarCoeffs[StdRegions::eVarCoeffMass] = mu;
807  }
808  DNekScalMat &eMass = *EdgeExp->GetLocMatrix(StdRegions::eMass, StdRegions::NullConstFactorMap, edgeVarCoeffs);
809  //DNekScalMat &eMass = *EdgeExp->GetLocMatrix(StdRegions::eMass);
810 
811  for(j = 0; j < order_e; ++j)
812  {
813  for(k = 0; k < order_e; ++k)
814  {
815  Mat(emap[j],emap[k]) = Mat(emap[j],emap[k]) + tau*sign[j]*sign[k]*eMass(j,k);
816  }
817  }
818  }
819  }
820  break;
821  // U^e (P22)
823  {
824  int i,j,k;
825  int nbndry = NumDGBndryCoeffs();
826  int ncoeffs = GetNcoeffs();
827  int nedges = GetNtraces();
829 
830  Array<OneD,NekDouble> lambda(nbndry);
831  DNekVec Lambda(nbndry,lambda,eWrapper);
832  Array<OneD,NekDouble> ulam(ncoeffs);
833  DNekVec Ulam(ncoeffs,ulam,eWrapper);
834  Array<OneD,NekDouble> f(ncoeffs);
835  DNekVec F(ncoeffs,f,eWrapper);
836 
837  Array<OneD, ExpansionSharedPtr> EdgeExp(nedges);
838  // declare matrix space
839  returnval = MemoryManager<DNekMat>::AllocateSharedPtr(ncoeffs,nbndry);
840  DNekMat &Umat = *returnval;
841 
842  // Z^e matrix
844  DNekScalMat &invHmat = *GetLocMatrix(newkey);
845 
848 
849  for(i = 0; i < nedges; ++i)
850  {
851  EdgeExp[i] = GetTraceExp(i);
852  }
853 
854  // for each degree of freedom of the lambda space
855  // calculate Umat entry
856  // Generate Lambda to U_lambda matrix
857  for(j = 0; j < nbndry; ++j)
858  {
859  // standard basis vectors e_j
860  Vmath::Zero(nbndry,&lambda[0],1);
861  Vmath::Zero(ncoeffs,&f[0],1);
862  lambda[j] = 1.0;
863 
864  SetTraceToGeomOrientation(EdgeExp,lambda);
865 
866  // Compute F = [I D_1 M^{-1} D_2 M^{-1}] C e_j
868  tau, lambda, EdgeExp, mkey.GetVarCoeffs(), f);
869 
870  // Compute U^e_j
871  Ulam = invHmat*F; // generate Ulam from lambda
872 
873  // fill column of matrix
874  for(k = 0; k < ncoeffs; ++k)
875  {
876  Umat(k,j) = Ulam[k];
877  }
878  }
879  }
880  break;
881  // Q_0, Q_1, Q_2 matrices (P23)
882  // Each are a product of a row of Eqn 32 with the C matrix.
883  // Rather than explicitly computing all of Eqn 32, we note each
884  // row is almost a multiple of U^e, so use that as our starting
885  // point.
889  {
890  int i = 0;
891  int j = 0;
892  int k = 0;
893  int dir = 0;
894  int nbndry = NumDGBndryCoeffs();
895  int ncoeffs = GetNcoeffs();
896  int nedges = GetNtraces();
897  int shapedim = 2;
898 
899  Array<OneD,NekDouble> lambda(nbndry);
900  DNekVec Lambda(nbndry,lambda,eWrapper);
901  Array<OneD, ExpansionSharedPtr> EdgeExp(nedges);
902 
903  Array<OneD,NekDouble> ulam(ncoeffs);
904  DNekVec Ulam(ncoeffs,ulam,eWrapper);
905  Array<OneD,NekDouble> f(ncoeffs);
906  DNekVec F(ncoeffs,f,eWrapper);
907 
908  // declare matrix space
909  returnval = MemoryManager<DNekMat>::AllocateSharedPtr(ncoeffs,nbndry);
910  DNekMat &Qmat = *returnval;
911 
912  // Lambda to U matrix
914  DNekScalMat &lamToU = *GetLocMatrix(lamToUkey);
915 
916  // Inverse mass matrix
918 
919 
920  for(i = 0; i < nedges; ++i)
921  {
922  EdgeExp[i] = GetTraceExp(i);
923  }
924 
925  //Weak Derivative matrix
927  switch(mkey.GetMatrixType())
928  {
930  dir = 0;
932  break;
934  dir = 1;
936  break;
938  dir = 2;
940  break;
941  default:
942  ASSERTL0(false,"Direction not known");
943  break;
944  }
945 
946  const StdRegions::VarCoeffMap &varcoeffs =
947  mkey.GetVarCoeffs();
948  if (varcoeffs.find(StdRegions::eVarCoeffMF1x) !=
949  varcoeffs.end())
950  {
951  StdRegions::VarCoeffMap VarCoeffDirDeriv;
952  VarCoeffDirDeriv[StdRegions::eVarCoeffMF] =
953  v_GetMF(dir,shapedim,varcoeffs);
954  VarCoeffDirDeriv[StdRegions::eVarCoeffMFDiv] =
955  v_GetMFDiv(dir,varcoeffs);
956 
958  DetShapeType(), *this,
960  VarCoeffDirDeriv);
961 
962  Dmat = GetLocMatrix(Dmatkey);
963 
965  Weight[StdRegions::eVarCoeffMass] =
966  v_GetMFMag(dir,mkey.GetVarCoeffs());
967 
968  MatrixKey invMasskey( StdRegions::eInvMass,
969  DetShapeType(), *this,
971  Weight);
972 
973  invMass = *GetLocMatrix(invMasskey);
974  }
975  else
976  {
977  StdRegions::MatrixType DerivType[3] = {
981 
982  Dmat = GetLocMatrix(DerivType[dir]);
983 
984  MatrixKey invMasskey( StdRegions::eInvMass,
985  DetShapeType(), *this);
986  invMass = *GetLocMatrix(invMasskey);
987  }
988 
989  // for each degree of freedom of the lambda space
990  // calculate Qmat entry
991  // Generate Lambda to Q_lambda matrix
992  for(j = 0; j < nbndry; ++j)
993  {
994  Vmath::Zero(nbndry,&lambda[0],1);
995  lambda[j] = 1.0;
996 
997  // for lambda[j] = 1 this is the solution to ulam
998  for(k = 0; k < ncoeffs; ++k)
999  {
1000  Ulam[k] = lamToU(k,j);
1001  }
1002 
1003  // -D^T ulam
1004  Vmath::Neg(ncoeffs,&ulam[0],1);
1005  F = Transpose(*Dmat)*Ulam;
1006 
1007  SetTraceToGeomOrientation(EdgeExp,lambda);
1008 
1009  // Add the C terms resulting from the I's on the
1010  // diagonals of Eqn 32
1011  AddNormTraceInt(dir,lambda,EdgeExp,f,mkey.GetVarCoeffs());
1012 
1013  // finally multiply by inverse mass matrix
1014  Ulam = invMass*F;
1015 
1016  // fill column of matrix (Qmat is in column major format)
1017  Vmath::Vcopy(ncoeffs,&ulam[0],1,&(Qmat.GetPtr())[0]+j*ncoeffs,1);
1018  }
1019  }
1020  break;
1021  // Matrix K (P23)
1023  {
1024  int i,j,e,cnt;
1025  int order_e, nquad_e;
1026  int nbndry = NumDGBndryCoeffs();
1027  int coordim = GetCoordim();
1028  int nedges = GetNtraces();
1030  StdRegions::VarCoeffMap::const_iterator x;
1031  const StdRegions::VarCoeffMap &varcoeffs
1032  = mkey.GetVarCoeffs();
1033  bool mmf =
1034  (varcoeffs.find(StdRegions::eVarCoeffMF1x) !=
1035  varcoeffs.end());
1036 
1037  Array<OneD,NekDouble> work, varcoeff_work;
1039  Array<OneD, ExpansionSharedPtr> EdgeExp(nedges);
1040  Array<OneD, NekDouble> lam(nbndry);
1041 
1044  StdRegions::Orientation edgedir;
1045 
1046  // declare matrix space
1047  returnval = MemoryManager<DNekMat>::AllocateSharedPtr(nbndry, nbndry);
1048  DNekMat &BndMat = *returnval;
1049 
1050  DNekScalMatSharedPtr LamToQ[3];
1051 
1052  // Matrix to map Lambda to U
1053  MatrixKey LamToUkey(StdRegions::eHybridDGLamToU, DetShapeType(), *this, mkey.GetConstFactors(), mkey.GetVarCoeffs());
1054  DNekScalMat &LamToU = *GetLocMatrix(LamToUkey);
1055 
1056  // Matrix to map Lambda to Q0
1057  MatrixKey LamToQ0key(StdRegions::eHybridDGLamToQ0, DetShapeType(), *this, mkey.GetConstFactors(), mkey.GetVarCoeffs());
1058  LamToQ[0] = GetLocMatrix(LamToQ0key);
1059 
1060  // Matrix to map Lambda to Q1
1061  MatrixKey LamToQ1key(StdRegions::eHybridDGLamToQ1, DetShapeType(), *this, mkey.GetConstFactors(), mkey.GetVarCoeffs());
1062  LamToQ[1] = GetLocMatrix(LamToQ1key);
1063 
1064  // Matrix to map Lambda to Q2 for 3D coordinates
1065  if (coordim == 3)
1066  {
1067  MatrixKey LamToQ2key(StdRegions::eHybridDGLamToQ2, DetShapeType(), *this, mkey.GetConstFactors(), mkey.GetVarCoeffs());
1068  LamToQ[2] = GetLocMatrix(LamToQ2key);
1069  }
1070 
1071  // Set up edge segment expansions from local geom info
1072  for(i = 0; i < nedges; ++i)
1073  {
1074  EdgeExp[i] = GetTraceExp(i);
1075  }
1076 
1077  // Set up matrix derived from <mu, Q_lam.n - \tau (U_lam - Lam) >
1078  for(i = 0; i < nbndry; ++i)
1079  {
1080  cnt = 0;
1081 
1082  Vmath::Zero(nbndry,lam,1);
1083  lam[i] = 1.0;
1084  SetTraceToGeomOrientation(EdgeExp,lam);
1085 
1086  for(e = 0; e < nedges; ++e)
1087  {
1088  order_e = EdgeExp[e]->GetNcoeffs();
1089  nquad_e = EdgeExp[e]->GetNumPoints(0);
1090 
1091  normals = GetTraceNormal(e);
1092  edgedir = GetTraceOrient(e);
1093 
1094  work = Array<OneD,NekDouble>(nquad_e);
1095  varcoeff_work = Array<OneD, NekDouble>(nquad_e);
1096 
1097  GetTraceToElementMap(e,emap,sign,edgedir);
1098 
1102 
1103  // Q0 * n0 (BQ_0 terms)
1104  Array<OneD, NekDouble> edgeCoeffs(order_e);
1105  Array<OneD, NekDouble> edgePhys (nquad_e);
1106  for(j = 0; j < order_e; ++j)
1107  {
1108  edgeCoeffs[j] = sign[j]*(*LamToQ[0])(emap[j],i);
1109  }
1110 
1111  EdgeExp[e]->BwdTrans(edgeCoeffs, edgePhys);
1112 // @TODO Var coeffs
1113  // Multiply by variable coefficient
1114 // if ((x = varcoeffs.find(VarCoeff[0])) != varcoeffs.end())
1115 // {
1116 // GetPhysEdgeVarCoeffsFromElement(e,EdgeExp[e],x->second,varcoeff_work);
1117 // Vmath::Vmul(nquad_e,varcoeff_work,1,EdgeExp[e]->GetPhys(),1,EdgeExp[e]->UpdatePhys(),1);
1118 // }
1119  if (mmf)
1120  {
1121  Array<OneD, NekDouble> ncdotMF =
1122  v_GetnEdgecdotMF(0, e, EdgeExp[e],
1123  normals, varcoeffs);
1124  Vmath::Vmul(nquad_e, ncdotMF, 1,
1125  edgePhys, 1,
1126  work, 1);
1127  }
1128  else
1129  {
1130  Vmath::Vmul(nquad_e, normals[0], 1,
1131  edgePhys, 1,
1132  work, 1);
1133  }
1134 
1135  // Q1 * n1 (BQ_1 terms)
1136  for(j = 0; j < order_e; ++j)
1137  {
1138  edgeCoeffs[j] = sign[j]*(*LamToQ[1])(emap[j],i);
1139  }
1140 
1141  EdgeExp[e]->BwdTrans(edgeCoeffs, edgePhys);
1142 
1143 // @TODO var coeffs
1144  // Multiply by variable coefficients
1145 // if ((x = varcoeffs.find(VarCoeff[1])) != varcoeffs.end())
1146 // {
1147 // GetPhysEdgeVarCoeffsFromElement(e,EdgeExp[e],x->second,varcoeff_work);
1148 // Vmath::Vmul(nquad_e,varcoeff_work,1,EdgeExp[e]->GetPhys(),1,EdgeExp[e]->UpdatePhys(),1);
1149 // }
1150 
1151  if (mmf)
1152  {
1153  Array<OneD, NekDouble> ncdotMF =
1154  v_GetnEdgecdotMF(1, e, EdgeExp[e],
1155  normals, varcoeffs);
1156  Vmath::Vvtvp(nquad_e, ncdotMF, 1,
1157  edgePhys, 1,
1158  work, 1,
1159  work, 1);
1160  }
1161  else
1162  {
1163  Vmath::Vvtvp(nquad_e, normals[1], 1,
1164  edgePhys, 1,
1165  work, 1,
1166  work, 1);
1167  }
1168 
1169  // Q2 * n2 (BQ_2 terms)
1170  if (coordim == 3)
1171  {
1172  for(j = 0; j < order_e; ++j)
1173  {
1174  edgeCoeffs[j] = sign[j]*(*LamToQ[2])(emap[j],i);
1175  }
1176 
1177  EdgeExp[e]->BwdTrans(edgeCoeffs, edgePhys);
1178 // @TODO var coeffs
1179  // Multiply by variable coefficients
1180 // if ((x = varcoeffs.find(VarCoeff[2])) != varcoeffs.end())
1181 // {
1182 // GetPhysEdgeVarCoeffsFromElement(e,EdgeExp[e],x->second,varcoeff_work);
1183 // Vmath::Vmul(nquad_e,varcoeff_work,1,EdgeExp[e]->GetPhys(),1,EdgeExp[e]->UpdatePhys(),1);
1184 // }
1185 
1186  Vmath::Vvtvp(nquad_e, normals[2], 1, edgePhys, 1,
1187  work, 1, work, 1);
1188  }
1189 
1190  // - tau (ulam - lam)
1191  // Corresponds to the G and BU terms.
1192  for(j = 0; j < order_e; ++j)
1193  {
1194  edgeCoeffs[j] = sign[j]*LamToU(emap[j],i) - lam[cnt+j];
1195  }
1196 
1197  EdgeExp[e]->BwdTrans(edgeCoeffs, edgePhys);
1198 
1199  // Multiply by variable coefficients
1200  if ((x = varcoeffs.find(VarCoeff[0])) != varcoeffs.end())
1201  {
1202  GetPhysEdgeVarCoeffsFromElement(e,EdgeExp[e],x->second,varcoeff_work);
1203  Vmath::Vmul(nquad_e,varcoeff_work,1,edgePhys,1,edgePhys,1);
1204  }
1205 
1206  Vmath::Svtvp(nquad_e,-tau,edgePhys,1,
1207  work,1,work,1);
1208  /// TODO: Add variable coeffs
1209  EdgeExp[e]->IProductWRTBase(work, edgeCoeffs);
1210 
1211  EdgeExp[e]->SetCoeffsToOrientation(edgedir,edgeCoeffs,edgeCoeffs);
1212 
1213  for(j = 0; j < order_e; ++j)
1214  {
1215  BndMat(cnt+j,i) = edgeCoeffs[j];
1216  }
1217 
1218  cnt += order_e;
1219  }
1220  }
1221  }
1222  break;
1223  //HDG postprocessing
1225  {
1226  MatrixKey lapkey(StdRegions::eLaplacian, DetShapeType(), *this, mkey.GetConstFactors(), mkey.GetVarCoeffs());
1227  DNekScalMat &LapMat = *GetLocMatrix(lapkey);
1228 
1229  returnval = MemoryManager<DNekMat>::AllocateSharedPtr(LapMat.GetRows(),LapMat.GetColumns());
1230  DNekMatSharedPtr lmat = returnval;
1231 
1232  (*lmat) = LapMat;
1233 
1234  // replace first column with inner product wrt 1
1235  int nq = GetTotPoints();
1236  Array<OneD, NekDouble> tmp(nq);
1238  Vmath::Fill(nq,1.0,tmp,1);
1239  IProductWRTBase(tmp, outarray);
1240 
1241  Vmath::Vcopy(m_ncoeffs,&outarray[0],1,
1242  &(lmat->GetPtr())[0],1);
1243 
1244  lmat->Invert();
1245  }
1246  break;
1247  default:
1248  ASSERTL0(false,"This matrix type cannot be generated from this class");
1249  break;
1250  }
1251 
1252  return returnval;
1253  }
1254 
1255  //Evaluate Coefficients of weak deriviative in the direction dir
1256  //given the input coefficicents incoeffs and the imposed
1257  //boundary values in EdgeExp (which will have its phys space updated);
1259  int dir,
1260  const Array<OneD, const NekDouble> &incoeffs,
1262  Array<OneD, Array<OneD, NekDouble> > &edgeCoeffs,
1263  Array<OneD, NekDouble> &out_d)
1264  {
1268 
1269  int ncoeffs = GetNcoeffs();
1270 
1272  DNekScalMat &Dmat = *GetLocMatrix(DerivType[dir]);
1273 
1274  Array<OneD, NekDouble> coeffs = incoeffs;
1275  DNekVec Coeffs (ncoeffs,coeffs, eWrapper);
1276 
1277  Coeffs = Transpose(Dmat)*Coeffs;
1278  Vmath::Neg(ncoeffs, coeffs,1);
1279 
1280  // Add the boundary integral including the relevant part of
1281  // the normal
1282  AddNormTraceInt(dir, EdgeExp, edgeCoeffs, coeffs);
1283 
1284  DNekVec Out_d (ncoeffs,out_d,eWrapper);
1285 
1286  Out_d = InvMass*Coeffs;
1287  }
1288 
1290  {
1294  };
1295 
1297  const Array<OneD, const NekDouble > &primCoeffs,
1298  DNekMatSharedPtr &inoutmat)
1299  {
1301  "Not set up for non boundary-interior expansions");
1302  ASSERTL1(inoutmat->GetRows() == inoutmat->GetColumns(),
1303  "Assuming that input matrix was square");
1304  int i,j;
1305  int id1,id2;
1306  ExpansionSharedPtr edgeExp = m_traceExp[edge].lock();
1307  int order_e = edgeExp->GetNcoeffs();
1308 
1311 
1312  StdRegions::VarCoeffMap varcoeffs;
1313  varcoeffs[StdRegions::eVarCoeffMass] = primCoeffs;
1314 
1316  DNekScalMat &edgemat = *edgeExp->GetLocMatrix(mkey);
1317 
1318  // Now need to identify a map which takes the local edge
1319  // mass matrix to the matrix stored in inoutmat;
1320  // This can currently be deduced from the size of the matrix
1321 
1322  // - if inoutmat.m_rows() == v_NCoeffs() it is a full
1323  // matrix system
1324 
1325  // - if inoutmat.m_rows() == v_NumBndCoeffs() it is a
1326  // boundary CG system
1327 
1328  // - if inoutmat.m_rows() == v_NumDGBndCoeffs() it is a
1329  // trace DG system
1330  int rows = inoutmat->GetRows();
1331 
1332  if (rows == GetNcoeffs())
1333  {
1334  GetTraceToElementMap(edge,map,sign,v_GetTraceOrient(edge));
1335  }
1336  else if(rows == NumBndryCoeffs())
1337  {
1338  int nbndry = NumBndryCoeffs();
1339  Array<OneD,unsigned int> bmap(nbndry);
1340 
1341  GetTraceToElementMap(edge,map,sign,v_GetTraceOrient(edge));
1342 
1343  GetBoundaryMap(bmap);
1344 
1345  for(i = 0; i < order_e; ++i)
1346  {
1347  for(j = 0; j < nbndry; ++j)
1348  {
1349  if(map[i] == bmap[j])
1350  {
1351  map[i] = j;
1352  break;
1353  }
1354  }
1355  ASSERTL1(j != nbndry,"Did not find number in map");
1356  }
1357  }
1358  else if (rows == NumDGBndryCoeffs())
1359  {
1360  // possibly this should be a separate method
1361  int cnt = 0;
1362  map = Array<OneD, unsigned int> (order_e);
1363  sign = Array<OneD, int> (order_e,1);
1364 
1365  for(i = 0; i < edge; ++i)
1366  {
1367  cnt += GetTraceNcoeffs(i);
1368  }
1369 
1370  for(i = 0; i < order_e; ++i)
1371  {
1372  map[i] = cnt++;
1373  }
1374  // check for mapping reversal
1376  {
1377  switch(edgeExp->GetBasis(0)->GetBasisType())
1378  {
1380  reverse( map.get() , map.get()+order_e);
1381  break;
1383  reverse( map.get() , map.get()+order_e);
1384  break;
1386  {
1387  swap(map[0],map[1]);
1388  for(i = 3; i < order_e; i+=2)
1389  {
1390  sign[i] = -1;
1391  }
1392  }
1393  break;
1394  default:
1395  ASSERTL0(false,"Edge boundary type not valid for this method");
1396  }
1397  }
1398  }
1399  else
1400  {
1401  ASSERTL0(false,"Could not identify matrix type from dimension");
1402  }
1403 
1404  for(i = 0; i < order_e; ++i)
1405  {
1406  id1 = map[i];
1407  for(j = 0; j < order_e; ++j)
1408  {
1409  id2 = map[j];
1410  (*inoutmat)(id1,id2) += edgemat(i,j)*sign[i]*sign[j];
1411  }
1412  }
1413  }
1414 
1415  /**
1416  * Given an edge and vector of element coefficients:
1417  * - maps those elemental coefficients corresponding to the edge into
1418  * an edge-vector.
1419  * - resets the element coefficients
1420  * - multiplies the edge vector by the edge mass matrix
1421  * - maps the edge coefficients back onto the elemental coefficients
1422  */
1424  const Array<OneD,
1425  const NekDouble> &primCoeffs,
1426  const Array<OneD, NekDouble> &incoeffs,
1427  Array<OneD, NekDouble> &coeffs)
1428  {
1430  "Not set up for non boundary-interior expansions");
1431  int i;
1432  ExpansionSharedPtr edgeExp = m_traceExp[edgeid].lock();
1433  int order_e = edgeExp->GetNcoeffs();
1434 
1437 
1438  StdRegions::VarCoeffMap varcoeffs;
1439  varcoeffs[StdRegions::eVarCoeffMass] = primCoeffs;
1440 
1443  varcoeffs);
1444  DNekScalMat &edgemat = *edgeExp->GetLocMatrix(mkey);
1445 
1446  NekVector<NekDouble> vEdgeCoeffs (order_e);
1447 
1448  GetTraceToElementMap(edgeid,map,sign,v_GetTraceOrient(edgeid));
1449 
1450  for (i = 0; i < order_e; ++i)
1451  {
1452  vEdgeCoeffs[i] = incoeffs[map[i]]*sign[i];
1453  }
1454 
1455  vEdgeCoeffs = edgemat * vEdgeCoeffs;
1456 
1457  for (i = 0; i < order_e; ++i)
1458  {
1459  coeffs[map[i]] += vEdgeCoeffs[i]*sign[i];
1460  }
1461  }
1462 
1464  const DNekScalMatSharedPtr &r_bnd)
1465  {
1466  MatrixStorage storage = eFULL;
1467  DNekMatSharedPtr m_vertexmatrix;
1468 
1469  int nVerts, vid1, vid2, vMap1, vMap2;
1470  NekDouble VertexValue;
1471 
1472  nVerts = GetNverts();
1473 
1474  m_vertexmatrix =
1476  nVerts, nVerts, 0.0, storage);
1477  DNekMat &VertexMat = (*m_vertexmatrix);
1478 
1479  for (vid1 = 0; vid1 < nVerts; ++vid1)
1480  {
1481  vMap1 = GetVertexMap(vid1);
1482 
1483  for (vid2 = 0; vid2 < nVerts; ++vid2)
1484  {
1485  vMap2 = GetVertexMap(vid2);
1486  VertexValue = (*r_bnd)(vMap1, vMap2);
1487  VertexMat.SetValue(vid1, vid2, VertexValue);
1488  }
1489  }
1490 
1491  return m_vertexmatrix;
1492  }
1493 
1495  int eid)
1496  {
1497  int n, j;
1498  int nEdgeCoeffs;
1499  int nBndCoeffs = NumBndryCoeffs();
1500 
1501  Array<OneD, unsigned int> bmap(nBndCoeffs);
1502  GetBoundaryMap(bmap);
1503 
1504  // Map from full system to statically condensed system (i.e reverse
1505  // GetBoundaryMap)
1506  map<int, int> invmap;
1507  for (j = 0; j < nBndCoeffs; ++j)
1508  {
1509  invmap[bmap[j]] = j;
1510  }
1511 
1512  // Number of interior edge coefficients
1513  nEdgeCoeffs = GetTraceNcoeffs(eid) - 2;
1514 
1516 
1517  Array<OneD, unsigned int> edgemaparray(nEdgeCoeffs);
1518  Array<OneD, unsigned int> maparray (nEdgeCoeffs);
1519  Array<OneD, int> signarray (nEdgeCoeffs, 1);
1520  StdRegions::Orientation eOrient = geom->GetEorient(eid);
1521 
1522  // maparray is the location of the edge within the matrix
1523  GetTraceInteriorToElementMap(eid, maparray, signarray, eOrient);
1524 
1525  for (n = 0; n < nEdgeCoeffs; ++n)
1526  {
1527  edgemaparray[n] = invmap[maparray[n]];
1528  }
1529 
1530  return edgemaparray;
1531  }
1532 
1533  void Expansion2D::v_SetUpPhysNormals(const int edge)
1534  {
1535  v_ComputeTraceNormal(edge);
1536  }
1537 
1539  const int edge) const
1540  {
1541  std::map<int, NormalVector>::const_iterator x;
1542  x = m_edgeNormals.find(edge);
1543  ASSERTL1 (x != m_edgeNormals.end(),
1544  "Edge normal not computed.");
1545  return x->second;
1546  }
1547 
1549  (const StdRegions::Orientation orient,
1550  Array<OneD, int> &idmap,
1551  const int nq0, const int nq1)
1552  {
1553  boost::ignore_unused(nq1);
1554 
1555  if (idmap.size() != nq0)
1556  {
1557  idmap = Array<OneD, int>(nq0);
1558  }
1559  switch (orient)
1560  {
1561  case StdRegions::eForwards:
1562  // Fwd
1563  for (int i = 0; i < nq0; ++i)
1564  {
1565  idmap[i] = i;
1566  }
1567  break;
1569  {
1570  // Bwd
1571  for (int i = 0; i < nq0; ++i)
1572  {
1573  idmap[i] = nq0-1-i;
1574  }
1575  }
1576  break;
1577  default:
1578  ASSERTL0(false, "Unknown orientation");
1579  break;
1580  }
1581  }
1582 
1584  const int dir,
1585  const int shapedim,
1586  const StdRegions::VarCoeffMap &varcoeffs)
1587  {
1588  return Expansion::v_GetMF(dir,shapedim,varcoeffs);
1589  }
1590 
1592  const int dir,
1593  const StdRegions::VarCoeffMap &varcoeffs)
1594  {
1595  return Expansion::v_GetMFDiv(dir,varcoeffs);
1596  }
1597 
1599  const int dir,
1600  const StdRegions::VarCoeffMap &varcoeffs)
1601  {
1602  return Expansion::v_GetMFMag(dir,varcoeffs);
1603  }
1604 
1605  // Compute edgenormal \cdot vector
1607  const int dir,
1608  const int edge,
1609  ExpansionSharedPtr &EdgeExp_e,
1610  const Array<OneD, const Array<OneD, NekDouble> > &normals,
1611  const StdRegions::VarCoeffMap &varcoeffs)
1612  {
1613  int nquad_e = EdgeExp_e->GetNumPoints(0);
1614  int coordim = GetCoordim();
1615  int nquad0 = m_base[0]->GetNumPoints();
1616  int nquad1 = m_base[1]->GetNumPoints();
1617  int nqtot = nquad0*nquad1;
1618 
1619  StdRegions::VarCoeffType MMFCoeffs[15] =
1620  {
1636  };
1637 
1638  StdRegions::VarCoeffMap::const_iterator MFdir;
1639 
1640  Array<OneD, NekDouble> ncdotMF(nqtot,0.0);
1641  Array<OneD, NekDouble> tmp(nqtot);
1642  Array<OneD, NekDouble> tmp_e(nquad_e);
1643  for (int k=0; k<coordim; k++)
1644  {
1645  MFdir = varcoeffs.find(MMFCoeffs[dir*5+k]);
1646  tmp = MFdir->second;
1647 
1648  GetPhysEdgeVarCoeffsFromElement(edge, EdgeExp_e, tmp, tmp_e);
1649 
1650  Vmath::Vvtvp(nquad_e,
1651  &tmp_e[0], 1,
1652  &normals[k][0], 1,
1653  &ncdotMF[0], 1,
1654  &ncdotMF[0], 1);
1655  }
1656  return ncdotMF;
1657  }
1658 
1660  const Array<OneD, Array<OneD, NekDouble> > &vec)
1661  {
1663  &normals = GetLeftAdjacentElementExp()->
1665 
1666  int nq = GetTotPoints();
1667  Array<OneD, NekDouble > Fn(nq);
1668  Vmath::Vmul (nq, &vec[0][0], 1, &normals[0][0], 1, &Fn[0], 1);
1669  Vmath::Vvtvp(nq, &vec[1][0], 1, &normals[1][0], 1, &Fn[0], 1, &Fn[0], 1);
1670  Vmath::Vvtvp(nq, &vec[2][0], 1, &normals[2][0], 1, &Fn[0], 1, &Fn[0], 1);
1671 
1672  return StdExpansion::Integral(Fn);
1673  }
1674  }
1675 }
#define ASSERTL0(condition, msg)
Definition: ErrorUtil.hpp:216
#define ASSERTL1(condition, msg)
Assert Level 1 – Debugging which is used whether in FULLDEBUG or DEBUG compilation mode....
Definition: ErrorUtil.hpp:250
#define sign(a, b)
return the sign(b)*a
Definition: Polylib.cpp:15
Describes the specification for a Basis.
Definition: Basis.h:50
virtual 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)
virtual void v_AddRobinTraceContribution(const int traceid, const Array< OneD, const NekDouble > &primCoeffs, const Array< OneD, NekDouble > &incoeffs, Array< OneD, NekDouble > &coeffs)
std::vector< bool > m_requireNeg
Definition: Expansion2D.h:120
virtual Array< OneD, NekDouble > v_GetMFDiv(const int dir, const StdRegions::VarCoeffMap &varcoeffs)
void SetTraceToGeomOrientation(Array< OneD, ExpansionSharedPtr > &EdgeExp, Array< OneD, NekDouble > &inout)
virtual const NormalVector & v_GetTraceNormal(const int edge) const
void v_ReOrientTracePhysMap(const StdRegions::Orientation orient, Array< OneD, int > &idmap, const int nq0, const int nq1)
virtual 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)
Definition: Expansion2D.cpp:56
virtual Array< OneD, NekDouble > v_GetMFMag(const int dir, const StdRegions::VarCoeffMap &varcoeffs)
Array< OneD, unsigned int > GetTraceInverseBoundaryMap(int eid)
virtual void v_SetUpPhysNormals(const int edge)
virtual void v_AddRobinMassMatrix(const int edgeid, const Array< OneD, const NekDouble > &primCoeffs, DNekMatSharedPtr &inoutmat)
void AddNormTraceInt(const int dir, Array< OneD, ExpansionSharedPtr > &EdgeExp, Array< OneD, Array< OneD, NekDouble > > &edgeCoeffs, Array< OneD, NekDouble > &outarray)
virtual DNekMatSharedPtr v_GenMatrix(const StdRegions::StdMatrixKey &mkey)
virtual Array< OneD, NekDouble > v_GetMF(const int dir, const int shapedim, const StdRegions::VarCoeffMap &varcoeffs)
SpatialDomains::Geometry2DSharedPtr GetGeom2D() const
Definition: Expansion2D.h:204
void AddHDGHelmholtzEdgeTerms(const NekDouble tau, const int edge, Array< OneD, ExpansionSharedPtr > &EdgeExp, Array< OneD, NekDouble > &edgePhys, const StdRegions::VarCoeffMap &dirForcing, Array< OneD, NekDouble > &outarray)
Array< OneD, NekDouble > v_GetnEdgecdotMF(const int dir, const int edge, ExpansionSharedPtr &EdgeExp_e, const Array< OneD, const Array< OneD, NekDouble > > &normals, const StdRegions::VarCoeffMap &varcoeffs)
virtual NekDouble v_VectorFlux(const Array< OneD, Array< OneD, NekDouble > > &vec)
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)
virtual DNekMatSharedPtr v_BuildVertexMatrix(const DNekScalMatSharedPtr &r_bnd)
std::map< int, NormalVector > m_edgeNormals
Definition: Expansion2D.h:121
void AddHDGHelmholtzTraceTerms(const NekDouble tau, const Array< OneD, const NekDouble > &inarray, Array< OneD, ExpansionSharedPtr > &EdgeExp, const StdRegions::VarCoeffMap &dirForcing, Array< OneD, NekDouble > &outarray)
SpatialDomains::GeometrySharedPtr GetGeom() const
Definition: Expansion.cpp:172
SpatialDomains::GeometrySharedPtr m_geom
Definition: Expansion.h:272
std::vector< ExpansionWeakPtr > m_traceExp
Definition: Expansion.h:271
Array< OneD, NekDouble > v_GetMF(const int dir, const int shapedim, const StdRegions::VarCoeffMap &varcoeffs)
Definition: Expansion.cpp:434
ExpansionSharedPtr GetLeftAdjacentElementExp() const
Definition: Expansion.h:438
const NormalVector & GetTraceNormal(const int id) const
Definition: Expansion.h:222
virtual void v_ComputeTraceNormal(const int id)
Definition: Expansion.cpp:702
int GetLeftAdjacentElementTrace() const
Definition: Expansion.h:454
Array< OneD, NekDouble > v_GetMFMag(const int dir, const StdRegions::VarCoeffMap &varcoeffs)
Definition: Expansion.cpp:531
Array< OneD, NekDouble > v_GetMFDiv(const int dir, const StdRegions::VarCoeffMap &varcoeffs)
Definition: Expansion.cpp:498
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)
Definition: Expansion.cpp:120
virtual StdRegions::Orientation v_GetTraceOrient(int trace)
Definition: Expansion.cpp:642
ExpansionSharedPtr GetTraceExp(const int traceid)
Definition: Expansion.h:417
StdRegions::Orientation GetTraceOrient(int trace)
Definition: Expansion.h:164
IndexMapValuesSharedPtr GetIndexMap(const IndexMapKey &ikey)
Definition: Expansion.h:138
DNekScalMatSharedPtr GetLocMatrix(const LocalRegions::MatrixKey &mkey)
Definition: Expansion.cpp:90
static std::shared_ptr< DataType > AllocateSharedPtr(const Args &...args)
Allocate a shared pointer from the memory pool.
void GetBoundaryMap(Array< OneD, unsigned int > &outarray)
Definition: StdExpansion.h:687
int GetNcoeffs(void) const
This function returns the total number of coefficients used in the expansion.
Definition: StdExpansion.h:124
int GetTotPoints() const
This function returns the total number of quadrature points used in the element.
Definition: StdExpansion.h:134
int GetVertexMap(const int localVertexId, bool useCoeffPacking=false)
Definition: StdExpansion.h:697
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...
Definition: StdExpansion.h:537
int GetNtraces() const
Returns the number of trace elements connected to this element.
Definition: StdExpansion.h:360
int GetNverts() const
This function returns the number of vertices of the expansion domain.
Definition: StdExpansion.h:249
void GetTraceToElementMap(const int tid, Array< OneD, unsigned int > &maparray, Array< OneD, int > &signarray, Orientation traceOrient=eForwards, int P=-1, int Q=-1)
Definition: StdExpansion.h:703
LibUtilities::ShapeType DetShapeType() const
This function returns the shape of the expansion domain.
Definition: StdExpansion.h:376
void GetTraceInteriorToElementMap(const int tid, Array< OneD, unsigned int > &maparray, Array< OneD, int > &signarray, const Orientation traceOrient=eForwards)
Definition: StdExpansion.h:714
int GetTraceNcoeffs(const int i) const
This function returns the number of expansion coefficients belonging to the i-th trace.
Definition: StdExpansion.h:265
void FwdTrans(const Array< OneD, const NekDouble > &inarray, Array< OneD, NekDouble > &outarray)
This function performs the Forward transformation from physical space to coefficient space.
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.
Definition: StdExpansion.h:171
Array< OneD, LibUtilities::BasisSharedPtr > m_base
const ConstFactorMap & GetConstFactors() const
Definition: StdMatrixKey.h:135
const VarCoeffMap & GetVarCoeffs() const
Definition: StdMatrixKey.h:161
MatrixType GetMatrixType() const
Definition: StdMatrixKey.h:81
const Array< OneD, const NekDouble > & GetVarCoeff(const StdRegions::VarCoeffType &coeff) const
Definition: StdMatrixKey.h:145
bool HasVarCoeff(const StdRegions::VarCoeffType &coeff) const
Definition: StdMatrixKey.h:166
NekDouble GetConstFactor(const ConstFactorType &factor) const
Definition: StdMatrixKey.h:121
const VarCoeffMap GetVarCoeffAsMap(const VarCoeffType &coeff) const
Definition: StdMatrixKey.h:154
void InterpCoeff1D(const BasisKey &fbasis0, const Array< OneD, const NekDouble > &from, const BasisKey &tbasis0, Array< OneD, NekDouble > &to)
Definition: InterpCoeff.cpp:46
@ eGauss_Lagrange
Lagrange Polynomials using the Gauss points .
Definition: BasisType.h:55
@ eGLL_Lagrange
Lagrange for SEM basis .
Definition: BasisType.h:54
@ eModified_A
Principle Modified Functions .
Definition: BasisType.h:48
std::shared_ptr< Expansion > ExpansionSharedPtr
Definition: Expansion.h:68
std::shared_ptr< IndexMapValues > IndexMapValuesSharedPtr
Definition: IndexMapKey.h:126
std::shared_ptr< Expansion1D > Expansion1DSharedPtr
Definition: Expansion1D.h:51
std::shared_ptr< Geometry2D > Geometry2DSharedPtr
Definition: Geometry.h:65
std::map< StdRegions::VarCoeffType, Array< OneD, NekDouble > > VarCoeffMap
Definition: StdRegions.hpp:272
std::map< ConstFactorType, NekDouble > ConstFactorMap
Definition: StdRegions.hpp:314
static ConstFactorMap NullConstFactorMap
Definition: StdRegions.hpp:315
The above copyright notice and this permission notice shall be included.
Definition: CoupledSolver.h:1
std::shared_ptr< DNekScalMat > DNekScalMatSharedPtr
NekMatrix< InnerMatrixType, BlockMatrixTag > Transpose(NekMatrix< InnerMatrixType, BlockMatrixTag > &rhs)
std::shared_ptr< DNekMat > DNekMatSharedPtr
Definition: NekTypeDefs.hpp:69
double NekDouble
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.cpp:192
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.cpp:565
void Neg(int n, T *x, const int incx)
Negate x = -x.
Definition: Vmath.cpp:461
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.cpp:513
void Zero(int n, T *x, const int incx)
Zero vector.
Definition: Vmath.cpp:436
void Fill(int n, const T alpha, T *x, const int incx)
Fill a vector with a constant value.
Definition: Vmath.cpp:45
void Vcopy(int n, const T *x, const int incx, T *y, const int incy)
Definition: Vmath.cpp:1199