Nektar++
Expansion3D.cpp
Go to the documentation of this file.
1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 // File: Expansion3D.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 Expansion3D routines
32 //
33 ///////////////////////////////////////////////////////////////////////////////
34 
35 #include <boost/core/ignore_unused.hpp>
36 
41 #include <LocalRegions/MatrixKey.h>
42 #include <LocalRegions/QuadExp.h>
43 #include <LocalRegions/TriExp.h>
45 
46 using namespace std;
47 
48 namespace Nektar
49 {
50 namespace LocalRegions
51 {
52 // evaluate additional terms in HDG face. Note that this assumes that
53 // edges are unpacked into local cartesian order.
54 void Expansion3D::AddHDGHelmholtzFaceTerms(
55  const NekDouble tau, const int face, Array<OneD, NekDouble> &facePhys,
56  const StdRegions::VarCoeffMap &varcoeffs, Array<OneD, NekDouble> &outarray)
57 {
58  ExpansionSharedPtr FaceExp = GetTraceExp(face);
59  int i, j, n;
60  int nquad_f = FaceExp->GetNumPoints(0) * FaceExp->GetNumPoints(1);
61  int order_f = FaceExp->GetNcoeffs();
62  int coordim = GetCoordim();
63  int ncoeffs = GetNcoeffs();
64  bool mmf = (varcoeffs.find(StdRegions::eVarCoeffMF1x) != varcoeffs.end());
65 
66  Array<OneD, NekDouble> inval(nquad_f);
67  Array<OneD, NekDouble> outcoeff(order_f);
68  Array<OneD, NekDouble> tmpcoeff(ncoeffs);
69 
71  GetTraceNormal(face);
72 
73  DNekScalMat &invMass = *GetLocMatrix(StdRegions::eInvMass);
74 
75  DNekVec Coeffs(ncoeffs, outarray, eWrapper);
76  DNekVec Tmpcoeff(ncoeffs, tmpcoeff, eWrapper);
77 
78  IndexMapKey ikey(eFaceToElement, DetShapeType(), GetBasisNumModes(0),
79  GetBasisNumModes(1), GetBasisNumModes(2), face,
80  GetTraceOrient(face));
81  IndexMapValuesSharedPtr map = GetIndexMap(ikey);
82 
86 
87  // @TODO Variable coefficients
88  /*
89  StdRegions::VarCoeffType VarCoeff[3] = {StdRegions::eVarCoeffD00,
90  StdRegions::eVarCoeffD11,
91  StdRegions::eVarCoeffD22};
92  Array<OneD, NekDouble> varcoeff_work(nquad_f);
93  StdRegions::VarCoeffMap::const_iterator x;
94  ///// @TODO: What direction to use here??
95  if ((x = varcoeffs.find(VarCoeff[0])) != varcoeffs.end())
96  {
97  GetPhysFaceVarCoeffsFromElement(face,FaceExp,x->second,varcoeff_work);
98  Vmath::Vmul(nquad_f,varcoeff_work,1,FaceExp->GetPhys(),1,FaceExp->UpdatePhys(),1);
99  }
100  */
101 
102  //================================================================
103  // Add F = \tau <phi_i,in_phys>
104  // Fill face and take inner product
105  FaceExp->IProductWRTBase(facePhys, outcoeff);
106 
107  for (i = 0; i < order_f; ++i)
108  {
109  outarray[(*map)[i].index] += (*map)[i].sign * tau * outcoeff[i];
110  }
111  //================================================================
112 
113  //===============================================================
114  // Add -\sum_i D_i^T M^{-1} G_i + E_i M^{-1} G_i =
115  // \sum_i D_i M^{-1} G_i term
116 
117  // Three independent direction
118  for (n = 0; n < coordim; ++n)
119  {
120  if (mmf)
121  {
123  Weight[StdRegions::eVarCoeffMass] = GetMFMag(n, varcoeffs);
124 
125  MatrixKey invMasskey(StdRegions::eInvMass, DetShapeType(), *this,
127 
128  invMass = *GetLocMatrix(invMasskey);
129 
130  Array<OneD, NekDouble> ncdotMF_f =
131  GetnFacecdotMF(n, face, FaceExp, normals, varcoeffs);
132 
133  Vmath::Vmul(nquad_f, ncdotMF_f, 1, facePhys, 1, inval, 1);
134  }
135  else
136  {
137  Vmath::Vmul(nquad_f, normals[n], 1, facePhys, 1, inval, 1);
138  }
139 
140  NekDouble scale = invMass.Scale();
141  const NekDouble *data = invMass.GetRawPtr();
142 
143  // @TODO Multiply by variable coefficients
144  // @TODO: Document this (probably not needed)
145  /*
146  StdRegions::VarCoeffMap::const_iterator x;
147  if ((x = varcoeffs.find(VarCoeff[n])) != varcoeffs.end())
148  {
149  GetPhysEdgeVarCoeffsFromElement(edge,FaceExp,x->second,varcoeff_work);
150  Vmath::Vmul(nquad_f,varcoeff_work,1,FaceExp->GetPhys(),1,FaceExp->UpdatePhys(),1);
151  }
152  */
153 
154  FaceExp->IProductWRTBase(inval, outcoeff);
155 
156  // M^{-1} G
157  for (i = 0; i < ncoeffs; ++i)
158  {
159  tmpcoeff[i] = 0;
160  for (j = 0; j < order_f; ++j)
161  {
162  tmpcoeff[i] += scale * data[i + (*map)[j].index * ncoeffs] *
163  (*map)[j].sign * outcoeff[j];
164  }
165  }
166 
167  if (mmf)
168  {
169  StdRegions::VarCoeffMap VarCoeffDirDeriv;
170  VarCoeffDirDeriv[StdRegions::eVarCoeffMF] =
171  GetMF(n, coordim, varcoeffs);
172  VarCoeffDirDeriv[StdRegions::eVarCoeffMFDiv] =
173  GetMFDiv(n, varcoeffs);
174 
175  MatrixKey Dmatkey(StdRegions::eWeakDirectionalDeriv, DetShapeType(),
177  VarCoeffDirDeriv);
178 
179  DNekScalMat &Dmat = *GetLocMatrix(Dmatkey);
180 
181  Coeffs = Coeffs + Dmat * Tmpcoeff;
182  }
183  else
184  {
185  DNekScalMat &Dmat = *GetLocMatrix(DerivType[n]);
186  Coeffs = Coeffs + Dmat * Tmpcoeff;
187  }
188 
189  /*
190  if(varcoeffs.find(VarCoeff[n]) != varcoeffs.end())
191  {
192  MatrixKey mkey(DerivType[n], DetExpansionType(), *this,
193  StdRegions::NullConstFactorMap, varcoeffs); DNekScalMat &Dmat =
194  *GetLocMatrix(mkey); Coeffs = Coeffs + Dmat*Tmpcoeff;
195  }
196 
197  else
198  {
199  DNekScalMat &Dmat = *GetLocMatrix(DerivType[n]);
200  Coeffs = Coeffs + Dmat*Tmpcoeff;
201  }
202  */
203  }
204 }
205 
206 void Expansion3D::GetPhysFaceVarCoeffsFromElement(
207  const int face, ExpansionSharedPtr &FaceExp,
208  const Array<OneD, const NekDouble> &varcoeff,
209  Array<OneD, NekDouble> &outarray)
210 {
211  Array<OneD, NekDouble> tmp(GetNcoeffs());
212  Array<OneD, NekDouble> facetmp(FaceExp->GetNcoeffs());
213 
214  // FwdTrans varcoeffs
215  FwdTrans(varcoeff, tmp);
216 
217  // Map to edge
220 
221  GetTraceToElementMap(face, emap, sign, GetTraceOrient(face));
222 
223  for (unsigned int i = 0; i < FaceExp->GetNcoeffs(); ++i)
224  {
225  facetmp[i] = tmp[emap[i]];
226  }
227 
228  // BwdTrans
229  FaceExp->BwdTrans(facetmp, outarray);
230 }
231 
232 /**
233  * Computes the C matrix entries due to the presence of the identity
234  * matrix in Eqn. 32.
235  */
236 void Expansion3D::AddNormTraceInt(const int dir,
239  Array<OneD, NekDouble> &outarray,
240  const StdRegions::VarCoeffMap &varcoeffs)
241 {
242  int i, f, cnt;
243  int order_f, nquad_f;
244  int nfaces = GetNtraces();
245 
246  cnt = 0;
247  for (f = 0; f < nfaces; ++f)
248  {
249  order_f = FaceExp[f]->GetNcoeffs();
250  nquad_f = FaceExp[f]->GetNumPoints(0) * FaceExp[f]->GetNumPoints(1);
251 
253  GetTraceNormal(f);
254  Array<OneD, NekDouble> faceCoeffs(order_f);
255  Array<OneD, NekDouble> facePhys(nquad_f);
256 
257  for (i = 0; i < order_f; ++i)
258  {
259  faceCoeffs[i] = inarray[i + cnt];
260  }
261  cnt += order_f;
262 
263  FaceExp[f]->BwdTrans(faceCoeffs, facePhys);
264 
265  // Multiply by variable coefficient
266  /// @TODO: Document this
267  // StdRegions::VarCoeffType VarCoeff[3] =
268  // {StdRegions::eVarCoeffD00,
269  // StdRegions::eVarCoeffD11,
270  // StdRegions::eVarCoeffD22};
271  // StdRegions::VarCoeffMap::const_iterator x;
272  // Array<OneD, NekDouble> varcoeff_work(nquad_e);
273 
274  // if ((x = varcoeffs.find(VarCoeff[dir])) !=
275  // varcoeffs.end())
276  // {
277  // GetPhysEdgeVarCoeffsFromElement(e,EdgeExp[e],x->second,varcoeff_work);
278  // Vmath::Vmul(nquad_e,varcoeff_work,1,EdgeExp[e]->GetPhys(),1,EdgeExp[e]->UpdatePhys(),1);
279  // }
280  StdRegions::VarCoeffMap::const_iterator x;
281  if ((x = varcoeffs.find(StdRegions::eVarCoeffMF1x)) != varcoeffs.end())
282  {
283  Array<OneD, NekDouble> ncdotMF_f =
284  GetnFacecdotMF(dir, f, FaceExp[f], normals, varcoeffs);
285 
286  Vmath::Vmul(nquad_f, ncdotMF_f, 1, facePhys, 1, facePhys, 1);
287  }
288  else
289  {
290  Vmath::Vmul(nquad_f, normals[dir], 1, facePhys, 1, facePhys, 1);
291  }
292 
293  AddFaceBoundaryInt(f, FaceExp[f], facePhys, outarray, varcoeffs);
294  }
295 }
296 
297 // shorter version of the above (coefficients are already set for faces)
298 void Expansion3D::AddNormTraceInt(
299  const int dir, Array<OneD, ExpansionSharedPtr> &FaceExp,
300  Array<OneD, Array<OneD, NekDouble>> &faceCoeffs,
301  Array<OneD, NekDouble> &outarray)
302 {
303  int f;
304  int nquad_f;
305  int nfaces = GetNtraces();
306 
307  for (f = 0; f < nfaces; ++f)
308  {
309  nquad_f = FaceExp[f]->GetNumPoints(0) * FaceExp[f]->GetNumPoints(1);
310 
312  GetTraceNormal(f);
313  Array<OneD, NekDouble> facePhys(nquad_f);
314 
315  FaceExp[f]->BwdTrans(faceCoeffs[f], facePhys);
316 
317  Vmath::Vmul(nquad_f, normals[dir], 1, facePhys, 1, facePhys, 1);
318 
319  AddFaceBoundaryInt(f, FaceExp[f], facePhys, outarray);
320  }
321 }
322 
323 /**
324  * For a given face add the \tilde{F}_1j contributions
325  */
326 void Expansion3D::AddFaceBoundaryInt(const int face,
327  ExpansionSharedPtr &FaceExp,
328  Array<OneD, NekDouble> &facePhys,
329  Array<OneD, NekDouble> &outarray,
330  const StdRegions::VarCoeffMap &varcoeffs)
331 {
332  boost::ignore_unused(varcoeffs);
333 
334  int i;
335  int order_f = FaceExp->GetNcoeffs();
336  Array<OneD, NekDouble> coeff(order_f);
337 
338  IndexMapKey ikey(eFaceToElement, DetShapeType(), GetBasisNumModes(0),
339  GetBasisNumModes(1), GetBasisNumModes(2), face,
340  GetTraceOrient(face));
341  IndexMapValuesSharedPtr map = GetIndexMap(ikey);
342 
343  // StdRegions::VarCoeffType VarCoeff[3] =
344  // {StdRegions::eVarCoeffD00,
345  // StdRegions::eVarCoeffD11,
346  // StdRegions::eVarCoeffD22};
347  // StdRegions::VarCoeffMap::const_iterator x;
348  // Array<OneD, NekDouble> varcoeff_work(nquad_e);
349  //
350  ///// @TODO Variable coeffs
351  // if ((x = varcoeffs.find(VarCoeff[0])) != varcoeffs.end())
352  // {
353  // GetPhysEdgeVarCoeffsFromElement(edge,EdgeExp,x->second,varcoeff_work);
354  // Vmath::Vmul(nquad_e,varcoeff_work,1,EdgeExp->GetPhys(),1,EdgeExp->UpdatePhys(),1);
355  // }
356 
357  FaceExp->IProductWRTBase(facePhys, coeff);
358 
359  // add data to out array
360  for (i = 0; i < order_f; ++i)
361  {
362  outarray[(*map)[i].index] += (*map)[i].sign * coeff[i];
363  }
364 }
365 
366 /**
367  * @brief Align face orientation with the geometry orientation.
368  */
369 void Expansion3D::SetFaceToGeomOrientation(const int face,
370  Array<OneD, NekDouble> &inout)
371 {
372  int j, k;
373  int nface = GetTraceNcoeffs(face);
374  Array<OneD, NekDouble> f_in(nface);
375  Vmath::Vcopy(nface, &inout[0], 1, &f_in[0], 1);
376 
377  // retreiving face to element map for standard face orientation and
378  // for actual face orientation
379  IndexMapKey ikey1(eFaceToElement, DetShapeType(), GetBasisNumModes(0),
380  GetBasisNumModes(1), GetBasisNumModes(2), face,
382  IndexMapValuesSharedPtr map1 = GetIndexMap(ikey1);
383  IndexMapKey ikey2(eFaceToElement, DetShapeType(), GetBasisNumModes(0),
384  GetBasisNumModes(1), GetBasisNumModes(2), face,
385  GetTraceOrient(face));
386  IndexMapValuesSharedPtr map2 = GetIndexMap(ikey2);
387 
388  ASSERTL1((*map1).size() == (*map2).size(),
389  "There is an error with the GetTraceToElementMap");
390 
391  for (j = 0; j < (*map1).size(); ++j)
392  {
393  // j = index in the standard orientation
394  for (k = 0; k < (*map2).size(); ++k)
395  {
396  // k = index in the actual orientation
397  if ((*map1)[j].index == (*map2)[k].index && k != j)
398  {
399  inout[k] = f_in[j];
400  // checking if sign is changing
401  if ((*map1)[j].sign != (*map2)[k].sign)
402  inout[k] *= -1.0;
403  break;
404  }
405  }
406  }
407 }
408 
409 /**
410  * @brief Align trace orientation with the geometry orientation.
411  */
412 void Expansion3D::SetTraceToGeomOrientation(Array<OneD, NekDouble> &inout)
413 {
414  int i, cnt = 0;
415  int nfaces = GetNtraces();
416 
418 
419  for (i = 0; i < nfaces; ++i)
420  {
421  SetFaceToGeomOrientation(i, f_tmp = inout + cnt);
422  cnt += GetTraceNcoeffs(i);
423  }
424 }
425 
426 DNekScalMatSharedPtr Expansion3D::CreateMatrix(const MatrixKey &mkey)
427 {
428  DNekScalMatSharedPtr returnval;
429  LibUtilities::PointsKeyVector ptsKeys = GetPointsKeys();
430 
431  ASSERTL2(m_metricinfo->GetGtype() != SpatialDomains::eNoGeomType,
432  "Geometric information is not set up");
433 
434  switch (mkey.GetMatrixType())
435  {
436  case StdRegions::eMass:
437  {
438  if (m_metricinfo->GetGtype() == SpatialDomains::eDeformed ||
439  mkey.GetNVarCoeff())
440  {
441  NekDouble one = 1.0;
442  DNekMatSharedPtr mat = GenMatrix(mkey);
443  returnval =
445  }
446  else
447  {
448  NekDouble jac = (m_metricinfo->GetJac(ptsKeys))[0];
449  DNekMatSharedPtr mat = GetStdMatrix(mkey);
450  returnval =
452  }
453  }
454  break;
456  {
457  if (m_metricinfo->GetGtype() == SpatialDomains::eDeformed)
458  {
459  NekDouble one = 1.0;
461  DetShapeType(), *this);
462  DNekMatSharedPtr mat = GenMatrix(masskey);
463  mat->Invert();
464  returnval =
466  }
467  else
468  {
469  NekDouble fac = 1.0 / (m_metricinfo->GetJac(ptsKeys))[0];
470  DNekMatSharedPtr mat = GetStdMatrix(mkey);
471  returnval =
473  }
474  }
475  break;
479  {
480  if (m_metricinfo->GetGtype() == SpatialDomains::eDeformed ||
481  mkey.GetNVarCoeff())
482  {
483  NekDouble one = 1.0;
484  DNekMatSharedPtr mat = GenMatrix(mkey);
485 
486  returnval =
488  }
489  else
490  {
491  NekDouble jac = (m_metricinfo->GetJac(ptsKeys))[0];
493  m_metricinfo->GetDerivFactors(ptsKeys);
494  int dir = 0;
496  dir = 0;
498  dir = 1;
500  dir = 2;
501 
503  mkey.GetShapeType(), *this);
505  mkey.GetShapeType(), *this);
507  mkey.GetShapeType(), *this);
508 
509  DNekMat &deriv0 = *GetStdMatrix(deriv0key);
510  DNekMat &deriv1 = *GetStdMatrix(deriv1key);
511  DNekMat &deriv2 = *GetStdMatrix(deriv2key);
512 
513  int rows = deriv0.GetRows();
514  int cols = deriv1.GetColumns();
515 
516  DNekMatSharedPtr WeakDeriv =
518  (*WeakDeriv) = df[3 * dir][0] * deriv0 +
519  df[3 * dir + 1][0] * deriv1 +
520  df[3 * dir + 2][0] * deriv2;
521 
523  jac, WeakDeriv);
524  }
525  }
526  break;
528  {
529  if (m_metricinfo->GetGtype() == SpatialDomains::eDeformed ||
530  (mkey.GetNVarCoeff() > 0) ||
532  {
533  NekDouble one = 1.0;
534  DNekMatSharedPtr mat = GenMatrix(mkey);
535 
536  returnval =
538  }
539  else
540  {
542  mkey.GetShapeType(), *this);
544  mkey.GetShapeType(), *this);
546  mkey.GetShapeType(), *this);
548  mkey.GetShapeType(), *this);
550  mkey.GetShapeType(), *this);
552  mkey.GetShapeType(), *this);
553 
554  DNekMat &lap00 = *GetStdMatrix(lap00key);
555  DNekMat &lap01 = *GetStdMatrix(lap01key);
556  DNekMat &lap02 = *GetStdMatrix(lap02key);
557  DNekMat &lap11 = *GetStdMatrix(lap11key);
558  DNekMat &lap12 = *GetStdMatrix(lap12key);
559  DNekMat &lap22 = *GetStdMatrix(lap22key);
560 
561  NekDouble jac = (m_metricinfo->GetJac(ptsKeys))[0];
563  m_metricinfo->GetGmat(ptsKeys);
564 
565  int rows = lap00.GetRows();
566  int cols = lap00.GetColumns();
567 
568  DNekMatSharedPtr lap =
570 
571  (*lap) = gmat[0][0] * lap00 + gmat[4][0] * lap11 +
572  gmat[8][0] * lap22 +
573  gmat[3][0] * (lap01 + Transpose(lap01)) +
574  gmat[6][0] * (lap02 + Transpose(lap02)) +
575  gmat[7][0] * (lap12 + Transpose(lap12));
576 
577  returnval =
579  }
580  }
581  break;
583  {
585  MatrixKey masskey(StdRegions::eMass, mkey.GetShapeType(), *this);
586  DNekScalMat &MassMat = *GetLocMatrix(masskey);
587  MatrixKey lapkey(StdRegions::eLaplacian, mkey.GetShapeType(), *this,
588  mkey.GetConstFactors(), mkey.GetVarCoeffs());
589  DNekScalMat &LapMat = *GetLocMatrix(lapkey);
590 
591  int rows = LapMat.GetRows();
592  int cols = LapMat.GetColumns();
593 
594  DNekMatSharedPtr helm =
596 
597  NekDouble one = 1.0;
598  (*helm) = LapMat + factor * MassMat;
599 
600  returnval =
602  }
603  break;
605  {
606  MatrixKey helmkey(mkey, StdRegions::eHelmholtz);
607  DNekScalMat &HelmMat = *GetLocMatrix(helmkey);
608 
609  // Generate a local copy of traceMat
611  DNekMatSharedPtr NDTraceMat = Expansion3D::v_GenMatrix(key);
612 
614  "Need to specify eFactorGJP to construct "
615  "a HelmholtzGJP matrix");
616 
618 
619  factor /= HelmMat.Scale();
620 
621  int ntot = HelmMat.GetRows() * HelmMat.GetColumns();
622 
623  Vmath::Svtvp(ntot, factor, &NDTraceMat->GetPtr()[0], 1,
624  HelmMat.GetRawPtr(), 1, &NDTraceMat->GetPtr()[0], 1);
625 
627  HelmMat.Scale(), NDTraceMat);
628  }
629  break;
631  {
632  if (m_metricinfo->GetGtype() == SpatialDomains::eDeformed)
633  {
634  NekDouble one = 1.0;
635  DNekMatSharedPtr mat = GenMatrix(mkey);
636  returnval =
638  }
639  else
640  {
641  NekDouble jac = (m_metricinfo->GetJac(ptsKeys))[0];
642  DNekMatSharedPtr mat = GetStdMatrix(mkey);
643  returnval =
645  }
646  }
647  break;
649  {
650  NekDouble one = 1.0;
651 
652  MatrixKey hkey(StdRegions::eHybridDGHelmholtz, DetShapeType(),
653  *this, mkey.GetConstFactors(), mkey.GetVarCoeffs());
654  DNekMatSharedPtr mat = GenMatrix(hkey);
655 
656  mat->Invert();
657  returnval = MemoryManager<DNekScalMat>::AllocateSharedPtr(one, mat);
658  }
659  break;
661  {
662  NekDouble one = 1.0;
664  *this, mkey.GetConstFactors(),
665  mkey.GetVarCoeffs());
666  DNekScalBlkMatSharedPtr helmStatCond =
667  GetLocStaticCondMatrix(helmkey);
668  DNekScalMatSharedPtr A = helmStatCond->GetBlock(0, 0);
669  DNekMatSharedPtr R = BuildVertexMatrix(A);
670 
672  }
673  break;
675  {
676  NekDouble one = 1.0;
677  MatrixKey masskey(StdRegions::eMass, mkey.GetShapeType(), *this);
678  DNekScalBlkMatSharedPtr massStatCond =
679  GetLocStaticCondMatrix(masskey);
680  DNekScalMatSharedPtr A = massStatCond->GetBlock(0, 0);
681  DNekMatSharedPtr R = BuildVertexMatrix(A);
682 
684  }
685  break;
687  {
688  NekDouble one = 1.0;
690  *this, mkey.GetConstFactors(),
691  mkey.GetVarCoeffs());
692  DNekScalBlkMatSharedPtr helmStatCond =
693  GetLocStaticCondMatrix(helmkey);
694  DNekScalMatSharedPtr A = helmStatCond->GetBlock(0, 0);
695 
697  DNekMatSharedPtr R =
698  BuildTransformationMatrix(A, mkey.GetMatrixType());
699 
701  }
702  break;
704  {
705  NekDouble one = 1.0;
706  MatrixKey masskey(StdRegions::eMass, mkey.GetShapeType(), *this);
707  DNekScalBlkMatSharedPtr StatCond = GetLocStaticCondMatrix(masskey);
708  DNekScalMatSharedPtr A = StatCond->GetBlock(0, 0);
709 
711  DNekMatSharedPtr R =
712  BuildTransformationMatrix(A, mkey.GetMatrixType());
713 
715  }
716  break;
717  default:
718  {
719  NekDouble one = 1.0;
720  DNekMatSharedPtr mat = GenMatrix(mkey);
721 
722  returnval = MemoryManager<DNekScalMat>::AllocateSharedPtr(one, mat);
723  }
724  break;
725  }
726 
727  return returnval;
728 }
729 
730 /**
731  * Computes matrices needed for the HDG formulation. References to
732  * equations relate to the following paper (with a suitable changes in
733  * formulation to adapt to 3D):
734  * R. M. Kirby, S. J. Sherwin, B. Cockburn, To CG or to HDG: A
735  * Comparative Study, J. Sci. Comp P1-30
736  * DOI 10.1007/s10915-011-9501-7
737  * NOTE: VARIABLE COEFFICIENTS CASE IS NOT IMPLEMENTED
738  */
739 DNekMatSharedPtr Expansion3D::v_GenMatrix(const StdRegions::StdMatrixKey &mkey)
740 {
741  // Variable coefficients are not implemented/////////
743  "Matrix construction is not implemented for variable "
744  "coefficients at the moment");
745  ////////////////////////////////////////////////////
746 
747  DNekMatSharedPtr returnval;
748 
749  switch (mkey.GetMatrixType())
750  {
751  // (Z^e)^{-1} (Eqn. 33, P22)
753  {
754  ASSERTL1(IsBoundaryInteriorExpansion(),
755  "HybridDGHelmholtz matrix not set up "
756  "for non boundary-interior expansions");
757 
758  int i, j, k;
759  NekDouble lambdaval =
762  int ncoeffs = GetNcoeffs();
763  int nfaces = GetNtraces();
764 
767  ExpansionSharedPtr FaceExp;
768  ExpansionSharedPtr FaceExp2;
769 
770  int order_f, coordim = GetCoordim();
771  DNekScalMat &invMass = *GetLocMatrix(StdRegions::eInvMass);
775 
776  returnval =
778  DNekMat &Mat = *returnval;
779  Vmath::Zero(ncoeffs * ncoeffs, Mat.GetPtr(), 1);
780 
781  // StdRegions::VarCoeffType Coeffs[3] = {StdRegions::eVarCoeffD00,
782  // StdRegions::eVarCoeffD11,
783  // StdRegions::eVarCoeffD22};
784  StdRegions::VarCoeffMap::const_iterator x;
785  const StdRegions::VarCoeffMap &varcoeffs = mkey.GetVarCoeffs();
786 
787  for (i = 0; i < coordim; ++i)
788  {
789  if ((x = varcoeffs.find(StdRegions::eVarCoeffMF1x)) !=
790  varcoeffs.end())
791  {
792  StdRegions::VarCoeffMap VarCoeffDirDeriv;
793  VarCoeffDirDeriv[StdRegions::eVarCoeffMF] =
794  GetMF(i, coordim, varcoeffs);
795  VarCoeffDirDeriv[StdRegions::eVarCoeffMFDiv] =
796  GetMFDiv(i, varcoeffs);
797 
799  DetShapeType(), *this,
801  VarCoeffDirDeriv);
802 
803  DNekScalMat &Dmat = *GetLocMatrix(Dmatkey);
804 
806  Weight[StdRegions::eVarCoeffMass] =
807  GetMFMag(i, mkey.GetVarCoeffs());
808 
809  MatrixKey invMasskey(StdRegions::eInvMass, DetShapeType(),
811  Weight);
812 
813  DNekScalMat &invMass = *GetLocMatrix(invMasskey);
814 
815  Mat = Mat + Dmat * invMass * Transpose(Dmat);
816  }
817  else
818  {
819  DNekScalMat &Dmat = *GetLocMatrix(DerivType[i]);
820  Mat = Mat + Dmat * invMass * Transpose(Dmat);
821  }
822 
823  /*
824  if(mkey.HasVarCoeff(Coeffs[i]))
825  {
826  MatrixKey DmatkeyL(DerivType[i], DetExpansionType(), *this,
827  StdRegions::NullConstFactorMap,
828  mkey.GetVarCoeffAsMap(Coeffs[i]));
829  MatrixKey DmatkeyR(DerivType[i], DetExpansionType(), *this);
830 
831  DNekScalMat &DmatL = *GetLocMatrix(DmatkeyL);
832  DNekScalMat &DmatR = *GetLocMatrix(DmatkeyR);
833  Mat = Mat + DmatL*invMass*Transpose(DmatR);
834  }
835  else
836  {
837  DNekScalMat &Dmat = *GetLocMatrix(DerivType[i]);
838  Mat = Mat + Dmat*invMass*Transpose(Dmat);
839  }
840  */
841  }
842 
843  // Add Mass Matrix Contribution for Helmholtz problem
844  DNekScalMat &Mass = *GetLocMatrix(StdRegions::eMass);
845  Mat = Mat + lambdaval * Mass;
846 
847  // Add tau*E_l using elemental mass matrices on each edge
848  for (i = 0; i < nfaces; ++i)
849  {
850  FaceExp = GetTraceExp(i);
851  order_f = FaceExp->GetNcoeffs();
852 
853  IndexMapKey ikey(eFaceToElement, DetShapeType(),
854  GetBasisNumModes(0), GetBasisNumModes(1),
855  GetBasisNumModes(2), i, GetTraceOrient(i));
856  IndexMapValuesSharedPtr map = GetIndexMap(ikey);
857 
858  // @TODO: Document
859  /*
860  StdRegions::VarCoeffMap edgeVarCoeffs;
861  if (mkey.HasVarCoeff(StdRegions::eVarCoeffD00))
862  {
863  Array<OneD, NekDouble> mu(nq);
864  GetPhysEdgeVarCoeffsFromElement(
865  i, EdgeExp2,
866  mkey.GetVarCoeff(StdRegions::eVarCoeffD00), mu);
867  edgeVarCoeffs[StdRegions::eVarCoeffMass] = mu;
868  }
869  DNekScalMat &eMass = *EdgeExp->GetLocMatrix(
870  StdRegions::eMass,
871  StdRegions::NullConstFactorMap, edgeVarCoeffs);
872  */
873 
874  DNekScalMat &eMass = *FaceExp->GetLocMatrix(StdRegions::eMass);
875 
876  for (j = 0; j < order_f; ++j)
877  {
878  for (k = 0; k < order_f; ++k)
879  {
880  Mat((*map)[j].index, (*map)[k].index) +=
881  tau * (*map)[j].sign * (*map)[k].sign * eMass(j, k);
882  }
883  }
884  }
885  break;
886  }
887 
888  // U^e (P22)
890  {
891  int i, j, k;
892  int nbndry = NumDGBndryCoeffs();
893  int ncoeffs = GetNcoeffs();
894  int nfaces = GetNtraces();
896 
897  Array<OneD, NekDouble> lambda(nbndry);
898  DNekVec Lambda(nbndry, lambda, eWrapper);
899  Array<OneD, NekDouble> ulam(ncoeffs);
900  DNekVec Ulam(ncoeffs, ulam, eWrapper);
901  Array<OneD, NekDouble> f(ncoeffs);
902  DNekVec F(ncoeffs, f, eWrapper);
903 
904  ExpansionSharedPtr FaceExp;
905  // declare matrix space
906  returnval =
908  DNekMat &Umat = *returnval;
909 
910  // Z^e matrix
911  MatrixKey newkey(StdRegions::eInvHybridDGHelmholtz, DetShapeType(),
912  *this, mkey.GetConstFactors(),
913  mkey.GetVarCoeffs());
914  DNekScalMat &invHmat = *GetLocMatrix(newkey);
915 
918 
919  // alternative way to add boundary terms contribution
920  int bndry_cnt = 0;
921  for (i = 0; i < nfaces; ++i)
922  {
923  FaceExp = GetTraceExp(
924  i); // temporary, need to rewrite AddHDGHelmholtzFaceTerms
925  int nface = GetTraceNcoeffs(i);
926  Array<OneD, NekDouble> face_lambda(nface);
927 
929  GetTraceNormal(i);
930 
931  for (j = 0; j < nface; ++j)
932  {
933  Vmath::Zero(nface, &face_lambda[0], 1);
934  Vmath::Zero(ncoeffs, &f[0], 1);
935  face_lambda[j] = 1.0;
936 
937  SetFaceToGeomOrientation(i, face_lambda);
938 
939  Array<OneD, NekDouble> tmp(FaceExp->GetTotPoints());
940  FaceExp->BwdTrans(face_lambda, tmp);
941  AddHDGHelmholtzFaceTerms(tau, i, tmp, mkey.GetVarCoeffs(),
942  f);
943 
944  Ulam = invHmat * F; // generate Ulam from lambda
945 
946  // fill column of matrix
947  for (k = 0; k < ncoeffs; ++k)
948  {
949  Umat(k, bndry_cnt) = Ulam[k];
950  }
951 
952  ++bndry_cnt;
953  }
954  }
955 
956  //// Set up face expansions from local geom info
957  // for(i = 0; i < nfaces; ++i)
958  //{
959  // FaceExp[i] = GetTraceExp(i);
960  //}
961  //
962  //// for each degree of freedom of the lambda space
963  //// calculate Umat entry
964  //// Generate Lambda to U_lambda matrix
965  // for(j = 0; j < nbndry; ++j)
966  //{
967  // // standard basis vectors e_j
968  // Vmath::Zero(nbndry,&lambda[0],1);
969  // Vmath::Zero(ncoeffs,&f[0],1);
970  // lambda[j] = 1.0;
971  //
972  // //cout << Lambda;
973  // SetTraceToGeomOrientation(lambda);
974  // //cout << Lambda << endl;
975  //
976  // // Compute F = [I D_1 M^{-1} D_2 M^{-1}] C e_j
977  // AddHDGHelmholtzTraceTerms(tau, lambda, FaceExp,
978  // mkey.GetVarCoeffs(), f);
979  //
980  // // Compute U^e_j
981  // Ulam = invHmat*F; // generate Ulam from lambda
982  //
983  // // fill column of matrix
984  // for(k = 0; k < ncoeffs; ++k)
985  // {
986  // Umat(k,j) = Ulam[k];
987  // }
988  //}
989  }
990  break;
991  // Q_0, Q_1, Q_2 matrices (P23)
992  // Each are a product of a row of Eqn 32 with the C matrix.
993  // Rather than explicitly computing all of Eqn 32, we note each
994  // row is almost a multiple of U^e, so use that as our starting
995  // point.
999  {
1000  int i = 0;
1001  int j = 0;
1002  int k = 0;
1003  int dir = 0;
1004  int nbndry = NumDGBndryCoeffs();
1005  int coordim = GetCoordim();
1006  int ncoeffs = GetNcoeffs();
1007  int nfaces = GetNtraces();
1008 
1009  Array<OneD, NekDouble> lambda(nbndry);
1010  DNekVec Lambda(nbndry, lambda, eWrapper);
1011  Array<OneD, ExpansionSharedPtr> FaceExp(nfaces);
1012 
1013  Array<OneD, NekDouble> ulam(ncoeffs);
1014  DNekVec Ulam(ncoeffs, ulam, eWrapper);
1015  Array<OneD, NekDouble> f(ncoeffs);
1016  DNekVec F(ncoeffs, f, eWrapper);
1017 
1018  // declare matrix space
1019  returnval =
1021  DNekMat &Qmat = *returnval;
1022 
1023  // Lambda to U matrix
1024  MatrixKey lamToUkey(StdRegions::eHybridDGLamToU, DetShapeType(),
1025  *this, mkey.GetConstFactors(),
1026  mkey.GetVarCoeffs());
1027  DNekScalMat &lamToU = *GetLocMatrix(lamToUkey);
1028 
1029  // Inverse mass matrix
1030  DNekScalMat &invMass = *GetLocMatrix(StdRegions::eInvMass);
1031 
1032  for (i = 0; i < nfaces; ++i)
1033  {
1034  FaceExp[i] = GetTraceExp(i);
1035  }
1036 
1037  // Weak Derivative matrix
1038  DNekScalMatSharedPtr Dmat;
1039  switch (mkey.GetMatrixType())
1040  {
1042  dir = 0;
1043  Dmat = GetLocMatrix(StdRegions::eWeakDeriv0);
1044  break;
1046  dir = 1;
1047  Dmat = GetLocMatrix(StdRegions::eWeakDeriv1);
1048  break;
1050  dir = 2;
1051  Dmat = GetLocMatrix(StdRegions::eWeakDeriv2);
1052  break;
1053  default:
1054  ASSERTL0(false, "Direction not known");
1055  break;
1056  }
1057 
1058  // DNekScalMatSharedPtr Dmat;
1059  // DNekScalMatSharedPtr &invMass;
1060  StdRegions::VarCoeffMap::const_iterator x;
1061  const StdRegions::VarCoeffMap &varcoeffs = mkey.GetVarCoeffs();
1062  if ((x = varcoeffs.find(StdRegions::eVarCoeffMF1x)) !=
1063  varcoeffs.end())
1064  {
1065  StdRegions::VarCoeffMap VarCoeffDirDeriv;
1066  VarCoeffDirDeriv[StdRegions::eVarCoeffMF] =
1067  GetMF(dir, coordim, varcoeffs);
1068  VarCoeffDirDeriv[StdRegions::eVarCoeffMFDiv] =
1069  GetMFDiv(dir, varcoeffs);
1070 
1071  MatrixKey Dmatkey(
1072  StdRegions::eWeakDirectionalDeriv, DetShapeType(), *this,
1073  StdRegions::NullConstFactorMap, VarCoeffDirDeriv);
1074 
1075  Dmat = GetLocMatrix(Dmatkey);
1076 
1077  StdRegions::VarCoeffMap Weight;
1078  Weight[StdRegions::eVarCoeffMass] =
1079  GetMFMag(dir, mkey.GetVarCoeffs());
1080 
1081  MatrixKey invMasskey(StdRegions::eInvMass, DetShapeType(),
1083  Weight);
1084 
1085  invMass = *GetLocMatrix(invMasskey);
1086  }
1087  else
1088  {
1089  // Inverse mass matrix
1090  invMass = *GetLocMatrix(StdRegions::eInvMass);
1091  }
1092 
1093  // for each degree of freedom of the lambda space
1094  // calculate Qmat entry
1095  // Generate Lambda to Q_lambda matrix
1096  for (j = 0; j < nbndry; ++j)
1097  {
1098  Vmath::Zero(nbndry, &lambda[0], 1);
1099  lambda[j] = 1.0;
1100 
1101  // for lambda[j] = 1 this is the solution to ulam
1102  for (k = 0; k < ncoeffs; ++k)
1103  {
1104  Ulam[k] = lamToU(k, j);
1105  }
1106 
1107  // -D^T ulam
1108  Vmath::Neg(ncoeffs, &ulam[0], 1);
1109  F = Transpose(*Dmat) * Ulam;
1110 
1111  SetTraceToGeomOrientation(lambda);
1112 
1113  // Add the C terms resulting from the I's on the
1114  // diagonals of Eqn 32
1115  AddNormTraceInt(dir, lambda, FaceExp, f, mkey.GetVarCoeffs());
1116 
1117  // finally multiply by inverse mass matrix
1118  Ulam = invMass * F;
1119 
1120  // fill column of matrix (Qmat is in column major format)
1121  Vmath::Vcopy(ncoeffs, &ulam[0], 1,
1122  &(Qmat.GetPtr())[0] + j * ncoeffs, 1);
1123  }
1124  }
1125  break;
1126  // Matrix K (P23)
1128  {
1129  int i, j, f, cnt;
1130  int order_f, nquad_f;
1131  int nbndry = NumDGBndryCoeffs();
1132  int nfaces = GetNtraces();
1134 
1135  Array<OneD, NekDouble> work, varcoeff_work;
1137  Array<OneD, ExpansionSharedPtr> FaceExp(nfaces);
1138  Array<OneD, NekDouble> lam(nbndry);
1139 
1142 
1143  // declare matrix space
1144  returnval =
1146  DNekMat &BndMat = *returnval;
1147 
1148  DNekScalMatSharedPtr LamToQ[3];
1149 
1150  // Matrix to map Lambda to U
1151  MatrixKey LamToUkey(StdRegions::eHybridDGLamToU, DetShapeType(),
1152  *this, mkey.GetConstFactors(),
1153  mkey.GetVarCoeffs());
1154  DNekScalMat &LamToU = *GetLocMatrix(LamToUkey);
1155 
1156  // Matrix to map Lambda to Q0
1157  MatrixKey LamToQ0key(StdRegions::eHybridDGLamToQ0, DetShapeType(),
1158  *this, mkey.GetConstFactors(),
1159  mkey.GetVarCoeffs());
1160  LamToQ[0] = GetLocMatrix(LamToQ0key);
1161 
1162  // Matrix to map Lambda to Q1
1163  MatrixKey LamToQ1key(StdRegions::eHybridDGLamToQ1, DetShapeType(),
1164  *this, mkey.GetConstFactors(),
1165  mkey.GetVarCoeffs());
1166  LamToQ[1] = GetLocMatrix(LamToQ1key);
1167 
1168  // Matrix to map Lambda to Q2
1169  MatrixKey LamToQ2key(StdRegions::eHybridDGLamToQ2, DetShapeType(),
1170  *this, mkey.GetConstFactors(),
1171  mkey.GetVarCoeffs());
1172  LamToQ[2] = GetLocMatrix(LamToQ2key);
1173 
1174  // Set up edge segment expansions from local geom info
1175  const StdRegions::VarCoeffMap &varcoeffs = mkey.GetVarCoeffs();
1176  for (i = 0; i < nfaces; ++i)
1177  {
1178  FaceExp[i] = GetTraceExp(i);
1179  }
1180 
1181  // Set up matrix derived from <mu, Q_lam.n - \tau (U_lam - Lam) >
1182  for (i = 0; i < nbndry; ++i)
1183  {
1184  cnt = 0;
1185 
1186  Vmath::Zero(nbndry, lam, 1);
1187  lam[i] = 1.0;
1188  SetTraceToGeomOrientation(lam);
1189 
1190  for (f = 0; f < nfaces; ++f)
1191  {
1192  order_f = FaceExp[f]->GetNcoeffs();
1193  nquad_f = FaceExp[f]->GetNumPoints(0) *
1194  FaceExp[f]->GetNumPoints(1);
1195  normals = GetTraceNormal(f);
1196 
1197  work = Array<OneD, NekDouble>(nquad_f);
1198  varcoeff_work = Array<OneD, NekDouble>(nquad_f);
1199 
1200  IndexMapKey ikey(eFaceToElement, DetShapeType(),
1201  GetBasisNumModes(0), GetBasisNumModes(1),
1202  GetBasisNumModes(2), f, GetTraceOrient(f));
1203  IndexMapValuesSharedPtr map = GetIndexMap(ikey);
1204 
1205  // @TODO Variable coefficients
1206  /*
1207  StdRegions::VarCoeffType VarCoeff[3] =
1208  {StdRegions::eVarCoeffD00, StdRegions::eVarCoeffD11,
1209  StdRegions::eVarCoeffD22};
1210  const StdRegions::VarCoeffMap &varcoeffs =
1211  mkey.GetVarCoeffs(); StdRegions::VarCoeffMap::const_iterator
1212  x;
1213  */
1214 
1215  // Q0 * n0 (BQ_0 terms)
1216  Array<OneD, NekDouble> faceCoeffs(order_f);
1217  Array<OneD, NekDouble> facePhys(nquad_f);
1218  for (j = 0; j < order_f; ++j)
1219  {
1220  faceCoeffs[j] =
1221  (*map)[j].sign * (*LamToQ[0])((*map)[j].index, i);
1222  }
1223 
1224  FaceExp[f]->BwdTrans(faceCoeffs, facePhys);
1225 
1226  // @TODO Variable coefficients
1227  // Multiply by variable coefficient
1228  /*
1229  if ((x = varcoeffs.find(VarCoeff[0])) != varcoeffs.end())
1230  {
1231  GetPhysEdgeVarCoeffsFromElement(e,EdgeExp[e],x->second,varcoeff_work);
1232  Vmath::Vmul(nquad_e,varcoeff_work,1,EdgeExp[e]->GetPhys(),1,EdgeExp[e]->UpdatePhys(),1);
1233  }
1234  */
1235 
1236  if (varcoeffs.find(StdRegions::eVarCoeffMF1x) !=
1237  varcoeffs.end())
1238  {
1239  Array<OneD, NekDouble> ncdotMF = GetnFacecdotMF(
1240  0, f, FaceExp[f], normals, varcoeffs);
1241 
1242  Vmath::Vmul(nquad_f, ncdotMF, 1, facePhys, 1, work, 1);
1243  }
1244  else
1245  {
1246  Vmath::Vmul(nquad_f, normals[0], 1, facePhys, 1, work,
1247  1);
1248  }
1249 
1250  // Q1 * n1 (BQ_1 terms)
1251  for (j = 0; j < order_f; ++j)
1252  {
1253  faceCoeffs[j] =
1254  (*map)[j].sign * (*LamToQ[1])((*map)[j].index, i);
1255  }
1256 
1257  FaceExp[f]->BwdTrans(faceCoeffs, facePhys);
1258 
1259  // @TODO Variable coefficients
1260  // Multiply by variable coefficients
1261  /*
1262  if ((x = varcoeffs.find(VarCoeff[1])) != varcoeffs.end())
1263  {
1264  GetPhysEdgeVarCoeffsFromElement(e,EdgeExp[e],x->second,varcoeff_work);
1265  Vmath::Vmul(nquad_e,varcoeff_work,1,EdgeExp[e]->GetPhys(),1,EdgeExp[e]->UpdatePhys(),1);
1266  }
1267  */
1268 
1269  if ((varcoeffs.find(StdRegions::eVarCoeffMF1x)) !=
1270  varcoeffs.end())
1271  {
1272  Array<OneD, NekDouble> ncdotMF = GetnFacecdotMF(
1273  1, f, FaceExp[f], normals, varcoeffs);
1274 
1275  Vmath::Vvtvp(nquad_f, ncdotMF, 1, facePhys, 1, work, 1,
1276  work, 1);
1277  }
1278  else
1279  {
1280  Vmath::Vvtvp(nquad_f, normals[1], 1, facePhys, 1, work,
1281  1, work, 1);
1282  }
1283 
1284  // Q2 * n2 (BQ_2 terms)
1285  for (j = 0; j < order_f; ++j)
1286  {
1287  faceCoeffs[j] =
1288  (*map)[j].sign * (*LamToQ[2])((*map)[j].index, i);
1289  }
1290 
1291  FaceExp[f]->BwdTrans(faceCoeffs, facePhys);
1292 
1293  // @TODO Variable coefficients
1294  // Multiply by variable coefficients
1295  /*
1296  if ((x = varcoeffs.find(VarCoeff[2])) != varcoeffs.end())
1297  {
1298  GetPhysEdgeVarCoeffsFromElement(e,EdgeExp[e],x->second,varcoeff_work);
1299  Vmath::Vmul(nquad_e,varcoeff_work,1,EdgeExp[e]->GetPhys(),1,EdgeExp[e]->UpdatePhys(),1);
1300  }
1301  */
1302 
1303  if (varcoeffs.find(StdRegions::eVarCoeffMF1x) !=
1304  varcoeffs.end())
1305  {
1306  Array<OneD, NekDouble> ncdotMF = GetnFacecdotMF(
1307  2, f, FaceExp[f], normals, varcoeffs);
1308 
1309  Vmath::Vvtvp(nquad_f, ncdotMF, 1, facePhys, 1, work, 1,
1310  work, 1);
1311  }
1312  else
1313  {
1314  Vmath::Vvtvp(nquad_f, normals[2], 1, facePhys, 1, work,
1315  1, work, 1);
1316  }
1317 
1318  // - tau (ulam - lam)
1319  // Corresponds to the G and BU terms.
1320  for (j = 0; j < order_f; ++j)
1321  {
1322  faceCoeffs[j] =
1323  (*map)[j].sign * LamToU((*map)[j].index, i) -
1324  lam[cnt + j];
1325  }
1326 
1327  FaceExp[f]->BwdTrans(faceCoeffs, facePhys);
1328 
1329  // @TODO Variable coefficients
1330  // Multiply by variable coefficients
1331  /*
1332  if ((x = varcoeffs.find(VarCoeff[0])) != varcoeffs.end())
1333  {
1334  GetPhysEdgeVarCoeffsFromElement(e,FaceExp[f],x->second,varcoeff_work);
1335  Vmath::Vmul(nquad_f,varcoeff_work,1,FaceExp[f]->GetPhys(),1,FaceExp[f]->UpdatePhys(),1);
1336  }
1337  */
1338 
1339  Vmath::Svtvp(nquad_f, -tau, facePhys, 1, work, 1, work, 1);
1340 
1341  // @TODO Add variable coefficients
1342  FaceExp[f]->IProductWRTBase(work, faceCoeffs);
1343 
1344  SetFaceToGeomOrientation(f, faceCoeffs);
1345 
1346  for (j = 0; j < order_f; ++j)
1347  {
1348  BndMat(cnt + j, i) = faceCoeffs[j];
1349  }
1350 
1351  cnt += order_f;
1352  }
1353  }
1354  }
1355  break;
1356  // HDG postprocessing
1358  {
1359  MatrixKey lapkey(StdRegions::eLaplacian, DetShapeType(), *this,
1360  mkey.GetConstFactors(), mkey.GetVarCoeffs());
1361  DNekScalMat &LapMat = *GetLocMatrix(lapkey);
1362 
1364  LapMat.GetRows(), LapMat.GetColumns());
1365  DNekMatSharedPtr lmat = returnval;
1366 
1367  (*lmat) = LapMat;
1368 
1369  // replace first column with inner product wrt 1
1370  int nq = GetTotPoints();
1371  Array<OneD, NekDouble> tmp(nq);
1372  Array<OneD, NekDouble> outarray(m_ncoeffs);
1373  Vmath::Fill(nq, 1.0, tmp, 1);
1374  IProductWRTBase(tmp, outarray);
1375 
1376  Vmath::Vcopy(m_ncoeffs, &outarray[0], 1, &(lmat->GetPtr())[0], 1);
1377 
1378  lmat->Invert();
1379  }
1380  break;
1382  {
1383  int ntraces = GetNtraces();
1384  int ncoords = GetCoordim();
1385  int nphys = GetTotPoints();
1387  Array<OneD, NekDouble> phys(nphys);
1388  returnval =
1389  MemoryManager<DNekMat>::AllocateSharedPtr(m_ncoeffs, m_ncoeffs);
1390  DNekMat &Mat = *returnval;
1391  Vmath::Zero(m_ncoeffs * m_ncoeffs, Mat.GetPtr(), 1);
1392 
1394 
1395  for (int d = 0; d < ncoords; ++d)
1396  {
1397  Deriv[d] = Array<OneD, NekDouble>(nphys);
1398  }
1399 
1400  Array<OneD, int> tracepts(ntraces);
1401  Array<OneD, ExpansionSharedPtr> traceExp(ntraces);
1402  int maxtpts = 0;
1403  for (int t = 0; t < ntraces; ++t)
1404  {
1405  traceExp[t] = GetTraceExp(t);
1406  tracepts[t] = traceExp[t]->GetTotPoints();
1407  maxtpts = (maxtpts > tracepts[t]) ? maxtpts : tracepts[t];
1408  }
1409 
1410  Array<OneD, NekDouble> val(maxtpts), tmp, tmp1;
1411 
1412  Array<OneD, Array<OneD, NekDouble>> dphidn(ntraces);
1413  for (int t = 0; t < ntraces; ++t)
1414  {
1415  dphidn[t] =
1416  Array<OneD, NekDouble>(m_ncoeffs * tracepts[t], 0.0);
1417  }
1418 
1419  for (int i = 0; i < m_ncoeffs; ++i)
1420  {
1421  FillMode(i, phys);
1422  PhysDeriv(phys, Deriv[0], Deriv[1], Deriv[2]);
1423 
1424  for (int t = 0; t < ntraces; ++t)
1425  {
1426  const NormalVector norm = GetTraceNormal(t);
1427 
1428  LibUtilities::BasisKey fromkey0 = GetTraceBasisKey(t, 0);
1429  LibUtilities::BasisKey fromkey1 = GetTraceBasisKey(t, 1);
1430  LibUtilities::BasisKey tokey0 =
1431  traceExp[t]->GetBasis(0)->GetBasisKey();
1432  LibUtilities::BasisKey tokey1 =
1433  traceExp[t]->GetBasis(1)->GetBasisKey();
1434  bool DoInterp =
1435  (fromkey0 != tokey0) || (fromkey1 != tokey1);
1436 
1437  // for variable p need add check and
1438  // interpolation here.
1439 
1440  Array<OneD, NekDouble> n(tracepts[t]);
1441  ;
1442  for (int d = 0; d < ncoords; ++d)
1443  {
1444  // if variable p may need to interpolate
1445  if (DoInterp)
1446  {
1447  LibUtilities::Interp2D(fromkey0, fromkey1, norm[d],
1448  tokey0, tokey1, n);
1449  }
1450  else
1451  {
1452  n = norm[d];
1453  }
1454 
1455  GetTracePhysVals(t, traceExp[t], Deriv[d], val,
1456  v_GetTraceOrient(t));
1457 
1458  Vmath::Vvtvp(tracepts[t], n, 1, val, 1,
1459  tmp = dphidn[t] + i * tracepts[t], 1,
1460  tmp1 = dphidn[t] + i * tracepts[t], 1);
1461  }
1462  }
1463  }
1464 
1465  for (int t = 0; t < ntraces; ++t)
1466  {
1467  int nt = tracepts[t];
1468  NekDouble h, p;
1469  TraceNormLen(t, h, p);
1470 
1471  // scaling from GJP paper
1472  NekDouble scale =
1473  (p == 1) ? 0.02 * h * h : 0.8 * pow(p + 1, -4.0) * h * h;
1474 
1475  for (int i = 0; i < m_ncoeffs; ++i)
1476  {
1477  for (int j = i; j < m_ncoeffs; ++j)
1478  {
1479  Vmath::Vmul(nt, dphidn[t] + i * nt, 1,
1480  dphidn[t] + j * nt, 1, val, 1);
1481  Mat(i, j) =
1482  Mat(i, j) + scale * traceExp[t]->Integral(val);
1483  }
1484  }
1485  }
1486 
1487  // fill in symmetric components.
1488  for (int i = 0; i < m_ncoeffs; ++i)
1489  {
1490  for (int j = 0; j < i; ++j)
1491  {
1492  Mat(i, j) = Mat(j, i);
1493  }
1494  }
1495  }
1496  break;
1497  default:
1498  ASSERTL0(false,
1499  "This matrix type cannot be generated from this class");
1500  break;
1501  }
1502 
1503  return returnval;
1504 }
1505 
1506 void Expansion3D::v_AddFaceNormBoundaryInt(
1507  const int face, const ExpansionSharedPtr &FaceExp,
1509 {
1510  int i, j;
1511 
1512  /*
1513  * Coming into this routine, the velocity V will have been
1514  * multiplied by the trace normals to give the input vector Vn. By
1515  * convention, these normals are inwards facing for elements which
1516  * have FaceExp as their right-adjacent face. This conditional
1517  * statement therefore determines whether the normals must be
1518  * negated, since the integral being performed here requires an
1519  * outwards facing normal.
1520  */
1521  if (m_requireNeg.size() == 0)
1522  {
1523  m_requireNeg.resize(GetNtraces());
1524 
1525  for (i = 0; i < GetNtraces(); ++i)
1526  {
1527  m_requireNeg[i] = false;
1528 
1529  ExpansionSharedPtr faceExp = m_traceExp[i].lock();
1530 
1531  if (faceExp->GetRightAdjacentElementExp())
1532  {
1533  if (faceExp->GetRightAdjacentElementExp()
1534  ->GetGeom()
1535  ->GetGlobalID() == GetGeom()->GetGlobalID())
1536  {
1537  m_requireNeg[i] = true;
1538  }
1539  }
1540  }
1541  }
1542 
1543  IndexMapKey ikey(eFaceToElement, DetShapeType(), GetBasisNumModes(0),
1544  GetBasisNumModes(1), GetBasisNumModes(2), face,
1545  GetTraceOrient(face));
1546  IndexMapValuesSharedPtr map = GetIndexMap(ikey);
1547 
1548  int order_e = (*map).size(); // Order of the element
1549  int n_coeffs = FaceExp->GetNcoeffs();
1550 
1551  Array<OneD, NekDouble> faceCoeffs(n_coeffs);
1552 
1553  if (n_coeffs != order_e) // Going to orthogonal space
1554  {
1555  Array<OneD, NekDouble> coeff(n_coeffs);
1556  Array<OneD, NekDouble> array(n_coeffs);
1557 
1558  FaceExp->FwdTrans(Fn, faceCoeffs);
1559 
1560  int NumModesElementMax = FaceExp->GetBasis(0)->GetNumModes();
1561  int NumModesElementMin = m_base[0]->GetNumModes();
1562 
1563  FaceExp->ReduceOrderCoeffs(NumModesElementMin, faceCoeffs, faceCoeffs);
1564 
1566  FaceExp->DetShapeType(), *FaceExp);
1567  FaceExp->MassMatrixOp(faceCoeffs, faceCoeffs, masskey);
1568 
1569  // Reorder coefficients for the lower degree face.
1570  int offset1 = 0, offset2 = 0;
1571 
1572  if (FaceExp->DetShapeType() == LibUtilities::eQuadrilateral)
1573  {
1574  for (i = 0; i < NumModesElementMin; ++i)
1575  {
1576  for (j = 0; j < NumModesElementMin; ++j)
1577  {
1578  faceCoeffs[offset1 + j] = faceCoeffs[offset2 + j];
1579  }
1580  offset1 += NumModesElementMin;
1581  offset2 += NumModesElementMax;
1582  }
1583 
1584  // Extract lower degree modes. TODO: Check this is correct.
1585  for (i = NumModesElementMin; i < NumModesElementMax; ++i)
1586  {
1587  for (j = NumModesElementMin; j < NumModesElementMax; ++j)
1588  {
1589  faceCoeffs[i * NumModesElementMax + j] = 0.0;
1590  }
1591  }
1592  }
1593 
1594  if (FaceExp->DetShapeType() == LibUtilities::eTriangle)
1595  {
1596 
1597  // Reorder coefficients for the lower degree face.
1598  int offset1 = 0, offset2 = 0;
1599 
1600  for (i = 0; i < NumModesElementMin; ++i)
1601  {
1602  for (j = 0; j < NumModesElementMin - i; ++j)
1603  {
1604  faceCoeffs[offset1 + j] = faceCoeffs[offset2 + j];
1605  }
1606  offset1 += NumModesElementMin - i;
1607  offset2 += NumModesElementMax - i;
1608  }
1609  }
1610  }
1611  else
1612  {
1613  FaceExp->IProductWRTBase(Fn, faceCoeffs);
1614  }
1615 
1616  if (m_requireNeg[face])
1617  {
1618  for (i = 0; i < order_e; ++i)
1619  {
1620  outarray[(*map)[i].index] -= (*map)[i].sign * faceCoeffs[i];
1621  }
1622  }
1623  else
1624  {
1625  for (i = 0; i < order_e; ++i)
1626  {
1627  outarray[(*map)[i].index] += (*map)[i].sign * faceCoeffs[i];
1628  }
1629  }
1630 }
1631 
1632 /**
1633  * @brief Evaluate coefficients of weak deriviative in the direction dir
1634  * given the input coefficicents incoeffs and the imposed boundary
1635  * values in EdgeExp (which will have its phys space updated).
1636  */
1637 void Expansion3D::v_DGDeriv(int dir,
1638  const Array<OneD, const NekDouble> &incoeffs,
1640  Array<OneD, Array<OneD, NekDouble>> &faceCoeffs,
1641  Array<OneD, NekDouble> &out_d)
1642 {
1643  int ncoeffs = GetNcoeffs();
1647 
1648  DNekScalMat &InvMass = *GetLocMatrix(StdRegions::eInvMass);
1649  DNekScalMat &Dmat = *GetLocMatrix(DerivType[dir]);
1650 
1651  Array<OneD, NekDouble> coeffs = incoeffs;
1652  DNekVec Coeffs(ncoeffs, coeffs, eWrapper);
1653 
1654  Coeffs = Transpose(Dmat) * Coeffs;
1655  Vmath::Neg(ncoeffs, coeffs, 1);
1656 
1657  // Add the boundary integral including the relevant part of
1658  // the normal
1659  AddNormTraceInt(dir, FaceExp, faceCoeffs, coeffs);
1660 
1661  DNekVec Out_d(ncoeffs, out_d, eWrapper);
1662 
1663  Out_d = InvMass * Coeffs;
1664 }
1665 
1666 void Expansion3D::v_AddRobinMassMatrix(
1667  const int face, const Array<OneD, const NekDouble> &primCoeffs,
1668  DNekMatSharedPtr &inoutmat)
1669 {
1670  ASSERTL1(IsBoundaryInteriorExpansion(),
1671  "Not set up for non boundary-interior expansions");
1672  ASSERTL1(inoutmat->GetRows() == inoutmat->GetColumns(),
1673  "Assuming that input matrix was square");
1674 
1675  int i, j;
1676  int id1, id2;
1677  ExpansionSharedPtr faceExp = m_traceExp[face].lock();
1678  int order_f = faceExp->GetNcoeffs();
1679 
1682 
1683  StdRegions::VarCoeffMap varcoeffs;
1684  varcoeffs[StdRegions::eVarCoeffMass] = primCoeffs;
1685 
1686  LibUtilities::ShapeType shapeType = faceExp->DetShapeType();
1687 
1688  LocalRegions::MatrixKey mkey(StdRegions::eMass, shapeType, *faceExp,
1689  StdRegions::NullConstFactorMap, varcoeffs);
1690 
1691  DNekScalMat &facemat = *faceExp->GetLocMatrix(mkey);
1692 
1693  // Now need to identify a map which takes the local face
1694  // mass matrix to the matrix stored in inoutmat;
1695  // This can currently be deduced from the size of the matrix
1696 
1697  // - if inoutmat.m_rows() == v_NCoeffs() it is a full
1698  // matrix system
1699 
1700  // - if inoutmat.m_rows() == v_GetNverts() it is a vertex space
1701  // preconditioner.
1702 
1703  // - if inoutmat.m_rows() == v_NumBndCoeffs() it is a
1704  // boundary CG system
1705 
1706  // - if inoutmat.m_rows() == v_NumDGBndCoeffs() it is a
1707  // trace DG system; still needs implementing.
1708  int rows = inoutmat->GetRows();
1709 
1710  if (rows == GetNcoeffs())
1711  {
1712  GetTraceToElementMap(face, map, sign, GetTraceOrient(face));
1713  }
1714  else if (rows == GetNverts())
1715  {
1716  int nfvert = faceExp->GetNverts();
1717 
1718  // Need to find where linear vertices are in facemat
1720  Array<OneD, int> linsign;
1721 
1722  // Use a linear expansion to get correct mapping
1723  GetLinStdExp()->GetTraceToElementMap(face, linmap, linsign,
1724  GetTraceOrient(face));
1725 
1726  // zero out sign map to remove all other modes
1727  sign = Array<OneD, int>(order_f, 0);
1728  map = Array<OneD, unsigned int>(order_f, (unsigned int)0);
1729 
1730  int fmap;
1731  // Reset sign map to only have contribution from vertices
1732  for (i = 0; i < nfvert; ++i)
1733  {
1734  fmap = faceExp->GetVertexMap(i, true);
1735  sign[fmap] = 1;
1736 
1737  // need to reset map
1738  map[fmap] = linmap[i];
1739  }
1740  }
1741  else if (rows == NumBndryCoeffs())
1742  {
1743  int nbndry = NumBndryCoeffs();
1744  Array<OneD, unsigned int> bmap(nbndry);
1745 
1746  GetTraceToElementMap(face, map, sign, GetTraceOrient(face));
1747  GetBoundaryMap(bmap);
1748 
1749  for (i = 0; i < order_f; ++i)
1750  {
1751  for (j = 0; j < nbndry; ++j)
1752  {
1753  if (map[i] == bmap[j])
1754  {
1755  map[i] = j;
1756  break;
1757  }
1758  }
1759  ASSERTL1(j != nbndry, "Did not find number in map");
1760  }
1761  }
1762  else if (rows == NumDGBndryCoeffs())
1763  {
1764  // possibly this should be a separate method
1765  int cnt = 0;
1766  map = Array<OneD, unsigned int>(order_f);
1767  sign = Array<OneD, int>(order_f, 1);
1768 
1769  IndexMapKey ikey1(eFaceToElement, DetShapeType(), GetBasisNumModes(0),
1770  GetBasisNumModes(1), GetBasisNumModes(2), face,
1771  GetTraceOrient(face));
1772  IndexMapValuesSharedPtr map1 = GetIndexMap(ikey1);
1773  IndexMapKey ikey2(eFaceToElement, DetShapeType(), GetBasisNumModes(0),
1774  GetBasisNumModes(1), GetBasisNumModes(2), face,
1776  IndexMapValuesSharedPtr map2 = GetIndexMap(ikey2);
1777 
1778  ASSERTL1((*map1).size() == (*map2).size(),
1779  "There is an error with the GetTraceToElementMap");
1780 
1781  for (i = 0; i < face; ++i)
1782  {
1783  cnt += GetTraceNcoeffs(i);
1784  }
1785 
1786  for (i = 0; i < (*map1).size(); ++i)
1787  {
1788  int idx = -1;
1789 
1790  for (j = 0; j < (*map2).size(); ++j)
1791  {
1792  if ((*map1)[i].index == (*map2)[j].index)
1793  {
1794  idx = j;
1795  break;
1796  }
1797  }
1798 
1799  ASSERTL2(idx >= 0, "Index not found");
1800  map[i] = idx + cnt;
1801  sign[i] = (*map2)[idx].sign;
1802  }
1803  }
1804  else
1805  {
1806  ASSERTL0(false, "Could not identify matrix type from dimension");
1807  }
1808 
1809  for (i = 0; i < order_f; ++i)
1810  {
1811  id1 = map[i];
1812  for (j = 0; j < order_f; ++j)
1813  {
1814  id2 = map[j];
1815  (*inoutmat)(id1, id2) += facemat(i, j) * sign[i] * sign[j];
1816  }
1817  }
1818 }
1819 
1820 DNekMatSharedPtr Expansion3D::v_BuildVertexMatrix(
1821  const DNekScalMatSharedPtr &r_bnd)
1822 {
1823  MatrixStorage storage = eFULL;
1824  DNekMatSharedPtr vertexmatrix;
1825 
1826  int nVerts, vid1, vid2, vMap1, vMap2;
1827  NekDouble VertexValue;
1828 
1829  nVerts = GetNverts();
1830 
1831  vertexmatrix =
1832  MemoryManager<DNekMat>::AllocateSharedPtr(nVerts, nVerts, 0.0, storage);
1833  DNekMat &VertexMat = (*vertexmatrix);
1834 
1835  for (vid1 = 0; vid1 < nVerts; ++vid1)
1836  {
1837  vMap1 = GetVertexMap(vid1, true);
1838 
1839  for (vid2 = 0; vid2 < nVerts; ++vid2)
1840  {
1841  vMap2 = GetVertexMap(vid2, true);
1842  VertexValue = (*r_bnd)(vMap1, vMap2);
1843  VertexMat.SetValue(vid1, vid2, VertexValue);
1844  }
1845  }
1846 
1847  return vertexmatrix;
1848 }
1849 
1850 DNekMatSharedPtr Expansion3D::v_BuildTransformationMatrix(
1851  const DNekScalMatSharedPtr &r_bnd, const StdRegions::MatrixType matrixType)
1852 {
1853  int nVerts, nEdges;
1854  int eid, fid, vid, n, i;
1855 
1856  int nBndCoeffs = NumBndryCoeffs();
1857 
1858  const SpatialDomains::Geometry3DSharedPtr &geom = GetGeom3D();
1859 
1860  // Get geometric information about this element
1861  nVerts = GetNverts();
1862  nEdges = GetNedges();
1863 
1864  /*************************************/
1865  /* Vetex-edge & vertex-face matrices */
1866  /*************************************/
1867 
1868  /**
1869  * The matrix component of \f$\mathbf{R}\f$ is given by \f[
1870  * \mathbf{R^{T}_{v}}=
1871  * -\mathbf{S}^{-1}_{ef,ef}\mathbf{S}^{T}_{v,ef}\f]
1872  *
1873  * For every vertex mode we extract the submatrices from statically
1874  * condensed matrix \f$\mathbf{S}\f$ corresponding to the coupling
1875  * between the attached edges and faces of a vertex
1876  * (\f$\mathbf{S_{ef,ef}}\f$). This matrix is then inverted and
1877  * multiplied by the submatrix representing the coupling between a
1878  * vertex and the attached edges and faces
1879  * (\f$\mathbf{S_{v,ef}}\f$).
1880  */
1881 
1882  int nmodes;
1883  int m;
1884  NekDouble VertexEdgeFaceValue;
1885 
1886  // The number of connected edges/faces is 3 (for all elements)
1887  int nConnectedEdges = 3;
1888  int nConnectedFaces = 3;
1889 
1890  // Location in the matrix
1891  Array<OneD, Array<OneD, unsigned int>> MatEdgeLocation(nConnectedEdges);
1892  Array<OneD, Array<OneD, unsigned int>> MatFaceLocation(nConnectedFaces);
1893 
1894  // Define storage for vertex transpose matrix and zero all entries
1895  MatrixStorage storage = eFULL;
1896  DNekMatSharedPtr transformationmatrix;
1897 
1898  transformationmatrix = MemoryManager<DNekMat>::AllocateSharedPtr(
1899  nBndCoeffs, nBndCoeffs, 0.0, storage);
1900 
1901  DNekMat &R = (*transformationmatrix);
1902 
1903  // Build the vertex-edge/face transform matrix: This matrix is
1904  // constructed from the submatrices corresponding to the couping
1905  // between each vertex and the attached edges/faces
1906  for (vid = 0; vid < nVerts; ++vid)
1907  {
1908  // Row and column size of the vertex-edge/face matrix
1909  int efRow = GetEdgeNcoeffs(geom->GetVertexEdgeMap(vid, 0)) +
1910  GetEdgeNcoeffs(geom->GetVertexEdgeMap(vid, 1)) +
1911  GetEdgeNcoeffs(geom->GetVertexEdgeMap(vid, 2)) +
1912  GetTraceIntNcoeffs(geom->GetVertexFaceMap(vid, 0)) +
1913  GetTraceIntNcoeffs(geom->GetVertexFaceMap(vid, 1)) +
1914  GetTraceIntNcoeffs(geom->GetVertexFaceMap(vid, 2)) - 6;
1915 
1916  int nedgemodesconnected =
1917  GetEdgeNcoeffs(geom->GetVertexEdgeMap(vid, 0)) +
1918  GetEdgeNcoeffs(geom->GetVertexEdgeMap(vid, 1)) +
1919  GetEdgeNcoeffs(geom->GetVertexEdgeMap(vid, 2)) - 6;
1920  Array<OneD, unsigned int> edgemodearray(nedgemodesconnected);
1921 
1922  int nfacemodesconnected =
1923  GetTraceIntNcoeffs(geom->GetVertexFaceMap(vid, 0)) +
1924  GetTraceIntNcoeffs(geom->GetVertexFaceMap(vid, 1)) +
1925  GetTraceIntNcoeffs(geom->GetVertexFaceMap(vid, 2));
1926  Array<OneD, unsigned int> facemodearray(nfacemodesconnected);
1927 
1928  int offset = 0;
1929 
1930  // Create array of edge modes
1931  for (eid = 0; eid < nConnectedEdges; ++eid)
1932  {
1933  MatEdgeLocation[eid] =
1934  GetEdgeInverseBoundaryMap(geom->GetVertexEdgeMap(vid, eid));
1935  nmodes = MatEdgeLocation[eid].size();
1936 
1937  if (nmodes)
1938  {
1939  Vmath::Vcopy(nmodes, &MatEdgeLocation[eid][0], 1,
1940  &edgemodearray[offset], 1);
1941  }
1942 
1943  offset += nmodes;
1944  }
1945 
1946  offset = 0;
1947 
1948  // Create array of face modes
1949  for (fid = 0; fid < nConnectedFaces; ++fid)
1950  {
1951  MatFaceLocation[fid] =
1952  GetTraceInverseBoundaryMap(geom->GetVertexFaceMap(vid, fid));
1953  nmodes = MatFaceLocation[fid].size();
1954 
1955  if (nmodes)
1956  {
1957  Vmath::Vcopy(nmodes, &MatFaceLocation[fid][0], 1,
1958  &facemodearray[offset], 1);
1959  }
1960  offset += nmodes;
1961  }
1962 
1963  DNekMatSharedPtr vertexedgefacetransformmatrix =
1964  MemoryManager<DNekMat>::AllocateSharedPtr(1, efRow, 0.0, storage);
1965  DNekMat &Sveft = (*vertexedgefacetransformmatrix);
1966 
1967  DNekMatSharedPtr vertexedgefacecoupling =
1968  MemoryManager<DNekMat>::AllocateSharedPtr(1, efRow, 0.0, storage);
1969  DNekMat &Svef = (*vertexedgefacecoupling);
1970 
1971  // Vertex-edge coupling
1972  for (n = 0; n < nedgemodesconnected; ++n)
1973  {
1974  // Matrix value for each coefficient location
1975  VertexEdgeFaceValue = (*r_bnd)(GetVertexMap(vid), edgemodearray[n]);
1976 
1977  // Set the value in the vertex edge/face matrix
1978  Svef.SetValue(0, n, VertexEdgeFaceValue);
1979  }
1980 
1981  // Vertex-face coupling
1982  for (n = 0; n < nfacemodesconnected; ++n)
1983  {
1984  // Matrix value for each coefficient location
1985  VertexEdgeFaceValue = (*r_bnd)(GetVertexMap(vid), facemodearray[n]);
1986 
1987  // Set the value in the vertex edge/face matrix
1988  Svef.SetValue(0, n + nedgemodesconnected, VertexEdgeFaceValue);
1989  }
1990 
1991  /*
1992  * Build the edge-face transform matrix: This matrix is
1993  * constructed from the submatrices corresponding to the couping
1994  * between the edges and faces on the attached faces/edges of a
1995  * vertex.
1996  */
1997 
1998  // Allocation of matrix to store edge/face-edge/face coupling
1999  DNekMatSharedPtr edgefacecoupling =
2001  storage);
2002  DNekMat &Sefef = (*edgefacecoupling);
2003 
2004  NekDouble EdgeEdgeValue, FaceFaceValue;
2005 
2006  // Edge-edge coupling (S_{ee})
2007  for (m = 0; m < nedgemodesconnected; ++m)
2008  {
2009  for (n = 0; n < nedgemodesconnected; ++n)
2010  {
2011  // Matrix value for each coefficient location
2012  EdgeEdgeValue = (*r_bnd)(edgemodearray[n], edgemodearray[m]);
2013 
2014  // Set the value in the vertex edge/face matrix
2015  Sefef.SetValue(n, m, EdgeEdgeValue);
2016  }
2017  }
2018 
2019  // Face-face coupling (S_{ff})
2020  for (n = 0; n < nfacemodesconnected; ++n)
2021  {
2022  for (m = 0; m < nfacemodesconnected; ++m)
2023  {
2024  // Matrix value for each coefficient location
2025  FaceFaceValue = (*r_bnd)(facemodearray[n], facemodearray[m]);
2026  // Set the value in the vertex edge/face matrix
2027  Sefef.SetValue(nedgemodesconnected + n, nedgemodesconnected + m,
2028  FaceFaceValue);
2029  }
2030  }
2031 
2032  // Edge-face coupling (S_{ef} and trans(S_{ef}))
2033  for (n = 0; n < nedgemodesconnected; ++n)
2034  {
2035  for (m = 0; m < nfacemodesconnected; ++m)
2036  {
2037  // Matrix value for each coefficient location
2038  FaceFaceValue = (*r_bnd)(edgemodearray[n], facemodearray[m]);
2039 
2040  // Set the value in the vertex edge/face matrix
2041  Sefef.SetValue(n, nedgemodesconnected + m, FaceFaceValue);
2042 
2043  FaceFaceValue = (*r_bnd)(facemodearray[m], edgemodearray[n]);
2044 
2045  // and transpose
2046  Sefef.SetValue(nedgemodesconnected + m, n, FaceFaceValue);
2047  }
2048  }
2049 
2050  // Invert edge-face coupling matrix
2051  if (efRow)
2052  {
2053  Sefef.Invert();
2054 
2055  // R_{v}=-S_{v,ef}inv(S_{ef,ef})
2056  Sveft = -Svef * Sefef;
2057  }
2058 
2059  // Populate R with R_{ve} components
2060  for (n = 0; n < edgemodearray.size(); ++n)
2061  {
2062  R.SetValue(GetVertexMap(vid), edgemodearray[n], Sveft(0, n));
2063  }
2064 
2065  // Populate R with R_{vf} components
2066  for (n = 0; n < facemodearray.size(); ++n)
2067  {
2068  R.SetValue(GetVertexMap(vid), facemodearray[n],
2069  Sveft(0, n + nedgemodesconnected));
2070  }
2071  }
2072 
2073  /********************/
2074  /* edge-face matrix */
2075  /********************/
2076 
2077  /*
2078  * The matrix component of \f$\mathbf{R}\f$ is given by \f[
2079  * \mathbf{R^{T}_{ef}}=-\mathbf{S}^{-1}_{ff}\mathbf{S}^{T}_{ef}\f]
2080  *
2081  * For each edge extract the submatrices from statically condensed
2082  * matrix \f$\mathbf{S}\f$ corresponding to inner products of modes
2083  * on the two attached faces within themselves as well as the
2084  * coupling matrix between the two faces
2085  * (\f$\mathbf{S}_{ff}\f$). This matrix of face coupling is then
2086  * inverted and multiplied by the submatrices of corresponding to
2087  * the coupling between the edge and attached faces
2088  * (\f$\mathbf{S}_{ef}\f$).
2089  */
2090 
2091  NekDouble EdgeFaceValue, FaceFaceValue;
2092  int efCol, efRow, nedgemodes;
2093 
2094  // Number of attached faces is always 2
2095  nConnectedFaces = 2;
2096 
2097  // Location in the matrix
2098  MatEdgeLocation = Array<OneD, Array<OneD, unsigned int>>(nEdges);
2099  MatFaceLocation = Array<OneD, Array<OneD, unsigned int>>(nConnectedFaces);
2100 
2101  // Build the edge/face transform matrix: This matrix is constructed
2102  // from the submatrices corresponding to the couping between a
2103  // specific edge and the two attached faces.
2104  for (eid = 0; eid < nEdges; ++eid)
2105  {
2106  // Row and column size of the vertex-edge/face matrix
2107  efCol = GetTraceIntNcoeffs(geom->GetEdgeFaceMap(eid, 0)) +
2108  GetTraceIntNcoeffs(geom->GetEdgeFaceMap(eid, 1));
2109  efRow = GetEdgeNcoeffs(eid) - 2;
2110 
2111  // Edge-face coupling matrix
2112  DNekMatSharedPtr efedgefacecoupling =
2114  storage);
2115  DNekMat &Mef = (*efedgefacecoupling);
2116 
2117  // Face-face coupling matrix
2118  DNekMatSharedPtr effacefacecoupling =
2120  storage);
2121  DNekMat &Meff = (*effacefacecoupling);
2122 
2123  // Edge-face transformation matrix
2124  DNekMatSharedPtr edgefacetransformmatrix =
2126  storage);
2127  DNekMat &Meft = (*edgefacetransformmatrix);
2128 
2129  int nfacemodesconnected =
2130  GetTraceIntNcoeffs(geom->GetEdgeFaceMap(eid, 0)) +
2131  GetTraceIntNcoeffs(geom->GetEdgeFaceMap(eid, 1));
2132  Array<OneD, unsigned int> facemodearray(nfacemodesconnected);
2133 
2134  // Create array of edge modes
2135  Array<OneD, unsigned int> inedgearray = GetEdgeInverseBoundaryMap(eid);
2136  nedgemodes = GetEdgeNcoeffs(eid) - 2;
2137  Array<OneD, unsigned int> edgemodearray(nedgemodes);
2138 
2139  if (nedgemodes)
2140  {
2141  Vmath::Vcopy(nedgemodes, &inedgearray[0], 1, &edgemodearray[0], 1);
2142  }
2143 
2144  int offset = 0;
2145 
2146  // Create array of face modes
2147  for (fid = 0; fid < nConnectedFaces; ++fid)
2148  {
2149  MatFaceLocation[fid] =
2150  GetTraceInverseBoundaryMap(geom->GetEdgeFaceMap(eid, fid));
2151  nmodes = MatFaceLocation[fid].size();
2152 
2153  if (nmodes)
2154  {
2155  Vmath::Vcopy(nmodes, &MatFaceLocation[fid][0], 1,
2156  &facemodearray[offset], 1);
2157  }
2158  offset += nmodes;
2159  }
2160 
2161  // Edge-face coupling
2162  for (n = 0; n < nedgemodes; ++n)
2163  {
2164  for (m = 0; m < nfacemodesconnected; ++m)
2165  {
2166  // Matrix value for each coefficient location
2167  EdgeFaceValue = (*r_bnd)(edgemodearray[n], facemodearray[m]);
2168 
2169  // Set the value in the edge/face matrix
2170  Mef.SetValue(n, m, EdgeFaceValue);
2171  }
2172  }
2173 
2174  // Face-face coupling
2175  for (n = 0; n < nfacemodesconnected; ++n)
2176  {
2177  for (m = 0; m < nfacemodesconnected; ++m)
2178  {
2179  // Matrix value for each coefficient location
2180  FaceFaceValue = (*r_bnd)(facemodearray[n], facemodearray[m]);
2181 
2182  // Set the value in the vertex edge/face matrix
2183  Meff.SetValue(n, m, FaceFaceValue);
2184  }
2185  }
2186 
2187  if (efCol)
2188  {
2189  // Invert edge-face coupling matrix
2190  Meff.Invert();
2191 
2192  // trans(R_{ef})=-S_{ef}*(inv(S_{ff})
2193  Meft = -Mef * Meff;
2194  }
2195 
2196  // Populate transformation matrix with Meft
2197  for (n = 0; n < Meft.GetRows(); ++n)
2198  {
2199  for (m = 0; m < Meft.GetColumns(); ++m)
2200  {
2201  R.SetValue(edgemodearray[n], facemodearray[m], Meft(n, m));
2202  }
2203  }
2204  }
2205 
2206  for (i = 0; i < R.GetRows(); ++i)
2207  {
2208  R.SetValue(i, i, 1.0);
2209  }
2210 
2211  if ((matrixType == StdRegions::ePreconR) ||
2212  (matrixType == StdRegions::ePreconRMass))
2213  {
2214  return transformationmatrix;
2215  }
2216  else
2217  {
2218  NEKERROR(ErrorUtil::efatal, "unkown matrix type");
2219  return NullDNekMatSharedPtr;
2220  }
2221 }
2222 
2223 /**
2224  * \brief Build inverse and inverse transposed transformation matrix:
2225  * \f$\mathbf{R^{-1}}\f$ and \f$\mathbf{R^{-T}}\f$
2226  *
2227  * \f\mathbf{R^{-T}}=[\left[\begin{array}{ccc} \mathbf{I} &
2228  * -\mathbf{R}_{ef} & -\mathbf{R}_{ve}+\mathbf{R}_{ve}\mathbf{R}_{vf} \\
2229  * 0 & \mathbf{I} & \mathbf{R}_{ef} \\
2230  * 0 & 0 & \mathbf{I}} \end{array}\right]\f]
2231  */
2232 DNekMatSharedPtr Expansion3D::v_BuildInverseTransformationMatrix(
2233  const DNekScalMatSharedPtr &transformationmatrix)
2234 {
2235  int i, j, n, eid = 0, fid = 0;
2236  int nCoeffs = NumBndryCoeffs();
2237  NekDouble MatrixValue;
2238  DNekScalMat &R = (*transformationmatrix);
2239 
2240  // Define storage for vertex transpose matrix and zero all entries
2241  MatrixStorage storage = eFULL;
2242 
2243  // Inverse transformation matrix
2244  DNekMatSharedPtr inversetransformationmatrix =
2245  MemoryManager<DNekMat>::AllocateSharedPtr(nCoeffs, nCoeffs, 0.0,
2246  storage);
2247  DNekMat &InvR = (*inversetransformationmatrix);
2248 
2249  int nVerts = GetNverts();
2250  int nEdges = GetNedges();
2251  int nFaces = GetNtraces();
2252 
2253  int nedgemodes = 0;
2254  int nfacemodes = 0;
2255  int nedgemodestotal = 0;
2256  int nfacemodestotal = 0;
2257 
2258  for (eid = 0; eid < nEdges; ++eid)
2259  {
2260  nedgemodes = GetEdgeNcoeffs(eid) - 2;
2261  nedgemodestotal += nedgemodes;
2262  }
2263 
2264  for (fid = 0; fid < nFaces; ++fid)
2265  {
2266  nfacemodes = GetTraceIntNcoeffs(fid);
2267  nfacemodestotal += nfacemodes;
2268  }
2269 
2270  Array<OneD, unsigned int> edgemodearray(nedgemodestotal);
2271  Array<OneD, unsigned int> facemodearray(nfacemodestotal);
2272 
2273  int offset = 0;
2274 
2275  // Create array of edge modes
2276  for (eid = 0; eid < nEdges; ++eid)
2277  {
2278  Array<OneD, unsigned int> edgearray = GetEdgeInverseBoundaryMap(eid);
2279  nedgemodes = GetEdgeNcoeffs(eid) - 2;
2280 
2281  // Only copy if there are edge modes
2282  if (nedgemodes)
2283  {
2284  Vmath::Vcopy(nedgemodes, &edgearray[0], 1, &edgemodearray[offset],
2285  1);
2286  }
2287 
2288  offset += nedgemodes;
2289  }
2290 
2291  offset = 0;
2292 
2293  // Create array of face modes
2294  for (fid = 0; fid < nFaces; ++fid)
2295  {
2296  Array<OneD, unsigned int> facearray = GetTraceInverseBoundaryMap(fid);
2297  nfacemodes = GetTraceIntNcoeffs(fid);
2298 
2299  // Only copy if there are face modes
2300  if (nfacemodes)
2301  {
2302  Vmath::Vcopy(nfacemodes, &facearray[0], 1, &facemodearray[offset],
2303  1);
2304  }
2305 
2306  offset += nfacemodes;
2307  }
2308 
2309  // Vertex-edge/face
2310  for (i = 0; i < nVerts; ++i)
2311  {
2312  for (j = 0; j < nedgemodestotal; ++j)
2313  {
2314  InvR.SetValue(GetVertexMap(i), edgemodearray[j],
2315  -R(GetVertexMap(i), edgemodearray[j]));
2316  }
2317  for (j = 0; j < nfacemodestotal; ++j)
2318  {
2319  InvR.SetValue(GetVertexMap(i), facemodearray[j],
2320  -R(GetVertexMap(i), facemodearray[j]));
2321  for (n = 0; n < nedgemodestotal; ++n)
2322  {
2323  MatrixValue = InvR.GetValue(GetVertexMap(i), facemodearray[j]) +
2324  R(GetVertexMap(i), edgemodearray[n]) *
2325  R(edgemodearray[n], facemodearray[j]);
2326  InvR.SetValue(GetVertexMap(i), facemodearray[j], MatrixValue);
2327  }
2328  }
2329  }
2330 
2331  // Edge-face contributions
2332  for (i = 0; i < nedgemodestotal; ++i)
2333  {
2334  for (j = 0; j < nfacemodestotal; ++j)
2335  {
2336  InvR.SetValue(edgemodearray[i], facemodearray[j],
2337  -R(edgemodearray[i], facemodearray[j]));
2338  }
2339  }
2340 
2341  for (i = 0; i < nCoeffs; ++i)
2342  {
2343  InvR.SetValue(i, i, 1.0);
2344  }
2345 
2346  return inversetransformationmatrix;
2347 }
2348 
2349 Array<OneD, unsigned int> Expansion3D::GetEdgeInverseBoundaryMap(int eid)
2350 {
2351  int n, j;
2352  int nEdgeCoeffs;
2353  int nBndCoeffs = NumBndryCoeffs();
2354 
2355  Array<OneD, unsigned int> bmap(nBndCoeffs);
2356  GetBoundaryMap(bmap);
2357 
2358  // Map from full system to statically condensed system (i.e reverse
2359  // GetBoundaryMap)
2360  map<int, int> invmap;
2361  for (j = 0; j < nBndCoeffs; ++j)
2362  {
2363  invmap[bmap[j]] = j;
2364  }
2365 
2366  // Number of interior edge coefficients
2367  nEdgeCoeffs = GetEdgeNcoeffs(eid) - 2;
2368 
2369  const SpatialDomains::Geometry3DSharedPtr &geom = GetGeom3D();
2370 
2371  Array<OneD, unsigned int> edgemaparray(nEdgeCoeffs);
2372  StdRegions::Orientation eOrient = geom->GetEorient(eid);
2373  Array<OneD, unsigned int> maparray = Array<OneD, unsigned int>(nEdgeCoeffs);
2374  Array<OneD, int> signarray = Array<OneD, int>(nEdgeCoeffs, 1);
2375 
2376  // maparray is the location of the edge within the matrix
2377  GetEdgeInteriorToElementMap(eid, maparray, signarray, eOrient);
2378 
2379  for (n = 0; n < nEdgeCoeffs; ++n)
2380  {
2381  edgemaparray[n] = invmap[maparray[n]];
2382  }
2383 
2384  return edgemaparray;
2385 }
2386 
2387 Array<OneD, unsigned int> Expansion3D::GetTraceInverseBoundaryMap(
2388  int fid, StdRegions::Orientation faceOrient, int P1, int P2)
2389 {
2390  int n, j;
2391  int nFaceCoeffs;
2392 
2393  int nBndCoeffs = NumBndryCoeffs();
2394 
2395  Array<OneD, unsigned int> bmap(nBndCoeffs);
2396  GetBoundaryMap(bmap);
2397 
2398  // Map from full system to statically condensed system (i.e reverse
2399  // GetBoundaryMap)
2400  map<int, int> reversemap;
2401  for (j = 0; j < bmap.size(); ++j)
2402  {
2403  reversemap[bmap[j]] = j;
2404  }
2405 
2406  // Number of interior face coefficients
2407  nFaceCoeffs = GetTraceIntNcoeffs(fid);
2408 
2409  StdRegions::Orientation fOrient;
2410  Array<OneD, unsigned int> maparray = Array<OneD, unsigned int>(nFaceCoeffs);
2411  Array<OneD, int> signarray = Array<OneD, int>(nFaceCoeffs, 1);
2412 
2413  if (faceOrient == StdRegions::eNoOrientation)
2414  {
2415  fOrient = GetTraceOrient(fid);
2416  }
2417  else
2418  {
2419  fOrient = faceOrient;
2420  }
2421 
2422  // maparray is the location of the face within the matrix
2423  GetTraceInteriorToElementMap(fid, maparray, signarray, fOrient);
2424 
2425  Array<OneD, unsigned int> facemaparray;
2426  int locP1, locP2;
2427  GetTraceNumModes(fid, locP1, locP2, fOrient);
2428 
2429  if (P1 == -1)
2430  {
2431  P1 = locP1;
2432  }
2433  else
2434  {
2435  ASSERTL1(P1 <= locP1, "Expect value of passed P1 to "
2436  "be lower or equal to face num modes");
2437  }
2438 
2439  if (P2 == -1)
2440  {
2441  P2 = locP2;
2442  }
2443  else
2444  {
2445  ASSERTL1(P2 <= locP2, "Expect value of passed P2 to "
2446  "be lower or equal to face num modes");
2447  }
2448 
2449  switch (GetGeom3D()->GetFace(fid)->GetShapeType())
2450  {
2452  {
2453  if (((P1 - 3) > 0) && ((P2 - 3) > 0))
2454  {
2455  facemaparray = Array<OneD, unsigned int>(
2457  P2 - 3));
2458  int cnt = 0;
2459  int cnt1 = 0;
2460  for (n = 0; n < P1 - 3; ++n)
2461  {
2462  for (int m = 0; m < P2 - 3 - n; ++m, ++cnt)
2463  {
2464  facemaparray[cnt] = reversemap[maparray[cnt1 + m]];
2465  }
2466  cnt1 += locP2 - 3 - n;
2467  }
2468  }
2469  }
2470  break;
2472  {
2473  if (((P1 - 2) > 0) && ((P2 - 2) > 0))
2474  {
2475  facemaparray = Array<OneD, unsigned int>(
2477  P2 - 2));
2478  int cnt = 0;
2479  int cnt1 = 0;
2480  for (n = 0; n < P2 - 2; ++n)
2481  {
2482  for (int m = 0; m < P1 - 2; ++m, ++cnt)
2483  {
2484  facemaparray[cnt] = reversemap[maparray[cnt1 + m]];
2485  }
2486  cnt1 += locP1 - 2;
2487  }
2488  }
2489  }
2490  break;
2491  default:
2492  {
2493  ASSERTL0(false, "Invalid shape type.");
2494  }
2495  break;
2496  }
2497 
2498  return facemaparray;
2499 }
2500 
2501 void Expansion3D::GetInverseBoundaryMaps(
2505 {
2506  int n, j;
2507  int nEdgeCoeffs;
2508  int nFaceCoeffs;
2509 
2510  int nBndCoeffs = NumBndryCoeffs();
2511 
2512  Array<OneD, unsigned int> bmap(nBndCoeffs);
2513  GetBoundaryMap(bmap);
2514 
2515  // Map from full system to statically condensed system (i.e reverse
2516  // GetBoundaryMap)
2517  map<int, int> reversemap;
2518  for (j = 0; j < bmap.size(); ++j)
2519  {
2520  reversemap[bmap[j]] = j;
2521  }
2522 
2523  int nverts = GetNverts();
2524  vmap = Array<OneD, unsigned int>(nverts);
2525  for (n = 0; n < nverts; ++n)
2526  {
2527  int id = GetVertexMap(n);
2528  vmap[n] = reversemap[id]; // not sure what should be true here.
2529  }
2530 
2531  int nedges = GetNedges();
2532  emap = Array<OneD, Array<OneD, unsigned int>>(nedges);
2533 
2534  for (int eid = 0; eid < nedges; ++eid)
2535  {
2536  // Number of interior edge coefficients
2537  nEdgeCoeffs = GetEdgeNcoeffs(eid) - 2;
2538 
2539  Array<OneD, unsigned int> edgemaparray(nEdgeCoeffs);
2540  Array<OneD, unsigned int> maparray =
2541  Array<OneD, unsigned int>(nEdgeCoeffs);
2542  Array<OneD, int> signarray = Array<OneD, int>(nEdgeCoeffs, 1);
2543 
2544  // maparray is the location of the edge within the matrix
2545  GetEdgeInteriorToElementMap(eid, maparray, signarray,
2547 
2548  for (n = 0; n < nEdgeCoeffs; ++n)
2549  {
2550  edgemaparray[n] = reversemap[maparray[n]];
2551  }
2552  emap[eid] = edgemaparray;
2553  }
2554 
2555  int nfaces = GetNtraces();
2556  fmap = Array<OneD, Array<OneD, unsigned int>>(nfaces);
2557 
2558  for (int fid = 0; fid < nfaces; ++fid)
2559  {
2560  // Number of interior face coefficients
2561  nFaceCoeffs = GetTraceIntNcoeffs(fid);
2562 
2563  Array<OneD, unsigned int> facemaparray(nFaceCoeffs);
2564  Array<OneD, unsigned int> maparray =
2565  Array<OneD, unsigned int>(nFaceCoeffs);
2566  Array<OneD, int> signarray = Array<OneD, int>(nFaceCoeffs, 1);
2567 
2568  // maparray is the location of the face within the matrix
2569  GetTraceInteriorToElementMap(fid, maparray, signarray,
2571 
2572  for (n = 0; n < nFaceCoeffs; ++n)
2573  {
2574  facemaparray[n] = reversemap[maparray[n]];
2575  }
2576 
2577  fmap[fid] = facemaparray;
2578  }
2579 }
2580 
2581 StdRegions::Orientation Expansion3D::v_GetTraceOrient(int face)
2582 {
2583  return m_geom->GetForient(face);
2584 }
2585 
2586 /**
2587  * @brief Extract the physical values along face \a face from \a
2588  * inarray into \a outarray following the local face orientation
2589  * and point distribution defined by defined in \a FaceExp.
2590  */
2591 void Expansion3D::v_GetTracePhysVals(
2592  const int face, const StdRegions::StdExpansionSharedPtr &FaceExp,
2593  const Array<OneD, const NekDouble> &inarray,
2595 {
2596  if (orient == StdRegions::eNoOrientation)
2597  {
2598  orient = GetTraceOrient(face);
2599  }
2600 
2601  int nq0 = FaceExp->GetNumPoints(0);
2602  int nq1 = FaceExp->GetNumPoints(1);
2603 
2604  int nfacepts = GetTraceNumPoints(face);
2605  int dir0 = GetGeom3D()->GetDir(face, 0);
2606  int dir1 = GetGeom3D()->GetDir(face, 1);
2607 
2608  Array<OneD, NekDouble> o_tmp(nfacepts);
2609  Array<OneD, NekDouble> o_tmp2(FaceExp->GetTotPoints());
2610  Array<OneD, int> faceids;
2611 
2612  // Get local face pts and put into o_tmp
2613  GetTracePhysMap(face, faceids);
2614  // The static cast is necessary because faceids should be
2615  // Array<OneD, size_t> faceids ... or at leaste the same type as
2616  // faceids.size() ...
2617  Vmath::Gathr(static_cast<int>(faceids.size()), inarray, faceids, o_tmp);
2618 
2619  int to_id0, to_id1;
2620 
2622  {
2623  to_id0 = 0;
2624  to_id1 = 1;
2625  }
2626  else // transpose points key evaluation
2627  {
2628  to_id0 = 1;
2629  to_id1 = 0;
2630  }
2631 
2632  // interpolate to points distrbution given in FaceExp
2634  m_base[dir0]->GetPointsKey(), m_base[dir1]->GetPointsKey(), o_tmp.get(),
2635  FaceExp->GetBasis(to_id0)->GetPointsKey(),
2636  FaceExp->GetBasis(to_id1)->GetPointsKey(), o_tmp2.get());
2637 
2638  // Reshuffule points as required and put into outarray.
2639  v_ReOrientTracePhysMap(orient, faceids, nq0, nq1);
2640  Vmath::Scatr(nq0 * nq1, o_tmp2, faceids, outarray);
2641 }
2642 
2643 void Expansion3D::v_GenTraceExp(const int traceid, ExpansionSharedPtr &exp)
2644 {
2645  SpatialDomains::GeometrySharedPtr faceGeom = m_geom->GetFace(traceid);
2646  if (faceGeom->GetNumVerts() == 3)
2647  {
2649  GetTraceBasisKey(traceid, 0), GetTraceBasisKey(traceid, 1),
2650  m_geom->GetFace(traceid));
2651  }
2652  else
2653  {
2655  GetTraceBasisKey(traceid, 0), GetTraceBasisKey(traceid, 1),
2656  m_geom->GetFace(traceid));
2657  }
2658 }
2659 
2660 void Expansion3D::v_ReOrientTracePhysMap(const StdRegions::Orientation orient,
2661  Array<OneD, int> &idmap, const int nq0,
2662  const int nq1)
2663 {
2664 
2665  if (idmap.size() != nq0 * nq1)
2666  {
2667  idmap = Array<OneD, int>(nq0 * nq1);
2668  }
2669 
2670  if (GetNverts() == 3) // Tri face
2671  {
2672  switch (orient)
2673  {
2675  // eseentially straight copy
2676  for (int i = 0; i < nq0 * nq1; ++i)
2677  {
2678  idmap[i] = i;
2679  }
2680  break;
2682  // reverse
2683  for (int j = 0; j < nq1; ++j)
2684  {
2685  for (int i = 0; i < nq0; ++i)
2686  {
2687  idmap[j * nq0 + i] = nq0 - 1 - i + j * nq0;
2688  }
2689  }
2690  break;
2691  default:
2692  ASSERTL0(false,
2693  "Case not supposed to be used in this function");
2694  }
2695  }
2696  else
2697  {
2698  switch (orient)
2699  {
2701  // eseentially straight copy
2702  for (int i = 0; i < nq0 * nq1; ++i)
2703  {
2704  idmap[i] = i;
2705  }
2706  break;
2708  {
2709  // Direction A negative and B positive
2710  for (int j = 0; j < nq1; j++)
2711  {
2712  for (int i = 0; i < nq0; ++i)
2713  {
2714  idmap[j * nq0 + i] = nq0 - 1 - i + j * nq0;
2715  }
2716  }
2717  }
2718  break;
2720  {
2721  // Direction A positive and B negative
2722  for (int j = 0; j < nq1; j++)
2723  {
2724  for (int i = 0; i < nq0; ++i)
2725  {
2726  idmap[j * nq0 + i] = nq0 * (nq1 - 1 - j) + i;
2727  }
2728  }
2729  }
2730  break;
2732  {
2733  // Direction A negative and B negative
2734  for (int j = 0; j < nq1; j++)
2735  {
2736  for (int i = 0; i < nq0; ++i)
2737  {
2738  idmap[j * nq0 + i] = nq0 * nq1 - 1 - j * nq0 - i;
2739  }
2740  }
2741  }
2742  break;
2744  {
2745  // Transposed, Direction A and B positive
2746  for (int i = 0; i < nq0; ++i)
2747  {
2748  for (int j = 0; j < nq1; ++j)
2749  {
2750  idmap[i * nq1 + j] = i + j * nq0;
2751  }
2752  }
2753  }
2754  break;
2756  {
2757  // Transposed, Direction A positive and B negative
2758  for (int i = 0; i < nq0; ++i)
2759  {
2760  for (int j = 0; j < nq1; ++j)
2761  {
2762  idmap[i * nq1 + j] = nq0 - 1 - i + j * nq0;
2763  }
2764  }
2765  }
2766  break;
2768  {
2769  // Transposed, Direction A negative and B positive
2770  for (int i = 0; i < nq0; ++i)
2771  {
2772  for (int j = 0; j < nq1; ++j)
2773  {
2774  idmap[i * nq1 + j] = i + nq0 * (nq1 - 1) - j * nq0;
2775  }
2776  }
2777  }
2778  break;
2780  {
2781  // Transposed, Direction A and B negative
2782  for (int i = 0; i < nq0; ++i)
2783  {
2784  for (int j = 0; j < nq1; ++j)
2785  {
2786  idmap[i * nq1 + j] = nq0 * nq1 - 1 - i - j * nq0;
2787  }
2788  }
2789  }
2790  break;
2791  default:
2792  ASSERTL0(false, "Unknow orientation");
2793  break;
2794  }
2795  }
2796 }
2797 
2798 void Expansion3D::v_NormVectorIProductWRTBase(
2799  const Array<OneD, const Array<OneD, NekDouble>> &Fvec,
2800  Array<OneD, NekDouble> &outarray)
2801 {
2802  NormVectorIProductWRTBase(Fvec[0], Fvec[1], Fvec[2], outarray);
2803 }
2804 
2805 // Compute edgenormal \cdot vector
2806 Array<OneD, NekDouble> Expansion3D::GetnFacecdotMF(
2807  const int dir, const int face, ExpansionSharedPtr &FaceExp_f,
2808  const Array<OneD, const Array<OneD, NekDouble>> &normals,
2809  const StdRegions::VarCoeffMap &varcoeffs)
2810 {
2811  int nquad_f = FaceExp_f->GetNumPoints(0) * FaceExp_f->GetNumPoints(1);
2812  int coordim = GetCoordim();
2813 
2814  int nquad0 = m_base[0]->GetNumPoints();
2815  int nquad1 = m_base[1]->GetNumPoints();
2816  int nquad2 = m_base[2]->GetNumPoints();
2817  int nqtot = nquad0 * nquad1 * nquad2;
2818 
2819  StdRegions::VarCoeffType MMFCoeffs[15] = {
2828 
2829  StdRegions::VarCoeffMap::const_iterator MFdir;
2830 
2831  Array<OneD, NekDouble> nFacecdotMF(nqtot, 0.0);
2832  Array<OneD, NekDouble> tmp(nqtot);
2833  Array<OneD, NekDouble> tmp_f(nquad_f);
2834  for (int k = 0; k < coordim; k++)
2835  {
2836  MFdir = varcoeffs.find(MMFCoeffs[dir * 5 + k]);
2837  tmp = MFdir->second.GetValue();
2838 
2839  GetPhysFaceVarCoeffsFromElement(face, FaceExp_f, tmp, tmp_f);
2840 
2841  Vmath::Vvtvp(nquad_f, &tmp_f[0], 1, &normals[k][0], 1, &nFacecdotMF[0],
2842  1, &nFacecdotMF[0], 1);
2843  }
2844 
2845  return nFacecdotMF;
2846 }
2847 
2848 void Expansion3D::v_TraceNormLen(const int traceid, NekDouble &h, NekDouble &p)
2849 {
2850  SpatialDomains::GeometrySharedPtr geom = GetGeom();
2851 
2852  int nverts = geom->GetFace(traceid)->GetNumVerts();
2853 
2854  SpatialDomains::PointGeom tn1, tn2, normal;
2855  tn1.Sub(*(geom->GetFace(traceid)->GetVertex(1)),
2856  *(geom->GetFace(traceid)->GetVertex(0)));
2857 
2858  tn2.Sub(*(geom->GetFace(traceid)->GetVertex(nverts - 1)),
2859  *(geom->GetFace(traceid)->GetVertex(0)));
2860 
2861  normal.Mult(tn1, tn2);
2862 
2863  // normalise normal
2864  NekDouble mag = normal.dot(normal);
2865  mag = 1.0 / sqrt(mag);
2866  normal.UpdatePosition(normal.x() * mag, normal.y() * mag, normal.z() * mag);
2867 
2869  h = 0.0;
2870  p = 0.0;
2871  for (int i = 0; i < nverts; ++i)
2872  {
2873  // vertices on edges
2874  int edgid = geom->GetEdgeNormalToFaceVert(traceid, i);
2875 
2876  // vector along noramal edge to each vertex
2877  Dx.Sub(*(geom->GetEdge(edgid)->GetVertex(0)),
2878  *(geom->GetEdge(edgid)->GetVertex(1)));
2879 
2880  // calculate perpendicular distance of normal length
2881  // from first vertex
2882  h += fabs(normal.dot(Dx));
2883  }
2884 
2885  h /= static_cast<NekDouble>(nverts);
2886 
2887  // find normal basis direction
2888  int dir0 = geom->GetDir(traceid, 0);
2889  int dir1 = geom->GetDir(traceid, 1);
2890  int dirn;
2891  for (dirn = 0; dirn < 3; ++dirn)
2892  {
2893  if ((dirn != dir0) && (dirn != dir1))
2894  {
2895  break;
2896  }
2897  }
2898  p = (NekDouble)(GetBasisNumModes(dirn) - 1);
2899 }
2900 } // namespace LocalRegions
2901 } // namespace Nektar
#define ASSERTL0(condition, msg)
Definition: ErrorUtil.hpp:215
#define NEKERROR(type, msg)
Assert Level 0 – Fundamental assert which is used whether in FULLDEBUG, DEBUG or OPT compilation mode...
Definition: ErrorUtil.hpp:209
#define ASSERTL1(condition, msg)
Assert Level 1 – Debugging which is used whether in FULLDEBUG or DEBUG compilation mode....
Definition: ErrorUtil.hpp:249
#define ASSERTL2(condition, msg)
Assert Level 2 – Debugging which is used FULLDEBUG compilation mode. This level assert is designed to...
Definition: ErrorUtil.hpp:272
#define sign(a, b)
return the sign(b)*a
Definition: Polylib.cpp:49
Describes the specification for a Basis.
Definition: Basis.h:50
General purpose memory allocation routines with the ability to allocate from thread specific memory p...
boost::call_traits< DataType >::const_reference z() const
Definition: NekPoint.hpp:172
boost::call_traits< DataType >::const_reference x() const
Definition: NekPoint.hpp:160
boost::call_traits< DataType >::const_reference y() const
Definition: NekPoint.hpp:166
void Sub(PointGeom &a, PointGeom &b)
Definition: PointGeom.cpp:124
void Mult(PointGeom &a, PointGeom &b)
_this = a x b
Definition: PointGeom.cpp:133
NekDouble dot(PointGeom &a)
retun the dot product between this and input a
Definition: PointGeom.cpp:187
void UpdatePosition(NekDouble x, NekDouble y, NekDouble z)
Definition: PointGeom.cpp:107
const ConstFactorMap & GetConstFactors() const
Definition: StdMatrixKey.h:140
LibUtilities::ShapeType GetShapeType() const
Definition: StdMatrixKey.h:90
const VarCoeffMap & GetVarCoeffs() const
Definition: StdMatrixKey.h:171
MatrixType GetMatrixType() const
Definition: StdMatrixKey.h:85
bool HasVarCoeff(const StdRegions::VarCoeffType &coeff) const
Definition: StdMatrixKey.h:176
NekDouble GetConstFactor(const ConstFactorType &factor) const
Definition: StdMatrixKey.h:126
bool ConstFactorExists(const ConstFactorType &factor) const
Definition: StdMatrixKey.h:135
void Interp2D(const BasisKey &fbasis0, const BasisKey &fbasis1, const Array< OneD, const NekDouble > &from, const BasisKey &tbasis0, const BasisKey &tbasis1, Array< OneD, NekDouble > &to)
this function interpolates a 2D function evaluated at the quadrature points of the 2D basis,...
Definition: Interp.cpp:106
std::vector< PointsKey > PointsKeyVector
Definition: Points.h:250
std::shared_ptr< Expansion > ExpansionSharedPtr
Definition: Expansion.h:68
std::shared_ptr< IndexMapValues > IndexMapValuesSharedPtr
Definition: IndexMapKey.h:128
@ eNoGeomType
No type defined.
@ eDeformed
Geometry is curved or has non-constant factors.
std::shared_ptr< Geometry > GeometrySharedPtr
Definition: Geometry.h:53
std::shared_ptr< Geometry3D > Geometry3DSharedPtr
Definition: Geometry3D.h:52
std::shared_ptr< StdExpansion > StdExpansionSharedPtr
static ConstFactorMap NullConstFactorMap
Definition: StdRegions.hpp:400
std::map< StdRegions::VarCoeffType, VarCoeffEntry > VarCoeffMap
Definition: StdRegions.hpp:343
The above copyright notice and this permission notice shall be included.
Definition: CoupledSolver.h:2
std::shared_ptr< DNekScalMat > DNekScalMatSharedPtr
NekMatrix< InnerMatrixType, BlockMatrixTag > Transpose(NekMatrix< InnerMatrixType, BlockMatrixTag > &rhs)
std::shared_ptr< DNekScalBlkMat > DNekScalBlkMatSharedPtr
Definition: NekTypeDefs.hpp:79
static DNekMatSharedPtr NullDNekMatSharedPtr
Definition: NekTypeDefs.hpp:83
static Array< OneD, NekDouble > NullNekDouble1DArray
std::shared_ptr< DNekMat > DNekMatSharedPtr
Definition: NekTypeDefs.hpp:75
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:209
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:622
void Neg(int n, T *x, const int incx)
Negate x = -x.
Definition: Vmath.cpp:518
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:574
void Scatr(int n, const T *x, const int *y, T *z)
Scatter vector z[y[i]] = x[i].
Definition: Vmath.cpp:822
void Gathr(int n, const T *sign, const T *x, const int *y, T *z)
Gather vector z[i] = sign[i]*x[y[i]].
Definition: Vmath.cpp:805
void Zero(int n, T *x, const int incx)
Zero vector.
Definition: Vmath.cpp:492
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:1255
scalarT< T > sqrt(scalarT< T > in)
Definition: scalar.hpp:294