Nektar++
Expansion1D.cpp
Go to the documentation of this file.
1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 // File: Expansion1D.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 Expansion1D routines
32 //
33 ///////////////////////////////////////////////////////////////////////////////
34 
35 #include <boost/core/ignore_unused.hpp>
36 
39 
40 using namespace std;
41 
42 namespace Nektar
43 {
44 namespace LocalRegions
45 {
46 
47 DNekMatSharedPtr Expansion1D::v_GenMatrix(const StdRegions::StdMatrixKey &mkey)
48 {
49  DNekMatSharedPtr returnval;
50 
51  switch (mkey.GetMatrixType())
52  {
54  {
55  ASSERTL1(IsBoundaryInteriorExpansion(),
56  "HybridDGHelmholtz matrix not set up "
57  "for non boundary-interior expansions");
58  int i;
59  NekDouble lambdaval =
62  int ncoeffs = GetNcoeffs();
63 
64  int coordim = GetCoordim();
65 
66  DNekScalMat &invMass = *GetLocMatrix(StdRegions::eInvMass);
70  DNekMat LocMat(ncoeffs, ncoeffs);
71 
72  returnval =
74  DNekMat &Mat = *returnval;
75 
76  Vmath::Zero(ncoeffs * ncoeffs, Mat.GetPtr(), 1);
77 
78  for (i = 0; i < coordim; ++i)
79  {
80  DNekScalMat &Dmat = *GetLocMatrix(DerivType[i]);
81 
82  Mat = Mat + Dmat * invMass * Transpose(Dmat);
83  }
84 
85  // Add end Mass Matrix Contribution
86  DNekScalMat &Mass = *GetLocMatrix(StdRegions::eMass);
87  Mat = Mat + lambdaval * Mass;
88 
90  GetBoundaryMap(bmap);
91 
92  // Add tau*F_e using elemental mass matrices
93  for (i = 0; i < 2; ++i)
94  {
95  Mat(bmap[i], bmap[i]) = Mat(bmap[i], bmap[i]) + tau;
96  }
97  }
98  break;
100  {
101  int j, k;
102  int nbndry = NumDGBndryCoeffs();
103  int ncoeffs = GetNcoeffs();
105  factors[StdRegions::eFactorLambda] =
107  factors[StdRegions::eFactorTau] =
109 
110  Array<OneD, NekDouble> lambda(nbndry);
111  DNekVec Lambda(nbndry, lambda, eWrapper);
112  Array<OneD, NekDouble> ulam(ncoeffs);
113  DNekVec Ulam(ncoeffs, ulam, eWrapper);
114  Array<OneD, NekDouble> f(ncoeffs);
115  DNekVec F(ncoeffs, f, eWrapper);
116 
117  // declare matrix space
118  returnval =
120  DNekMat &Umat = *returnval;
121 
122  // Helmholtz matrix
123  DNekScalMat &invHmat =
124  *GetLocMatrix(StdRegions::eInvHybridDGHelmholtz, factors);
125 
126  // for each degree of freedom of the lambda space
127  // calculate Umat entry
128  // Generate Lambda to U_lambda matrix
129  for (j = 0; j < nbndry; ++j)
130  {
131  Vmath::Zero(nbndry, &lambda[0], 1);
132  Vmath::Zero(ncoeffs, &f[0], 1);
133  lambda[j] = 1.0;
134 
135  AddHDGHelmholtzTraceTerms(factors[StdRegions::eFactorTau],
136  lambda, f);
137 
138  Ulam = invHmat * F; // generate Ulam from lambda
139 
140  // fill column of matrix
141  for (k = 0; k < ncoeffs; ++k)
142  {
143  Umat(k, j) = Ulam[k];
144  }
145  }
146  }
147  break;
151  {
152  int j = 0;
153  int k = 0;
154  int dir = 0;
155  int nbndry = NumDGBndryCoeffs();
156  int ncoeffs = GetNcoeffs();
157 
158  Array<OneD, NekDouble> lambda(nbndry);
159  DNekVec Lambda(nbndry, lambda, eWrapper);
160 
161  Array<OneD, NekDouble> ulam(ncoeffs);
162  DNekVec Ulam(ncoeffs, ulam, eWrapper);
163  Array<OneD, NekDouble> f(ncoeffs);
164  DNekVec F(ncoeffs, f, eWrapper);
166  factors[StdRegions::eFactorLambda] =
168  factors[StdRegions::eFactorTau] =
170 
171  // declare matrix space
172  returnval =
174  DNekMat &Qmat = *returnval;
175 
176  // Lambda to U matrix
177  DNekScalMat &lamToU =
178  *GetLocMatrix(StdRegions::eHybridDGLamToU, factors);
179 
180  // Inverse mass matrix
181  DNekScalMat &invMass = *GetLocMatrix(StdRegions::eInvMass);
182 
183  // Weak Derivative matrix
185  switch (mkey.GetMatrixType())
186  {
188  dir = 0;
189  Dmat = GetLocMatrix(StdRegions::eWeakDeriv0);
190  break;
192  dir = 1;
193  Dmat = GetLocMatrix(StdRegions::eWeakDeriv1);
194  break;
196  dir = 2;
197  Dmat = GetLocMatrix(StdRegions::eWeakDeriv2);
198  break;
199  default:
200  ASSERTL0(false, "Direction not known");
201  break;
202  }
203 
204  // for each degree of freedom of the lambda space
205  // calculate Qmat entry
206  // Generate Lambda to Q_lambda matrix
207  for (j = 0; j < nbndry; ++j)
208  {
209  Vmath::Zero(nbndry, &lambda[0], 1);
210  lambda[j] = 1.0;
211 
212  // for lambda[j] = 1 this is the solution to ulam
213  for (k = 0; k < ncoeffs; ++k)
214  {
215  Ulam[k] = lamToU(k, j);
216  }
217 
218  // -D^T ulam
219  Vmath::Neg(ncoeffs, &ulam[0], 1);
220  F = Transpose(*Dmat) * Ulam;
221 
222  // + \tilde{G} \lambda
223  AddNormTraceInt(dir, lambda, f);
224 
225  // multiply by inverse mass matrix
226  Ulam = invMass * F;
227 
228  // fill column of matrix (Qmat is in column major format)
229  Vmath::Vcopy(ncoeffs, &ulam[0], 1,
230  &(Qmat.GetPtr())[0] + j * ncoeffs, 1);
231  }
232  }
233  break;
235  {
236  int j;
237  int nbndry = NumBndryCoeffs();
238 
240  factors[StdRegions::eFactorLambda] =
242  factors[StdRegions::eFactorTau] =
244 
246  Array<OneD, NekDouble> lam(2);
247  GetBoundaryMap(bmap);
248 
249  // declare matrix space
250  returnval =
252  DNekMat &BndMat = *returnval;
253 
254  // Matrix to map Lambda to U
255  DNekScalMat &LamToU =
256  *GetLocMatrix(StdRegions::eHybridDGLamToU, factors);
257 
258  // Matrix to map Lambda to Q
259  DNekScalMat &LamToQ =
260  *GetLocMatrix(StdRegions::eHybridDGLamToQ0, factors);
261 
262  lam[0] = 1.0;
263  lam[1] = 0.0;
264  for (j = 0; j < nbndry; ++j)
265  {
266  BndMat(0, j) =
267  -LamToQ(bmap[0], j) - factors[StdRegions::eFactorTau] *
268  (LamToU(bmap[0], j) - lam[j]);
269  }
270 
271  lam[0] = 0.0;
272  lam[1] = 1.0;
273  for (j = 0; j < nbndry; ++j)
274  {
275  BndMat(1, j) =
276  LamToQ(bmap[1], j) - factors[StdRegions::eFactorTau] *
277  (LamToU(bmap[1], j) - lam[j]);
278  }
279  }
280  break;
281  default:
282  ASSERTL0(false,
283  "This matrix type cannot be generated from this class");
284  break;
285  }
286 
287  return returnval;
288 }
289 
290 void Expansion1D::AddNormTraceInt(const int dir,
292  Array<OneD, NekDouble> &outarray)
293 {
294  boost::ignore_unused(dir);
295 
296  int k;
297  int nbndry = NumBndryCoeffs();
298  int nquad = GetNumPoints(0);
299  const Array<OneD, const NekDouble> &Basis = GetBasis(0)->GetBdata();
301 
302  GetBoundaryMap(vmap);
303 
304  // add G \lambda term (can assume G is diagonal since one
305  // of the basis is zero at boundary otherwise)
306  for (k = 0; k < nbndry; ++k)
307  {
308  outarray[vmap[k]] += (Basis[(vmap[k] + 1) * nquad - 1] *
309  Basis[(vmap[k] + 1) * nquad - 1] -
310  Basis[vmap[k] * nquad] * Basis[vmap[k] * nquad]) *
311  inarray[vmap[k]];
312  }
313 }
314 
315 void Expansion1D::AddHDGHelmholtzTraceTerms(
316  const NekDouble tau, const Array<OneD, const NekDouble> &inarray,
317  Array<OneD, NekDouble> &outarray)
318 {
319  int i, n;
320  int nbndry = NumBndryCoeffs();
321  int nquad = GetNumPoints(0);
322  int ncoeffs = GetNcoeffs();
323  int coordim = GetCoordim();
325 
326  ASSERTL0(&inarray[0] != &outarray[0],
327  "Input and output arrays use the same memory");
328 
329  const Array<OneD, const NekDouble> &Basis = GetBasis(0)->GetBdata();
330  DNekScalMat &invMass = *GetLocMatrix(StdRegions::eInvMass);
331 
332  GetBoundaryMap(vmap);
333 
334  // Add F = \tau <phi_i,phi_j> (note phi_i is zero if phi_j is non-zero)
335  for (i = 0; i < nbndry; ++i)
336  {
337  outarray[vmap[i]] += tau * Basis[(vmap[i] + 1) * nquad - 1] *
338  Basis[(vmap[i] + 1) * nquad - 1] *
339  inarray[vmap[i]];
340  outarray[vmap[i]] += tau * Basis[vmap[i] * nquad] *
341  Basis[vmap[i] * nquad] * inarray[vmap[i]];
342  }
343 
344  //===============================================================
345  // Add -\sum_i D_i^T M^{-1} G_i + E_i M^{-1} G_i =
346  // \sum_i D_i M^{-1} G_i term
347 
351  Array<OneD, NekDouble> tmpcoeff(ncoeffs, 0.0);
352  DNekVec Coeffs(ncoeffs, outarray, eWrapper);
353  DNekVec Tmpcoeff(ncoeffs, tmpcoeff, eWrapper);
354 
355  for (n = 0; n < coordim; ++n)
356  {
357  // evaluate M^{-1} G
358  for (i = 0; i < ncoeffs; ++i)
359  {
360  // lower boundary (negative normal)
361  tmpcoeff[i] -= invMass(i, vmap[0]) * Basis[vmap[0] * nquad] *
362  Basis[vmap[0] * nquad] * inarray[vmap[0]];
363 
364  // upper boundary (positive normal)
365  tmpcoeff[i] += invMass(i, vmap[1]) *
366  Basis[(vmap[1] + 1) * nquad - 1] *
367  Basis[(vmap[1] + 1) * nquad - 1] * inarray[vmap[1]];
368  }
369 
370  DNekScalMat &Dmat = *GetLocMatrix(DerivType[n]);
371  Coeffs = Coeffs + Dmat * Tmpcoeff;
372  }
373 }
374 
375 void Expansion1D::v_AddRobinMassMatrix(
376  const int vert, const Array<OneD, const NekDouble> &primCoeffs,
377  DNekMatSharedPtr &inoutmat)
378 {
379  ASSERTL0(IsBoundaryInteriorExpansion(),
380  "Robin boundary conditions are only implemented for "
381  "boundary-interior expanisons");
382  ASSERTL1(inoutmat->GetRows() == inoutmat->GetColumns(),
383  "Assuming that input matrix was square");
384 
385  // Get local Element mapping for vertex point
386  int map = GetVertexMap(vert);
387 
388  // Now need to identify a map which takes the local edge
389  // mass matrix to the matrix stored in inoutmat;
390  // This can currently be deduced from the size of the matrix
391  // - if inoutmat.m_rows() == v_NCoeffs() it is a full
392  // matrix system
393  // - if inoutmat.m_rows() == v_NumBndCoeffs() it is a
394  // boundary CG system
395 
396  int rows = inoutmat->GetRows();
397 
398  if (rows == GetNcoeffs())
399  {
400  // no need to do anything
401  }
402  else if (rows == NumBndryCoeffs()) // same as NumDGBndryCoeffs()
403  {
404  int i;
406  GetBoundaryMap(bmap);
407 
408  for (i = 0; i < 2; ++i)
409  {
410  if (map == bmap[i])
411  {
412  map = i;
413  break;
414  }
415  }
416  ASSERTL1(i != 2, "Did not find number in map");
417  }
418 
419  // assumes end points have unit magnitude
420  (*inoutmat)(map, map) += primCoeffs[0];
421 }
422 
423 /**
424  * Given an edge and vector of element coefficients:
425  * - maps those elemental coefficients corresponding to the trace into
426  * an vector.
427  * - update the element coefficients
428  * - multiplies the edge vector by the edge mass matrix
429  * - maps the edge coefficients back onto the elemental coefficients
430  */
431 void Expansion1D::v_AddRobinTraceContribution(
432  const int vert, const Array<OneD, const NekDouble> &primCoeffs,
433  const Array<OneD, NekDouble> &incoeffs, Array<OneD, NekDouble> &coeffs)
434 {
435  ASSERTL1(IsBoundaryInteriorExpansion(),
436  "Not set up for non boundary-interior expansions");
437 
438  int map = GetVertexMap(vert);
439  coeffs[map] += primCoeffs[0] * incoeffs[map];
440 }
441 
442 NekDouble Expansion1D::v_VectorFlux(
443  const Array<OneD, Array<OneD, NekDouble>> &vec)
444 {
446  GetLeftAdjacentElementExp()->GetTraceNormal(
447  GetLeftAdjacentElementTrace());
448 
449  int nq = m_base[0]->GetNumPoints();
450  Array<OneD, NekDouble> Fn(nq);
451  Vmath::Vmul(nq, &vec[0][0], 1, &normals[0][0], 1, &Fn[0], 1);
452  Vmath::Vvtvp(nq, &vec[1][0], 1, &normals[1][0], 1, &Fn[0], 1, &Fn[0], 1);
453 
454  return Integral(Fn);
455 }
456 
457 /** @brief: This method gets all of the factors which are
458  required as part of the Gradient Jump Penalty
459  stabilisation and involves the product of the normal and
460  geometric factors along the element trace.
461 */
462 void Expansion1D::v_NormalTraceDerivFactors(
463  Array<OneD, Array<OneD, NekDouble>> &factors,
464  Array<OneD, Array<OneD, NekDouble>> &d0factors,
465  Array<OneD, Array<OneD, NekDouble>> &d1factors)
466 {
467  boost::ignore_unused(d0factors, d1factors); // for 2D&3D shapes
468  int nquad = GetNumPoints(0);
470  m_metricinfo->GetDerivFactors(GetPointsKeys());
471 
472  if (factors.size() <= 2)
473  {
475  factors[0] = Array<OneD, NekDouble>(1);
476  factors[1] = Array<OneD, NekDouble>(1);
477  }
478 
479  // Outwards normal
481  GetTraceNormal(0);
483  GetTraceNormal(1);
484 
485  if (m_metricinfo->GetGtype() == SpatialDomains::eDeformed)
486  {
487  factors[0][0] = gmat[0][nquad - 1] * normal_0[0][0];
488  factors[1][0] = gmat[0][0] * normal_1[0][0];
489 
490  for (int n = 1; n < normal_0.size(); ++n)
491  {
492  factors[0][0] += gmat[n][0] * normal_0[n][0];
493  factors[1][0] += gmat[n][nquad - 1] * normal_1[n][0];
494  }
495  }
496  else
497  {
498  factors[0][0] = gmat[0][0] * normal_0[0][0];
499  factors[1][0] = gmat[0][0] * normal_1[0][0];
500 
501  for (int n = 1; n < normal_0.size(); ++n)
502  {
503  factors[0][0] += gmat[n][0] * normal_0[n][0];
504  factors[1][0] += gmat[n][0] * normal_1[n][0];
505  }
506  }
507 }
508 
509 void Expansion1D::v_ReOrientTracePhysMap(const StdRegions::Orientation orient,
510  Array<OneD, int> &idmap, const int nq0,
511  const int nq1)
512 {
513  boost::ignore_unused(orient, nq0, nq1);
514 
515  if (idmap.size() != 1)
516  {
517  idmap = Array<OneD, int>(1);
518  }
519 
520  idmap[0] = 0;
521 }
522 
523 void Expansion1D::v_TraceNormLen(const int traceid, NekDouble &h, NekDouble &p)
524 {
525  boost::ignore_unused(traceid);
526  h = GetGeom()->GetVertex(1)->dist(*GetGeom()->GetVertex(0));
527  p = m_ncoeffs - 1;
528 }
529 
530 } // namespace LocalRegions
531 } // namespace Nektar
#define ASSERTL0(condition, msg)
Definition: ErrorUtil.hpp:215
#define ASSERTL1(condition, msg)
Assert Level 1 – Debugging which is used whether in FULLDEBUG or DEBUG compilation mode....
Definition: ErrorUtil.hpp:249
Represents a basis of a given type.
Definition: Basis.h:213
const Array< OneD, const NekDouble > & GetBdata() const
Return basis definition array m_bdata.
Definition: Basis.h:316
General purpose memory allocation routines with the ability to allocate from thread specific memory p...
MatrixType GetMatrixType() const
Definition: StdMatrixKey.h:85
NekDouble GetConstFactor(const ConstFactorType &factor) const
Definition: StdMatrixKey.h:126
@ eDeformed
Geometry is curved or has non-constant factors.
std::map< ConstFactorType, NekDouble > ConstFactorMap
Definition: StdRegions.hpp:399
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< 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 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 Zero(int n, T *x, const int incx)
Zero vector.
Definition: Vmath.cpp:492
void Vcopy(int n, const T *x, const int incx, T *y, const int incy)
Definition: Vmath.cpp:1255