Nektar++
PreconditionerLowEnergy.cpp
Go to the documentation of this file.
1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 // File: PreconditionerLowEnergy.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: PreconditionerLowEnergy definition
32 //
33 ///////////////////////////////////////////////////////////////////////////////
34 
36 #include <LocalRegions/MatrixKey.h>
41 #include <cmath>
42 
43 using namespace std;
44 
45 namespace Nektar
46 {
47 using namespace LibUtilities;
48 
49 namespace MultiRegions
50 {
51 /**
52  * Registers the class with the Factory.
53  */
54 string PreconditionerLowEnergy::className =
55  GetPreconFactory().RegisterCreatorFunction("LowEnergyBlock",
56  PreconditionerLowEnergy::create,
57  "LowEnergy Preconditioning");
58 
59 /**
60  * @class PreconditionerLowEnergy
61  *
62  * This class implements low energy preconditioning for the conjugate
63  * gradient matrix solver.
64  */
65 
66 PreconditionerLowEnergy::PreconditionerLowEnergy(
67  const std::shared_ptr<GlobalLinSys> &plinsys,
68  const AssemblyMapSharedPtr &pLocToGloMap)
69  : Preconditioner(plinsys, pLocToGloMap)
70 {
71 }
72 
74 {
75  GlobalSysSolnType solvertype = m_locToGloMap.lock()->GetGlobalSysSolnType();
76 
77  ASSERTL0(solvertype == eIterativeStaticCond ||
78  solvertype == ePETScStaticCond,
79  "Solver type not valid");
80 
81  std::shared_ptr<MultiRegions::ExpList> expList =
82  ((m_linsys.lock())->GetLocMat()).lock();
83 
84  m_comm = expList->GetComm();
85 
87 
88  locExpansion = expList->GetExp(0);
89 
90  int nDim = locExpansion->GetShapeDimension();
91 
92  ASSERTL0(nDim == 3, "Preconditioner type only valid in 3D");
93 
94  // Set up block transformation matrix
96 
97  // Sets up variable p mask
99 }
100 
101 /**
102  * \brief Construct the low energy preconditioner from
103  * \f$\mathbf{S}_{2}\f$
104  *
105  * \f[\mathbf{M}^{-1}=\left[\begin{array}{ccc}
106  * Diag[(\mathbf{S_{2}})_{vv}] & & \\ & (\mathbf{S}_{2})_{eb} & \\ & &
107  * (\mathbf{S}_{2})_{fb} \end{array}\right] \f]
108  *
109  * where \f$\mathbf{R}\f$ is the transformation matrix and
110  * \f$\mathbf{S}_{2}\f$ the Schur complement of the modified basis,
111  * given by
112  *
113  * \f[\mathbf{S}_{2}=\mathbf{R}\mathbf{S}_{1}\mathbf{R}^{T}\f]
114  *
115  * where \f$\mathbf{S}_{1}\f$ is the local schur complement matrix for
116  * each element.
117  */
119 {
120  std::shared_ptr<MultiRegions::ExpList> expList =
121  ((m_linsys.lock())->GetLocMat()).lock();
123  GlobalLinSysKey linSysKey = (m_linsys.lock())->GetKey();
124 
125  int i, j, k;
126  int nVerts, nEdges, nFaces;
127  int eid, fid, n, cnt, nmodes, nedgemodes, nfacemodes;
128  int nedgemodesloc;
129  NekDouble zero = 0.0;
130 
131  int vMap1, vMap2, sign1, sign2;
132  int m, v, eMap1, eMap2, fMap1, fMap2;
133  int offset, globalrow, globalcol, nCoeffs;
134 
135  // Periodic information
136  PeriodicMap periodicVerts;
137  PeriodicMap periodicEdges;
138  PeriodicMap periodicFaces;
139  expList->GetPeriodicEntities(periodicVerts, periodicEdges, periodicFaces);
140 
141  // matrix storage
142  MatrixStorage storage = eFULL;
143  MatrixStorage vertstorage = eDIAGONAL;
144  MatrixStorage blkmatStorage = eDIAGONAL;
145 
146  // local element static condensed matrices
147  DNekScalBlkMatSharedPtr loc_mat;
148  DNekScalMatSharedPtr bnd_mat;
149 
150  DNekMatSharedPtr pRSRT;
151 
152  DNekMat RS;
153  DNekMat RSRT;
154 
155  auto asmMap = m_locToGloMap.lock();
156 
157  int nDirBnd = asmMap->GetNumGlobalDirBndCoeffs();
158  int nNonDirVerts = asmMap->GetNumNonDirVertexModes();
159 
160  // Vertex, edge and face preconditioner matrices
162  nNonDirVerts, nNonDirVerts, zero, vertstorage);
163 
164  Array<OneD, NekDouble> vertArray(nNonDirVerts, 0.0);
165  Array<OneD, long> VertBlockToUniversalMap(nNonDirVerts, -1);
166 
167  // maps for different element types
168  int n_exp = expList->GetNumElmts();
169  int nNonDirEdgeIDs = asmMap->GetNumNonDirEdges();
170  int nNonDirFaceIDs = asmMap->GetNumNonDirFaces();
171 
172  set<int> edgeDirMap;
173  set<int> faceDirMap;
174  map<int, int> uniqueEdgeMap;
175  map<int, int> uniqueFaceMap;
176 
177  // this should be of size total number of local edges + faces
178  Array<OneD, int> modeoffset(1 + nNonDirEdgeIDs + nNonDirFaceIDs, 0);
179  Array<OneD, int> globaloffset(1 + nNonDirEdgeIDs + nNonDirFaceIDs, 0);
180 
181  const Array<OneD, const ExpListSharedPtr> &bndCondExp =
182  expList->GetBndCondExpansions();
183  LocalRegions::Expansion2DSharedPtr bndCondFaceExp;
185  &bndConditions = expList->GetBndConditions();
186 
187  int meshVertId;
188  int meshEdgeId;
189  int meshFaceId;
190 
191  const Array<OneD, const int> &extradiredges = asmMap->GetExtraDirEdges();
192  for (i = 0; i < extradiredges.size(); ++i)
193  {
194  meshEdgeId = extradiredges[i];
195  edgeDirMap.insert(meshEdgeId);
196  }
197 
198  // Determine which boundary edges and faces have dirichlet values
199  for (i = 0; i < bndCondExp.size(); i++)
200  {
201  cnt = 0;
202  for (j = 0; j < bndCondExp[i]->GetNumElmts(); j++)
203  {
204  bndCondFaceExp =
205  std::dynamic_pointer_cast<LocalRegions::Expansion2D>(
206  bndCondExp[i]->GetExp(j));
207  if (bndConditions[i]->GetBoundaryConditionType() ==
209  {
210  for (k = 0; k < bndCondFaceExp->GetNtraces(); k++)
211  {
212  meshEdgeId = bndCondFaceExp->GetGeom()->GetEid(k);
213  if (edgeDirMap.count(meshEdgeId) == 0)
214  {
215  edgeDirMap.insert(meshEdgeId);
216  }
217  }
218  meshFaceId = bndCondFaceExp->GetGeom()->GetGlobalID();
219  faceDirMap.insert(meshFaceId);
220  }
221  }
222  }
223 
224  int dof = 0;
225  int maxFaceDof = 0;
226  int maxEdgeDof = 0;
227  int nlocalNonDirEdges = 0;
228  int nlocalNonDirFaces = 0;
229  int ntotalentries = 0;
230 
231  map<int, int> EdgeSize;
232  map<int, int> FaceSize;
233  map<int, pair<int, int>> FaceModes;
234 
235  /// - Count edges, face and add up min edges and min face sizes
236  for (n = 0; n < n_exp; ++n)
237  {
238  locExpansion = expList->GetExp(n)->as<LocalRegions::Expansion3D>();
239 
240  nEdges = locExpansion->GetNedges();
241  for (j = 0; j < nEdges; ++j)
242  {
243  int nEdgeInteriorCoeffs = locExpansion->GetEdgeNcoeffs(j) - 2;
244  meshEdgeId = locExpansion->as<LocalRegions::Expansion3D>()
245  ->GetGeom3D()
246  ->GetEid(j);
247  if (EdgeSize.count(meshEdgeId) == 0)
248  {
249  EdgeSize[meshEdgeId] = nEdgeInteriorCoeffs;
250  }
251  else
252  {
253  EdgeSize[meshEdgeId] =
254  min(EdgeSize[meshEdgeId], nEdgeInteriorCoeffs);
255  }
256  }
257 
258  nFaces = locExpansion->GetNtraces();
259  for (j = 0; j < nFaces; ++j)
260  {
261  int nFaceInteriorCoeffs = locExpansion->GetTraceIntNcoeffs(j);
262  meshFaceId = locExpansion->GetGeom3D()->GetFid(j);
263 
264  if (FaceSize.count(meshFaceId) == 0)
265  {
266  FaceSize[meshFaceId] = nFaceInteriorCoeffs;
267 
268  int m0, m1;
269  locExpansion->GetTraceNumModes(j, m0, m1,
270  locExpansion->GetTraceOrient(j));
271  FaceModes[meshFaceId] = pair<int, int>(m0, m1);
272  }
273  else
274  {
275  if (nFaceInteriorCoeffs < FaceSize[meshFaceId])
276  {
277  FaceSize[meshFaceId] = nFaceInteriorCoeffs;
278  int m0, m1;
279  locExpansion->GetTraceNumModes(
280  j, m0, m1, locExpansion->GetTraceOrient(j));
281  FaceModes[meshFaceId] = pair<int, int>(m0, m1);
282  }
283  }
284  }
285  }
286 
287  bool verbose = expList->GetSession()->DefinesCmdLineArgument("verbose");
288 
289  // For parallel runs need to check have minimum of edges and faces over
290  // partition boundaries
291  if (m_comm->GetSize() > 1)
292  {
293  int EdgeSizeLen = EdgeSize.size();
294  int FaceSizeLen = FaceSize.size();
295  Array<OneD, long> FacetMap(EdgeSizeLen + FaceSizeLen, -1);
296  Array<OneD, NekDouble> FacetLen(EdgeSizeLen + FaceSizeLen, -1);
297 
298  map<int, int>::iterator it;
299 
300  cnt = 0;
301  int maxid = 0;
302  for (it = EdgeSize.begin(); it != EdgeSize.end(); ++it, ++cnt)
303  {
304  FacetMap[cnt] = it->first;
305  maxid = max(it->first, maxid);
306  FacetLen[cnt] = it->second;
307  }
308  maxid++;
309 
310  m_comm->AllReduce(maxid, ReduceMax);
311 
312  for (it = FaceSize.begin(); it != FaceSize.end(); ++it, ++cnt)
313  {
314  FacetMap[cnt] = it->first + maxid;
315  FacetLen[cnt] = it->second;
316  }
317 
318  // Exchange vertex data over different processes
319  Gs::gs_data *tmp = Gs::Init(FacetMap, m_comm, verbose);
320  Gs::Gather(FacetLen, Gs::gs_min, tmp);
321 
322  cnt = 0;
323  for (it = EdgeSize.begin(); it != EdgeSize.end(); ++it, ++cnt)
324  {
325  it->second = (int)FacetLen[cnt];
326  }
327 
328  for (it = FaceSize.begin(); it != FaceSize.end(); ++it, ++cnt)
329  {
330  it->second = (int)FacetLen[cnt];
331  }
332  }
333 
334  // Loop over all the elements in the domain and compute total edge
335  // DOF and set up unique ordering.
336  map<int, int> nblks;
337  int matrixlocation = 0;
338 
339  // First do periodic edges
340  for (auto &pIt : periodicEdges)
341  {
342  meshEdgeId = pIt.first;
343 
344  if (edgeDirMap.count(meshEdgeId) == 0)
345  {
346  dof = EdgeSize[meshEdgeId];
347  if (uniqueEdgeMap.count(meshEdgeId) == 0 && dof > 0)
348  {
349  bool SetUpNewEdge = true;
350 
351  for (i = 0; i < pIt.second.size(); ++i)
352  {
353  if (!pIt.second[i].isLocal)
354  {
355  continue;
356  }
357 
358  int meshEdgeId2 = pIt.second[i].id;
359  if (edgeDirMap.count(meshEdgeId2) == 0)
360  {
361  if (uniqueEdgeMap.count(meshEdgeId2) != 0)
362  {
363  // set unique map to same location
364  uniqueEdgeMap[meshEdgeId] =
365  uniqueEdgeMap[meshEdgeId2];
366  SetUpNewEdge = false;
367  }
368  }
369  else
370  {
371  edgeDirMap.insert(meshEdgeId);
372  SetUpNewEdge = false;
373  }
374  }
375 
376  if (SetUpNewEdge)
377  {
378  uniqueEdgeMap[meshEdgeId] = matrixlocation;
379  globaloffset[matrixlocation] += ntotalentries;
380  modeoffset[matrixlocation] = dof * dof;
381  ntotalentries += dof * dof;
382  nblks[matrixlocation++] = dof;
383  }
384  }
385  }
386  }
387 
388  for (cnt = n = 0; n < n_exp; ++n)
389  {
390  locExpansion = expList->GetExp(n)->as<LocalRegions::Expansion3D>();
391 
392  for (j = 0; j < locExpansion->GetNedges(); ++j)
393  {
394  meshEdgeId = locExpansion->GetGeom()->GetEid(j);
395  dof = EdgeSize[meshEdgeId];
396  maxEdgeDof = (dof > maxEdgeDof ? dof : maxEdgeDof);
397 
398  if (edgeDirMap.count(meshEdgeId) == 0)
399  {
400  if (uniqueEdgeMap.count(meshEdgeId) == 0 && dof > 0)
401 
402  {
403  uniqueEdgeMap[meshEdgeId] = matrixlocation;
404 
405  globaloffset[matrixlocation] += ntotalentries;
406  modeoffset[matrixlocation] = dof * dof;
407  ntotalentries += dof * dof;
408  nblks[matrixlocation++] = dof;
409  }
410  nlocalNonDirEdges += dof * dof;
411  }
412  }
413  }
414 
415  // Loop over all the elements in the domain and compute max face
416  // DOF. Reduce across all processes to get universal maximum.
417  // - Periodic faces
418  for (auto &pIt : periodicFaces)
419  {
420  meshFaceId = pIt.first;
421 
422  if (faceDirMap.count(meshFaceId) == 0)
423  {
424  dof = FaceSize[meshFaceId];
425 
426  if (uniqueFaceMap.count(meshFaceId) == 0 && dof > 0)
427  {
428  bool SetUpNewFace = true;
429 
430  if (pIt.second[0].isLocal)
431  {
432  int meshFaceId2 = pIt.second[0].id;
433 
434  if (faceDirMap.count(meshFaceId2) == 0)
435  {
436  if (uniqueFaceMap.count(meshFaceId2) != 0)
437  {
438  // set unique map to same location
439  uniqueFaceMap[meshFaceId] =
440  uniqueFaceMap[meshFaceId2];
441  SetUpNewFace = false;
442  }
443  }
444  else // set face to be a Dirichlet face
445  {
446  faceDirMap.insert(meshFaceId);
447  SetUpNewFace = false;
448  }
449  }
450 
451  if (SetUpNewFace)
452  {
453  uniqueFaceMap[meshFaceId] = matrixlocation;
454 
455  modeoffset[matrixlocation] = dof * dof;
456  globaloffset[matrixlocation] += ntotalentries;
457  ntotalentries += dof * dof;
458  nblks[matrixlocation++] = dof;
459  }
460  }
461  }
462  }
463 
464  for (cnt = n = 0; n < n_exp; ++n)
465  {
466  locExpansion = expList->GetExp(n)->as<LocalRegions::Expansion3D>();
467 
468  for (j = 0; j < locExpansion->GetNtraces(); ++j)
469  {
470  meshFaceId = locExpansion->GetGeom()->GetFid(j);
471 
472  dof = FaceSize[meshFaceId];
473  maxFaceDof = (dof > maxFaceDof ? dof : maxFaceDof);
474 
475  if (faceDirMap.count(meshFaceId) == 0)
476  {
477  if (uniqueFaceMap.count(meshFaceId) == 0 && dof > 0)
478  {
479  uniqueFaceMap[meshFaceId] = matrixlocation;
480  modeoffset[matrixlocation] = dof * dof;
481  globaloffset[matrixlocation] += ntotalentries;
482  ntotalentries += dof * dof;
483  nblks[matrixlocation++] = dof;
484  }
485  nlocalNonDirFaces += dof * dof;
486  }
487  }
488  }
489 
490  m_comm->AllReduce(maxEdgeDof, ReduceMax);
491  m_comm->AllReduce(maxFaceDof, ReduceMax);
492 
493  // Allocate arrays for block to universal map (number of expansions * p^2)
494  Array<OneD, long> BlockToUniversalMap(ntotalentries, -1);
495  Array<OneD, int> localToGlobalMatrixMap(
496  nlocalNonDirEdges + nlocalNonDirFaces, -1);
497 
498  // Allocate arrays to store matrices (number of expansions * p^2)
499  Array<OneD, NekDouble> BlockArray(nlocalNonDirEdges + nlocalNonDirFaces,
500  0.0);
501 
502  int matrixoffset = 0;
503  int vGlobal;
504  int uniEdgeOffset = 0;
505 
506  // Need to obtain a fixed offset for the universal number
507  // of the faces which come after the edge numbering
508  for (n = 0; n < n_exp; ++n)
509  {
510  for (j = 0; j < locExpansion->GetNedges(); ++j)
511  {
512  meshEdgeId = locExpansion->as<LocalRegions::Expansion3D>()
513  ->GetGeom3D()
514  ->GetEid(j);
515 
516  uniEdgeOffset = max(meshEdgeId, uniEdgeOffset);
517  }
518  }
519  uniEdgeOffset++;
520 
521  m_comm->AllReduce(uniEdgeOffset, ReduceMax);
522  uniEdgeOffset = uniEdgeOffset * maxEdgeDof * maxEdgeDof;
523 
524  for (n = 0; n < n_exp; ++n)
525  {
526  locExpansion = expList->GetExp(n)->as<LocalRegions::Expansion3D>();
527 
528  // loop over the edges of the expansion
529  for (j = 0; j < locExpansion->GetNedges(); ++j)
530  {
531  // get mesh edge id
532  meshEdgeId = locExpansion->GetGeom()->GetEid(j);
533 
534  nedgemodes = EdgeSize[meshEdgeId];
535 
536  if (edgeDirMap.count(meshEdgeId) == 0 && nedgemodes > 0)
537  {
538  // Determine the Global edge offset
539  int edgeOffset = globaloffset[uniqueEdgeMap[meshEdgeId]];
540 
541  // Determine a universal map offset
542  int uniOffset = meshEdgeId;
543  auto pIt = periodicEdges.find(meshEdgeId);
544  if (pIt != periodicEdges.end())
545  {
546  for (int l = 0; l < pIt->second.size(); ++l)
547  {
548  uniOffset = min(uniOffset, pIt->second[l].id);
549  }
550  }
551  uniOffset = uniOffset * maxEdgeDof * maxEdgeDof;
552 
553  for (k = 0; k < nedgemodes * nedgemodes; ++k)
554  {
555  vGlobal = edgeOffset + k;
556  localToGlobalMatrixMap[matrixoffset + k] = vGlobal;
557  BlockToUniversalMap[vGlobal] = uniOffset + k + 1;
558  }
559  matrixoffset += nedgemodes * nedgemodes;
560  }
561  }
562 
563  Array<OneD, unsigned int> faceInteriorMap;
564  Array<OneD, int> faceInteriorSign;
565  // loop over the faces of the expansion
566  for (j = 0; j < locExpansion->GetNtraces(); ++j)
567  {
568  // get mesh face id
569  meshFaceId = locExpansion->GetGeom()->GetFid(j);
570 
571  nfacemodes = FaceSize[meshFaceId];
572 
573  // Check if face has dirichlet values
574  if (faceDirMap.count(meshFaceId) == 0 && nfacemodes > 0)
575  {
576  // Determine the Global edge offset
577  int faceOffset = globaloffset[uniqueFaceMap[meshFaceId]];
578  // Determine a universal map offset
579  int uniOffset = meshFaceId;
580  // use minimum face edge when periodic
581  auto pIt = periodicFaces.find(meshFaceId);
582  if (pIt != periodicFaces.end())
583  {
584  uniOffset = min(uniOffset, pIt->second[0].id);
585  }
586  uniOffset = uniOffset * maxFaceDof * maxFaceDof;
587 
588  for (k = 0; k < nfacemodes * nfacemodes; ++k)
589  {
590  vGlobal = faceOffset + k;
591 
592  localToGlobalMatrixMap[matrixoffset + k] = vGlobal;
593 
594  BlockToUniversalMap[vGlobal] =
595  uniOffset + uniEdgeOffset + k + 1;
596  }
597  matrixoffset += nfacemodes * nfacemodes;
598  }
599  }
600  }
601 
602  matrixoffset = 0;
603 
604  map<int, int>::iterator it;
605  Array<OneD, unsigned int> n_blks(nblks.size() + 1);
606  n_blks[0] = nNonDirVerts;
607  for (i = 1, it = nblks.begin(); it != nblks.end(); ++it)
608  {
609  n_blks[i++] = it->second;
610  }
611 
613  blkmatStorage);
614 
615  // Here we loop over the expansion and build the block low energy
616  // preconditioner as well as the block versions of the transformation
617  // matrices.
618  for (cnt = n = 0; n < n_exp; ++n)
619  {
620  locExpansion = expList->GetExp(n)->as<LocalRegions::Expansion3D>();
621  nCoeffs = locExpansion->NumBndryCoeffs();
622 
623  // Get correct transformation matrix for element type
624  DNekMat &R = (*m_RBlk->GetBlock(n, n));
625 
626  pRSRT = MemoryManager<DNekMat>::AllocateSharedPtr(nCoeffs, nCoeffs,
627  zero, storage);
628  RSRT = (*pRSRT);
629 
630  nVerts = locExpansion->GetGeom()->GetNumVerts();
631  nEdges = locExpansion->GetGeom()->GetNumEdges();
632  nFaces = locExpansion->GetGeom()->GetNumFaces();
633 
634  // Get statically condensed matrix
635  loc_mat = (m_linsys.lock())->GetStaticCondBlock(n);
636 
637  // Extract boundary block (elemental S1)
638  bnd_mat = loc_mat->GetBlock(0, 0);
639 
640  // offset by number of rows
641  offset = bnd_mat->GetRows();
642 
643  DNekScalMat &S = (*bnd_mat);
644 
645  DNekMat Sloc(nCoeffs, nCoeffs);
646 
647  // For variable p we need to just use the active modes
648  NekDouble val;
649 
650  for (int i = 0; i < nCoeffs; ++i)
651  {
652  for (int j = 0; j < nCoeffs; ++j)
653  {
654  val = S(i, j) * m_variablePmask[cnt + i] *
655  m_variablePmask[cnt + j];
656  Sloc.SetValue(i, j, val);
657  }
658  }
659 
660  // Calculate R*S*trans(R)
661  RSRT = R * Sloc * Transpose(R);
662 
663  // loop over vertices of the element and return the vertex map
664  // for each vertex
665  for (v = 0; v < nVerts; ++v)
666  {
667  vMap1 = locExpansion->GetVertexMap(v);
668 
669  // Get vertex map
670  globalrow = asmMap->GetLocalToGlobalBndMap(cnt + vMap1) - nDirBnd;
671 
672  if (globalrow >= 0)
673  {
674  for (m = 0; m < nVerts; ++m)
675  {
676  vMap2 = locExpansion->GetVertexMap(m);
677 
678  // global matrix location (without offset due to
679  // dirichlet values)
680  globalcol =
681  asmMap->GetLocalToGlobalBndMap(cnt + vMap2) - nDirBnd;
682 
683  // offset for dirichlet conditions
684  if (globalcol == globalrow)
685  {
686  // modal connectivity between elements
687  sign1 = asmMap->GetLocalToGlobalBndSign(cnt + vMap1);
688  sign2 = asmMap->GetLocalToGlobalBndSign(cnt + vMap2);
689 
690  vertArray[globalrow] +=
691  sign1 * sign2 * RSRT(vMap1, vMap2);
692 
693  meshVertId = locExpansion->GetGeom()->GetVid(v);
694 
695  auto pIt = periodicVerts.find(meshVertId);
696  if (pIt != periodicVerts.end())
697  {
698  for (k = 0; k < pIt->second.size(); ++k)
699  {
700  meshVertId = min(meshVertId, pIt->second[k].id);
701  }
702  }
703 
704  VertBlockToUniversalMap[globalrow] = meshVertId + 1;
705  }
706  }
707  }
708  }
709 
710  // loop over edges of the element and return the edge map
711  for (eid = 0; eid < nEdges; ++eid)
712  {
713 
714  meshEdgeId = locExpansion->as<LocalRegions::Expansion3D>()
715  ->GetGeom3D()
716  ->GetEid(eid);
717 
718  nedgemodes = EdgeSize[meshEdgeId];
719  if (nedgemodes)
720  {
721  nedgemodesloc = locExpansion->GetEdgeNcoeffs(eid) - 2;
722  DNekMatSharedPtr m_locMat =
724  nedgemodes, nedgemodes, zero, storage);
725 
726  Array<OneD, unsigned int> edgemodearray =
727  locExpansion->GetEdgeInverseBoundaryMap(eid);
728 
729  if (edgeDirMap.count(meshEdgeId) == 0)
730  {
731  for (v = 0; v < nedgemodesloc; ++v)
732  {
733  eMap1 = edgemodearray[v];
734  sign1 = asmMap->GetLocalToGlobalBndSign(cnt + eMap1);
735 
736  if (sign1 == 0)
737  {
738  continue;
739  }
740 
741  for (m = 0; m < nedgemodesloc; ++m)
742  {
743  eMap2 = edgemodearray[m];
744 
745  // modal connectivity between elements
746  sign2 =
747  asmMap->GetLocalToGlobalBndSign(cnt + eMap2);
748 
749  NekDouble globalEdgeValue =
750  sign1 * sign2 * RSRT(eMap1, eMap2);
751 
752  if (sign2 != 0)
753  {
754  // if(eMap1 == eMap2)
755  BlockArray[matrixoffset + v * nedgemodes + m] =
756  globalEdgeValue;
757  }
758  }
759  }
760  matrixoffset += nedgemodes * nedgemodes;
761  }
762  }
763  }
764 
765  // loop over faces of the element and return the face map
766  for (fid = 0; fid < nFaces; ++fid)
767  {
768  meshFaceId = locExpansion->as<LocalRegions::Expansion3D>()
769  ->GetGeom3D()
770  ->GetFid(fid);
771 
772  nfacemodes = FaceSize[meshFaceId];
773  if (nfacemodes > 0)
774  {
775  DNekMatSharedPtr m_locMat =
777  nfacemodes, nfacemodes, zero, storage);
778 
779  if (faceDirMap.count(meshFaceId) == 0)
780  {
781  Array<OneD, unsigned int> facemodearray;
782  StdRegions::Orientation faceOrient =
783  locExpansion->GetTraceOrient(fid);
784 
785  auto pIt = periodicFaces.find(meshFaceId);
786  if (pIt != periodicFaces.end())
787  {
788  if (meshFaceId == min(meshFaceId, pIt->second[0].id))
789  {
790  faceOrient = DeterminePeriodicFaceOrient(
791  faceOrient, pIt->second[0].orient);
792  }
793  }
794 
795  facemodearray = locExpansion->GetTraceInverseBoundaryMap(
796  fid, faceOrient, FaceModes[meshFaceId].first,
797  FaceModes[meshFaceId].second);
798 
799  for (v = 0; v < nfacemodes; ++v)
800  {
801  fMap1 = facemodearray[v];
802 
803  sign1 = asmMap->GetLocalToGlobalBndSign(cnt + fMap1);
804 
805  ASSERTL1(sign1 != 0,
806  "Something is wrong since we "
807  "shoudl only be extracting modes for "
808  "lowest order expansion");
809 
810  for (m = 0; m < nfacemodes; ++m)
811  {
812  fMap2 = facemodearray[m];
813 
814  // modal connectivity between elements
815  sign2 =
816  asmMap->GetLocalToGlobalBndSign(cnt + fMap2);
817 
818  ASSERTL1(sign2 != 0,
819  "Something is wrong since "
820  "we shoudl only be extracting modes for "
821  "lowest order expansion");
822 
823  // Get the face-face value from the
824  // low energy matrix (S2)
825  NekDouble globalFaceValue =
826  sign1 * sign2 * RSRT(fMap1, fMap2);
827 
828  // local face value to global face value
829  // if(fMap1 == fMap2)
830  BlockArray[matrixoffset + v * nfacemodes + m] =
831  globalFaceValue;
832  }
833  }
834  matrixoffset += nfacemodes * nfacemodes;
835  }
836  }
837  }
838 
839  // offset for the expansion
840  cnt += nCoeffs;
841  }
842 
843  if (nNonDirVerts != 0)
844  {
845  // Exchange vertex data over different processes
846  Gs::gs_data *tmp = Gs::Init(VertBlockToUniversalMap, m_comm, verbose);
847  Gs::Gather(vertArray, Gs::gs_add, tmp);
848  }
849 
850  Array<OneD, NekDouble> GlobalBlock(ntotalentries, 0.0);
851  if (ntotalentries)
852  {
853  // Assemble edge matrices of each process
854  Vmath::Assmb(BlockArray.size(), BlockArray, localToGlobalMatrixMap,
855  GlobalBlock);
856  }
857 
858  // Exchange edge & face data over different processes
859  Gs::gs_data *tmp1 = Gs::Init(BlockToUniversalMap, m_comm, verbose);
860  Gs::Gather(GlobalBlock, Gs::gs_add, tmp1);
861 
862  // Populate vertex block
863  for (int i = 0; i < nNonDirVerts; ++i)
864  {
865  VertBlk->SetValue(i, i, 1.0 / vertArray[i]);
866  }
867 
868  // Set the first block to be the diagonal of the vertex space
869  m_BlkMat->SetBlock(0, 0, VertBlk);
870 
871  // Build the edge and face matrices from the vector
872  DNekMatSharedPtr gmat;
873 
874  offset = 0;
875  // -1 since we ignore vert block
876  for (int loc = 0; loc < n_blks.size() - 1; ++loc)
877  {
878  nmodes = n_blks[1 + loc];
879  gmat = MemoryManager<DNekMat>::AllocateSharedPtr(nmodes, nmodes, zero,
880  storage);
881 
882  for (v = 0; v < nmodes; ++v)
883  {
884  for (m = 0; m < nmodes; ++m)
885  {
886  NekDouble Value = GlobalBlock[offset + v * nmodes + m];
887  gmat->SetValue(v, m, Value);
888  }
889  }
890  m_BlkMat->SetBlock(1 + loc, 1 + loc, gmat);
891  offset += modeoffset[loc];
892  }
893 
894  // invert blocks.
895  int totblks = m_BlkMat->GetNumberOfBlockRows();
896  for (i = 1; i < totblks; ++i)
897  {
898  unsigned int nmodes = m_BlkMat->GetNumberOfRowsInBlockRow(i);
899  if (nmodes)
900  {
901  DNekMatSharedPtr tmp_mat =
902  MemoryManager<DNekMat>::AllocateSharedPtr(nmodes, nmodes, zero,
903  storage);
904 
905  tmp_mat = m_BlkMat->GetBlock(i, i);
906  tmp_mat->Invert();
907 
908  m_BlkMat->SetBlock(i, i, tmp_mat);
909  }
910  }
911 }
912 
913 /**
914  * Apply the low energy preconditioner during the conjugate gradient
915  * routine
916  */
918  const Array<OneD, NekDouble> &pInput, Array<OneD, NekDouble> &pOutput)
919 {
920  int nDir = m_locToGloMap.lock()->GetNumGlobalDirBndCoeffs();
921  int nGlobal = m_locToGloMap.lock()->GetNumGlobalBndCoeffs();
922  int nNonDir = nGlobal - nDir;
923  DNekBlkMat &M = (*m_BlkMat);
924 
925  NekVector<NekDouble> r(nNonDir, pInput, eWrapper);
926  NekVector<NekDouble> z(nNonDir, pOutput, eWrapper);
927 
928  z = M * r;
929 }
930 
931 /**
932  * Set a block transformation matrices for each element type. These are
933  * needed in routines that transform the schur complement matrix to and
934  * from the low energy basis.
935  */
937 {
938  std::shared_ptr<MultiRegions::ExpList> expList =
939  ((m_linsys.lock())->GetLocMat()).lock();
942  map<int, int> EdgeSize;
943 
944  int n;
945 
946  std::map<ShapeType, DNekScalMatSharedPtr> maxRmat;
947  map<ShapeType, LocalRegions::Expansion3DSharedPtr> maxElmt;
948  map<ShapeType, Array<OneD, unsigned int>> vertMapMaxR;
949  map<ShapeType, Array<OneD, Array<OneD, unsigned int>>> edgeMapMaxR;
950 
951  // Sets up reference element and builds transformation matrix for
952  // maximum polynomial order meshes
953  SetUpReferenceElements(maxRmat, maxElmt, vertMapMaxR, edgeMapMaxR);
954 
955  const Array<OneD, const unsigned int> &nbdry_size =
956  m_locToGloMap.lock()->GetNumLocalBndCoeffsPerPatch();
957 
958  int n_exp = expList->GetNumElmts();
959 
960  MatrixStorage blkmatStorage = eDIAGONAL;
961 
962  // Variants of R matrices required for low energy preconditioning
964  nbdry_size, nbdry_size, blkmatStorage);
966  nbdry_size, nbdry_size, blkmatStorage);
967 
968  DNekMatSharedPtr rmat, invrmat;
969 
970  int offset = 0;
971 
972  // Set up transformation matrices whilst checking to see if
973  // consecutive matrices are the same and if so reuse the
974  // matrices and store how many consecutive offsets there
975  // are
976  for (n = 0; n < n_exp; ++n)
977  {
978  locExp = expList->GetExp(n)->as<LocalRegions::Expansion3D>();
979 
980  ShapeType eltype = locExp->DetShapeType();
981 
982  int nbndcoeffs = locExp->NumBndryCoeffs();
983 
984  if (m_sameBlock.size() == 0)
985  {
986  rmat = ExtractLocMat(locExp, maxRmat[eltype], maxElmt[eltype],
987  vertMapMaxR[eltype], edgeMapMaxR[eltype]);
988  // Block R matrix
989  m_RBlk->SetBlock(n, n, rmat);
990 
992  invrmat->Invert();
993 
994  // Block inverse R matrix
995  m_InvRBlk->SetBlock(n, n, invrmat);
996 
997  m_sameBlock.push_back(pair<int, int>(1, nbndcoeffs));
998  locExpSav = locExp;
999  }
1000  else
1001  {
1002  bool reuse = true;
1003 
1004  // check to see if same as previous matrix and
1005  // reuse if we can
1006  for (int i = 0; i < 3; ++i)
1007  {
1008  if (locExpSav->GetBasis(i) != locExp->GetBasis(i))
1009  {
1010  reuse = false;
1011  break;
1012  }
1013  }
1014 
1015  if (reuse)
1016  {
1017  m_RBlk->SetBlock(n, n, rmat);
1018  m_InvRBlk->SetBlock(n, n, invrmat);
1019 
1020  m_sameBlock[offset] =
1021  (pair<int, int>(m_sameBlock[offset].first + 1, nbndcoeffs));
1022  }
1023  else
1024  {
1025  rmat = ExtractLocMat(locExp, maxRmat[eltype], maxElmt[eltype],
1026  vertMapMaxR[eltype], edgeMapMaxR[eltype]);
1027 
1028  // Block R matrix
1029  m_RBlk->SetBlock(n, n, rmat);
1030 
1032  invrmat->Invert();
1033  // Block inverse R matrix
1034  m_InvRBlk->SetBlock(n, n, invrmat);
1035 
1036  m_sameBlock.push_back(pair<int, int>(1, nbndcoeffs));
1037  offset++;
1038  locExpSav = locExp;
1039  }
1040  }
1041  }
1042 }
1043 
1044 /**
1045  * \brief Transform the basis vector to low energy space
1046  *
1047  * As the conjugate gradient system is solved for the low energy basis,
1048  * the solution vector \f$\mathbf{x}\f$ must be transformed to the low
1049  * energy basis i.e. \f$\overline{\mathbf{x}}=\mathbf{R}\mathbf{x}\f$.
1050  */
1052  Array<OneD, NekDouble> &pInOut)
1053 {
1054  int nLocBndDofs = m_locToGloMap.lock()->GetNumLocalBndCoeffs();
1055 
1056  // Block transformation matrix
1057  DNekBlkMat &R = *m_RBlk;
1058 
1059  Array<OneD, NekDouble> pLocalIn(nLocBndDofs, pInOut.get());
1060 
1061  // Apply mask in case of variable P
1062  Vmath::Vmul(nLocBndDofs, pLocalIn, 1, m_variablePmask, 1, pLocalIn, 1);
1063 
1064  // Multiply by the block transformation matrix
1065  int cnt = 0;
1066  int cnt1 = 0;
1067  for (int i = 0; i < m_sameBlock.size(); ++i)
1068  {
1069  int nexp = m_sameBlock[i].first;
1070  int nbndcoeffs = m_sameBlock[i].second;
1071  Blas::Dgemm('N', 'N', nbndcoeffs, nexp, nbndcoeffs, 1.0,
1072  &(R.GetBlock(cnt1, cnt1)->GetPtr()[0]), nbndcoeffs,
1073  pLocalIn.get() + cnt, nbndcoeffs, 0.0, pInOut.get() + cnt,
1074  nbndcoeffs);
1075  cnt += nbndcoeffs * nexp;
1076  cnt1 += nexp;
1077  }
1078 }
1079 
1080 /**
1081  * \brief transform the solution coeffiicents from low energy
1082  * back to the original coefficient space.
1083  *
1084  * After the conjugate gradient routine the output vector is in the low
1085  * energy basis and must be trasnformed back to the original basis in
1086  * order to get the correct solution out. the solution vector
1087  * i.e. \f$\mathbf{x}=\mathbf{R^{T}}\mathbf{\overline{x}}\f$.
1088  */
1090  Array<OneD, NekDouble> &pInOut)
1091 {
1092  int nLocBndDofs = m_locToGloMap.lock()->GetNumLocalBndCoeffs();
1093 
1094  ASSERTL1(pInOut.size() >= nLocBndDofs,
1095  "Output array is not greater than the nLocBndDofs");
1096 
1097  // Block transposed transformation matrix
1098  DNekBlkMat &R = *m_RBlk;
1099 
1100  Array<OneD, NekDouble> pLocalIn(nLocBndDofs, pInOut.get());
1101 
1102  // Multiply by the transpose of block transformation matrix
1103  int cnt = 0;
1104  int cnt1 = 0;
1105  for (int i = 0; i < m_sameBlock.size(); ++i)
1106  {
1107  int nexp = m_sameBlock[i].first;
1108  int nbndcoeffs = m_sameBlock[i].second;
1109  Blas::Dgemm('T', 'N', nbndcoeffs, nexp, nbndcoeffs, 1.0,
1110  &(R.GetBlock(cnt1, cnt1)->GetPtr()[0]), nbndcoeffs,
1111  pLocalIn.get() + cnt, nbndcoeffs, 0.0, pInOut.get() + cnt,
1112  nbndcoeffs);
1113  cnt += nbndcoeffs * nexp;
1114  cnt1 += nexp;
1115  }
1116 
1117  Vmath::Vmul(nLocBndDofs, pInOut, 1, m_variablePmask, 1, pInOut, 1);
1118 }
1119 
1120 /**
1121  * \brief Multiply by the block inverse transformation matrix
1122  * This transforms the bassi from Low Energy to original basis
1123  *
1124  * Note; not typically required
1125  */
1126 
1128  const Array<OneD, NekDouble> &pInput, Array<OneD, NekDouble> &pOutput)
1129 {
1130  int nLocBndDofs = m_locToGloMap.lock()->GetNumLocalBndCoeffs();
1131 
1132  ASSERTL1(pInput.size() >= nLocBndDofs,
1133  "Input array is smaller than nLocBndDofs");
1134  ASSERTL1(pOutput.size() >= nLocBndDofs,
1135  "Output array is smaller than nLocBndDofs");
1136 
1137  // Block inverse transformation matrix
1138  DNekBlkMat &invR = *m_InvRBlk;
1139 
1140  Array<OneD, NekDouble> pLocalIn(nLocBndDofs, pInput.get());
1141 
1142  // Multiply by the inverse transformation matrix
1143  int cnt = 0;
1144  int cnt1 = 0;
1145  for (int i = 0; i < m_sameBlock.size(); ++i)
1146  {
1147  int nexp = m_sameBlock[i].first;
1148  int nbndcoeffs = m_sameBlock[i].second;
1149  Blas::Dgemm('N', 'N', nbndcoeffs, nexp, nbndcoeffs, 1.0,
1150  &(invR.GetBlock(cnt1, cnt1)->GetPtr()[0]), nbndcoeffs,
1151  pLocalIn.get() + cnt, nbndcoeffs, 0.0, pOutput.get() + cnt,
1152  nbndcoeffs);
1153  cnt += nbndcoeffs * nexp;
1154  cnt1 += nexp;
1155  }
1156 }
1157 
1158 /**
1159  * \brief Multiply by the block tranposed inverse
1160  * transformation matrix (R^T)^{-1} which is equivlaent to
1161  * transforming coefficients to LowEnergy space
1162  *
1163  * In JCP 2001 paper on low energy this is seen as (C^T)^{-1}
1164  */
1166  const Array<OneD, NekDouble> &pInput, Array<OneD, NekDouble> &pOutput)
1167 {
1168  int nLocBndDofs = m_locToGloMap.lock()->GetNumLocalBndCoeffs();
1169 
1170  ASSERTL1(pInput.size() >= nLocBndDofs,
1171  "Input array is less than nLocBndDofs");
1172  ASSERTL1(pOutput.size() >= nLocBndDofs,
1173  "Output array is less than nLocBndDofs");
1174 
1175  // Block inverse transformation matrix
1176  DNekBlkMat &invR = *m_InvRBlk;
1177 
1178  Array<OneD, NekDouble> pLocalIn(nLocBndDofs, pInput.get());
1179 
1180  // Multiply by the transpose of block transformation matrix
1181  int cnt = 0;
1182  int cnt1 = 0;
1183  for (int i = 0; i < m_sameBlock.size(); ++i)
1184  {
1185  int nexp = m_sameBlock[i].first;
1186  int nbndcoeffs = m_sameBlock[i].second;
1187  Blas::Dgemm('T', 'N', nbndcoeffs, nexp, nbndcoeffs, 1.0,
1188  &(invR.GetBlock(cnt1, cnt1)->GetPtr()[0]), nbndcoeffs,
1189  pLocalIn.get() + cnt, nbndcoeffs, 0.0, pOutput.get() + cnt,
1190  nbndcoeffs);
1191  cnt += nbndcoeffs * nexp;
1192  cnt1 += nexp;
1193  }
1194 }
1195 
1196 /**
1197  * \brief Set up the transformed block matrix system
1198  *
1199  * Sets up a block elemental matrix in which each of the block matrix is
1200  * the low energy equivalent
1201  * i.e. \f$\mathbf{S}_{2}=\mathbf{R}\mathbf{S}_{1}\mathbf{R}^{T}\f$
1202  */
1204  int n, int bndoffset, const std::shared_ptr<DNekScalMat> &loc_mat)
1205 {
1206  std::shared_ptr<MultiRegions::ExpList> expList =
1207  ((m_linsys.lock())->GetLocMat()).lock();
1208 
1209  LocalRegions::ExpansionSharedPtr locExpansion;
1210  locExpansion = expList->GetExp(n);
1211  unsigned int nbnd = locExpansion->NumBndryCoeffs();
1212 
1213  MatrixStorage storage = eFULL;
1214  DNekMatSharedPtr pS2 =
1215  MemoryManager<DNekMat>::AllocateSharedPtr(nbnd, nbnd, 0.0, storage);
1216 
1217  // transformation matrices
1218  DNekMat &R = (*m_RBlk->GetBlock(n, n));
1219 
1220  // Original Schur Complement
1221  DNekScalMat &S1 = (*loc_mat);
1222 
1223  DNekMat Sloc(nbnd, nbnd);
1224 
1225  // For variable p we need to just use the active modes
1226  NekDouble val;
1227 
1228  for (int i = 0; i < nbnd; ++i)
1229  {
1230  for (int j = 0; j < nbnd; ++j)
1231  {
1232  val = S1(i, j) * m_variablePmask[bndoffset + i] *
1233  m_variablePmask[bndoffset + j];
1234  Sloc.SetValue(i, j, val);
1235  }
1236  }
1237 
1238  // create low energy matrix
1239  DNekMat &S2 = (*pS2);
1240 
1241  S2 = R * Sloc * Transpose(R);
1242 
1243  DNekScalMatSharedPtr return_val;
1244  return_val = MemoryManager<DNekScalMat>::AllocateSharedPtr(1.0, pS2);
1245 
1246  return return_val;
1247 }
1248 
1249 /**
1250  * Create the inverse multiplicity map.
1251  */
1253 {
1254  unsigned int nLocBnd = m_locToGloMap.lock()->GetNumLocalBndCoeffs();
1255  unsigned int i;
1256  auto asmMap = m_locToGloMap.lock();
1257 
1259  asmMap->GetLocalToGlobalBndSign();
1260 
1261  m_signChange = asmMap->GetSignChange();
1262 
1263  // Construct a map of 1/multiplicity
1265  for (i = 0; i < nLocBnd; ++i)
1266  {
1267  if (m_signChange)
1268  {
1269  m_variablePmask[i] = fabs(sign[i]);
1270  }
1271  else
1272  {
1273  m_variablePmask[i] = 1.0;
1274  }
1275  }
1276 }
1277 
1278 /**
1279  *\brief Sets up the reference prismatic element needed to construct
1280  *a low energy basis
1281  */
1283 {
1284  //////////////////////////
1285  // Set up Prism element //
1286  //////////////////////////
1287 
1288  const int three = 3;
1289  const int nVerts = 6;
1290  const double point[][3] = {
1291  {-1, -1, 0},
1292  {1, -1, 0},
1293  {1, 1, 0},
1294  {-1, 1, 0},
1295  {0, -1, sqrt(double(3))},
1296  {0, 1, sqrt(double(3))},
1297  };
1298 
1299  // std::shared_ptr<SpatialDomains::PointGeom> verts[6];
1301  for (int i = 0; i < nVerts; ++i)
1302  {
1304  three, i, point[i][0], point[i][1], point[i][2]);
1305  }
1306  const int nEdges = 9;
1307  const int vertexConnectivity[][2] = {{0, 1}, {1, 2}, {3, 2}, {0, 3}, {0, 4},
1308  {1, 4}, {2, 5}, {3, 5}, {4, 5}};
1309 
1310  // Populate the list of edges
1311  SpatialDomains::SegGeomSharedPtr edges[nEdges];
1312  for (int i = 0; i < nEdges; ++i)
1313  {
1314  SpatialDomains::PointGeomSharedPtr vertsArray[2];
1315  for (int j = 0; j < 2; ++j)
1316  {
1317  vertsArray[j] = verts[vertexConnectivity[i][j]];
1318  }
1320  i, three, vertsArray);
1321  }
1322 
1323  ////////////////////////
1324  // Set up Prism faces //
1325  ////////////////////////
1326 
1327  const int nFaces = 5;
1328  // quad-edge connectivity base-face0, vertical-quadface2, vertical-quadface4
1329  const int quadEdgeConnectivity[][4] = {
1330  {0, 1, 2, 3}, {1, 6, 8, 5}, {3, 7, 8, 4}};
1331  // QuadId ordered as 0, 1, 2, otherwise return false
1332  const int quadId[] = {0, -1, 1, -1, 2};
1333 
1334  // triangle-edge connectivity side-triface-1, side triface-3
1335  const int triEdgeConnectivity[][3] = {{0, 5, 4}, {2, 6, 7}};
1336  // TriId ordered as 0, 1, otherwise return false
1337  const int triId[] = {-1, 0, -1, 1, -1};
1338 
1339  // Populate the list of faces
1341  for (int f = 0; f < nFaces; ++f)
1342  {
1343  if (f == 1 || f == 3)
1344  {
1345  int i = triId[f];
1346  SpatialDomains::SegGeomSharedPtr edgeArray[3];
1347  for (int j = 0; j < 3; ++j)
1348  {
1349  edgeArray[j] = edges[triEdgeConnectivity[i][j]];
1350  }
1351  faces[f] =
1353  f, edgeArray);
1354  }
1355  else
1356  {
1357  int i = quadId[f];
1358  SpatialDomains::SegGeomSharedPtr edgeArray[4];
1359  for (int j = 0; j < 4; ++j)
1360  {
1361  edgeArray[j] = edges[quadEdgeConnectivity[i][j]];
1362  }
1363  faces[f] =
1365  f, edgeArray);
1366  }
1367  }
1368 
1371 
1372  return geom;
1373 }
1374 
1375 /**
1376  *\brief Sets up the reference prismatic element needed to construct
1377  *a low energy basis mapping arrays
1378  */
1380 {
1381  //////////////////////////
1382  // Set up Pyramid element //
1383  //////////////////////////
1384 
1385  const int nVerts = 5;
1386  const double point[][3] = {{-1, -1, 0},
1387  {1, -1, 0},
1388  {1, 1, 0},
1389  {-1, 1, 0},
1390  {0, 0, sqrt(double(2))}};
1391 
1392  // boost::shared_ptr<SpatialDomains::PointGeom> verts[6];
1393  const int three = 3;
1395  for (int i = 0; i < nVerts; ++i)
1396  {
1398  three, i, point[i][0], point[i][1], point[i][2]);
1399  }
1400  const int nEdges = 8;
1401  const int vertexConnectivity[][2] = {{0, 1}, {1, 2}, {2, 3}, {3, 0},
1402  {0, 4}, {1, 4}, {2, 4}, {3, 4}};
1403 
1404  // Populate the list of edges
1405  SpatialDomains::SegGeomSharedPtr edges[nEdges];
1406  for (int i = 0; i < nEdges; ++i)
1407  {
1408  SpatialDomains::PointGeomSharedPtr vertsArray[2];
1409  for (int j = 0; j < 2; ++j)
1410  {
1411  vertsArray[j] = verts[vertexConnectivity[i][j]];
1412  }
1414  i, three, vertsArray);
1415  }
1416 
1417  ////////////////////////
1418  // Set up Pyramid faces //
1419  ////////////////////////
1420 
1421  const int nFaces = 5;
1422  // quad-edge connectivity base-face0,
1423  const int quadEdgeConnectivity[][4] = {{0, 1, 2, 3}};
1424 
1425  // triangle-edge connectivity side-triface-1, side triface-2
1426  const int triEdgeConnectivity[][3] = {
1427  {0, 5, 4}, {1, 6, 5}, {2, 7, 6}, {3, 4, 7}};
1428 
1429  // Populate the list of faces
1431  for (int f = 0; f < nFaces; ++f)
1432  {
1433  if (f == 0)
1434  {
1435  SpatialDomains::SegGeomSharedPtr edgeArray[4];
1436  for (int j = 0; j < 4; ++j)
1437  {
1438  edgeArray[j] = edges[quadEdgeConnectivity[f][j]];
1439  }
1440 
1441  faces[f] =
1443  f, edgeArray);
1444  }
1445  else
1446  {
1447  int i = f - 1;
1448  SpatialDomains::SegGeomSharedPtr edgeArray[3];
1449  for (int j = 0; j < 3; ++j)
1450  {
1451  edgeArray[j] = edges[triEdgeConnectivity[i][j]];
1452  }
1453  faces[f] =
1455  f, edgeArray);
1456  }
1457  }
1458 
1461 
1462  return geom;
1463 }
1464 
1465 /**
1466  *\brief Sets up the reference tretrahedral element needed to construct
1467  *a low energy basis
1468  */
1470 {
1471  /////////////////////////////////
1472  // Set up Tetrahedron vertices //
1473  /////////////////////////////////
1474 
1475  int i, j;
1476  const int three = 3;
1477  const int nVerts = 4;
1478  const double point[][3] = {{-1, -1 / sqrt(double(3)), -1 / sqrt(double(6))},
1479  {1, -1 / sqrt(double(3)), -1 / sqrt(double(6))},
1480  {0, 2 / sqrt(double(3)), -1 / sqrt(double(6))},
1481  {0, 0, 3 / sqrt(double(6))}};
1482 
1483  std::shared_ptr<SpatialDomains::PointGeom> verts[4];
1484  for (i = 0; i < nVerts; ++i)
1485  {
1487  three, i, point[i][0], point[i][1], point[i][2]);
1488  }
1489 
1490  //////////////////////////////
1491  // Set up Tetrahedron Edges //
1492  //////////////////////////////
1493 
1494  // SegGeom (int id, const int coordim), EdgeComponent(id, coordim)
1495  const int nEdges = 6;
1496  const int vertexConnectivity[][2] = {{0, 1}, {1, 2}, {0, 2},
1497  {0, 3}, {1, 3}, {2, 3}};
1498 
1499  // Populate the list of edges
1500  SpatialDomains::SegGeomSharedPtr edges[nEdges];
1501  for (i = 0; i < nEdges; ++i)
1502  {
1503  std::shared_ptr<SpatialDomains::PointGeom> vertsArray[2];
1504  for (j = 0; j < 2; ++j)
1505  {
1506  vertsArray[j] = verts[vertexConnectivity[i][j]];
1507  }
1508 
1510  i, three, vertsArray);
1511  }
1512 
1513  //////////////////////////////
1514  // Set up Tetrahedron faces //
1515  //////////////////////////////
1516 
1517  const int nFaces = 4;
1518  const int edgeConnectivity[][3] = {
1519  {0, 1, 2}, {0, 4, 3}, {1, 5, 4}, {2, 5, 3}};
1520 
1521  // Populate the list of faces
1522  SpatialDomains::TriGeomSharedPtr faces[nFaces];
1523  for (i = 0; i < nFaces; ++i)
1524  {
1525  SpatialDomains::SegGeomSharedPtr edgeArray[3];
1526  for (j = 0; j < 3; ++j)
1527  {
1528  edgeArray[j] = edges[edgeConnectivity[i][j]];
1529  }
1530 
1532  i, edgeArray);
1533  }
1534 
1537 
1538  return geom;
1539 }
1540 
1541 /**
1542  *\brief Sets up the reference hexahedral element needed to construct
1543  *a low energy basis
1544  */
1546 {
1547  ////////////////////////////////
1548  // Set up Hexahedron vertices //
1549  ////////////////////////////////
1550 
1551  const int three = 3;
1552 
1553  const int nVerts = 8;
1554  const double point[][3] = {{0, 0, 0}, {1, 0, 0}, {1, 1, 0}, {0, 1, 0},
1555  {0, 0, 1}, {1, 0, 1}, {1, 1, 1}, {0, 1, 1}};
1556 
1557  // Populate the list of verts
1559  for (int i = 0; i < nVerts; ++i)
1560  {
1562  three, i, point[i][0], point[i][1], point[i][2]);
1563  }
1564 
1565  /////////////////////////////
1566  // Set up Hexahedron Edges //
1567  /////////////////////////////
1568 
1569  // SegGeom (int id, const int coordim), EdgeComponent(id, coordim)
1570  const int nEdges = 12;
1571  const int vertexConnectivity[][2] = {{0, 1}, {1, 2}, {2, 3}, {0, 3},
1572  {0, 4}, {1, 5}, {2, 6}, {3, 7},
1573  {4, 5}, {5, 6}, {6, 7}, {4, 7}};
1574 
1575  // Populate the list of edges
1576  SpatialDomains::SegGeomSharedPtr edges[nEdges];
1577  for (int i = 0; i < nEdges; ++i)
1578  {
1579  SpatialDomains::PointGeomSharedPtr vertsArray[2];
1580  for (int j = 0; j < 2; ++j)
1581  {
1582  vertsArray[j] = verts[vertexConnectivity[i][j]];
1583  }
1585  i, three, vertsArray);
1586  }
1587 
1588  /////////////////////////////
1589  // Set up Hexahedron faces //
1590  /////////////////////////////
1591 
1592  const int nFaces = 6;
1593  const int edgeConnectivity[][4] = {{0, 1, 2, 3}, {0, 5, 8, 4},
1594  {1, 6, 9, 5}, {2, 7, 10, 6},
1595  {3, 7, 11, 4}, {8, 9, 10, 11}};
1596 
1597  // Populate the list of faces
1598  SpatialDomains::QuadGeomSharedPtr faces[nFaces];
1599  for (int i = 0; i < nFaces; ++i)
1600  {
1601  SpatialDomains::SegGeomSharedPtr edgeArray[4];
1602  for (int j = 0; j < 4; ++j)
1603  {
1604  edgeArray[j] = edges[edgeConnectivity[i][j]];
1605  }
1607  i, edgeArray);
1608  }
1609 
1612 
1613  return geom;
1614 }
1615 
1616 /**
1617  * \brief Loop expansion and determine different variants of the
1618  * transformation matrix
1619  *
1620  * Sets up multiple reference elements based on the element expansion.
1621  */
1623  std::map<ShapeType, DNekScalMatSharedPtr> &maxRmat,
1624  map<ShapeType, LocalRegions::Expansion3DSharedPtr> &maxElmt,
1625  map<ShapeType, Array<OneD, unsigned int>> &vertMapMaxR,
1626  map<ShapeType, Array<OneD, Array<OneD, unsigned int>>> &edgeMapMaxR)
1627 {
1628 
1629  std::shared_ptr<MultiRegions::ExpList> expList =
1630  ((m_linsys.lock())->GetLocMat()).lock();
1631  GlobalLinSysKey linSysKey = (m_linsys.lock())->GetKey();
1632 
1634 
1635  // face maps for pyramid and hybrid meshes - not need to return.
1636  map<ShapeType, Array<OneD, Array<OneD, unsigned int>>> faceMapMaxR;
1637 
1638  /* Determine the maximum expansion order for all elements */
1639  int nummodesmax = 0;
1641 
1642  for (int n = 0; n < expList->GetNumElmts(); ++n)
1643  {
1644  locExp = expList->GetExp(n);
1645 
1646  nummodesmax = max(nummodesmax, locExp->GetBasisNumModes(0));
1647  nummodesmax = max(nummodesmax, locExp->GetBasisNumModes(1));
1648  nummodesmax = max(nummodesmax, locExp->GetBasisNumModes(2));
1649 
1650  Shapes[locExp->DetShapeType()] = 1;
1651  }
1652 
1653  m_comm->AllReduce(nummodesmax, ReduceMax);
1654  m_comm->AllReduce(Shapes, ReduceMax);
1655 
1656  if (Shapes[ePyramid] || Shapes[ePrism]) // if Pyramids or Prisms used then
1657  // need Tet and Hex expansion
1658  {
1659  Shapes[eTetrahedron] = 1;
1660  Shapes[eHexahedron] = 1;
1661  }
1662 
1663  StdRegions::MatrixType PreconR;
1664  if (linSysKey.GetMatrixType() == StdRegions::eMass)
1665  {
1666  PreconR = StdRegions::ePreconRMass;
1667  }
1668  else
1669  {
1670  PreconR = StdRegions::ePreconR;
1671  }
1672 
1676 
1677  /*
1678  * Set up a transformation matrices for equal max order
1679  * polynomial meshes
1680  */
1681 
1682  if (Shapes[eHexahedron])
1683  {
1685  // Bases for Hex element
1686  const BasisKey HexBa(eModified_A, nummodesmax,
1687  PointsKey(nummodesmax + 1, eGaussLobattoLegendre));
1688  const BasisKey HexBb(eModified_A, nummodesmax,
1689  PointsKey(nummodesmax + 1, eGaussLobattoLegendre));
1690  const BasisKey HexBc(eModified_A, nummodesmax,
1691  PointsKey(nummodesmax + 1, eGaussLobattoLegendre));
1692 
1693  // Create reference Hexahdedral expansion
1695 
1697  HexBa, HexBb, HexBc, hexgeom);
1698 
1699  maxElmt[eHexahedron] = HexExp;
1700 
1701  // Hex:
1702  HexExp->GetInverseBoundaryMaps(vmap, emap, fmap);
1703  vertMapMaxR[eHexahedron] = vmap;
1704  edgeMapMaxR[eHexahedron] = emap;
1705  faceMapMaxR[eHexahedron] = fmap;
1706 
1707  // Get hexahedral transformation matrix
1708  LocalRegions::MatrixKey HexR(PreconR, eHexahedron, *HexExp,
1709  linSysKey.GetConstFactors());
1710  maxRmat[eHexahedron] = HexExp->GetLocMatrix(HexR);
1711  }
1712 
1713  if (Shapes[eTetrahedron])
1714  {
1716  // Bases for Tetrahedral element
1717  const BasisKey TetBa(eModified_A, nummodesmax,
1718  PointsKey(nummodesmax + 1, eGaussLobattoLegendre));
1719  const BasisKey TetBb(eModified_B, nummodesmax,
1720  PointsKey(nummodesmax, eGaussRadauMAlpha1Beta0));
1721  const BasisKey TetBc(eModified_C, nummodesmax,
1722  PointsKey(nummodesmax, eGaussRadauMAlpha2Beta0));
1723 
1724  // Create reference tetrahedral expansion
1726 
1728  TetBa, TetBb, TetBc, tetgeom);
1729 
1730  maxElmt[eTetrahedron] = TetExp;
1731 
1732  TetExp->GetInverseBoundaryMaps(vmap, emap, fmap);
1733  vertMapMaxR[eTetrahedron] = vmap;
1734  edgeMapMaxR[eTetrahedron] = emap;
1735  faceMapMaxR[eTetrahedron] = fmap;
1736 
1737  // Get tetrahedral transformation matrix
1738  LocalRegions::MatrixKey TetR(PreconR, eTetrahedron, *TetExp,
1739  linSysKey.GetConstFactors());
1740  maxRmat[eTetrahedron] = TetExp->GetLocMatrix(TetR);
1741 
1742  if ((Shapes[ePyramid]) || (Shapes[eHexahedron]))
1743  {
1744  ReSetTetMaxRMat(nummodesmax, TetExp, maxRmat, vertMapMaxR,
1745  edgeMapMaxR, faceMapMaxR);
1746  }
1747  }
1748 
1749  if (Shapes[ePyramid])
1750  {
1752 
1753  // Bases for Pyramid element
1754  const BasisKey PyrBa(eModified_A, nummodesmax,
1755  PointsKey(nummodesmax + 1, eGaussLobattoLegendre));
1756  const BasisKey PyrBb(eModified_A, nummodesmax,
1757  PointsKey(nummodesmax + 1, eGaussLobattoLegendre));
1758  const BasisKey PyrBc(eModifiedPyr_C, nummodesmax,
1759  PointsKey(nummodesmax, eGaussRadauMAlpha2Beta0));
1760 
1761  // Create reference pyramid expansion
1763 
1765  PyrBa, PyrBb, PyrBc, pyrgeom);
1766 
1767  maxElmt[ePyramid] = PyrExp;
1768 
1769  // Pyramid:
1770  PyrExp->GetInverseBoundaryMaps(vmap, emap, fmap);
1771  vertMapMaxR[ePyramid] = vmap;
1772  edgeMapMaxR[ePyramid] = emap;
1773  faceMapMaxR[ePyramid] = fmap;
1774 
1775  // Set up Pyramid Transformation Matrix based on Tet
1776  // and Hex expansion
1777  SetUpPyrMaxRMat(nummodesmax, PyrExp, maxRmat, vertMapMaxR, edgeMapMaxR,
1778  faceMapMaxR);
1779  }
1780 
1781  if (Shapes[ePrism])
1782  {
1784  // Bases for Prism element
1785  const BasisKey PrismBa(
1786  eModified_A, nummodesmax,
1787  PointsKey(nummodesmax + 1, eGaussLobattoLegendre));
1788  const BasisKey PrismBb(
1789  eModified_A, nummodesmax,
1790  PointsKey(nummodesmax + 1, eGaussLobattoLegendre));
1791  const BasisKey PrismBc(eModified_B, nummodesmax,
1792  PointsKey(nummodesmax, eGaussRadauMAlpha1Beta0));
1793 
1794  // Create reference prismatic expansion
1796 
1798  PrismBa, PrismBb, PrismBc, prismgeom);
1799  maxElmt[ePrism] = PrismExp;
1800 
1801  // Prism:
1802  PrismExp->GetInverseBoundaryMaps(vmap, emap, fmap);
1803  vertMapMaxR[ePrism] = vmap;
1804  edgeMapMaxR[ePrism] = emap;
1805 
1806  faceMapMaxR[ePrism] = fmap;
1807 
1808  if ((Shapes[ePyramid]) || (Shapes[eHexahedron]))
1809  {
1810  ReSetPrismMaxRMat(nummodesmax, PrismExp, maxRmat, vertMapMaxR,
1811  edgeMapMaxR, faceMapMaxR, false);
1812  }
1813  else
1814  {
1815 
1816  // Get prismatic transformation matrix
1817  LocalRegions::MatrixKey PrismR(PreconR, ePrism, *PrismExp,
1818  linSysKey.GetConstFactors());
1819  maxRmat[ePrism] = PrismExp->GetLocMatrix(PrismR);
1820 
1821  if (Shapes[eTetrahedron]) // reset triangular faces from Tet
1822  {
1823  ReSetPrismMaxRMat(nummodesmax, PrismExp, maxRmat, vertMapMaxR,
1824  edgeMapMaxR, faceMapMaxR, true);
1825  }
1826  }
1827  }
1828 }
1829 
1831  int nummodesmax, LocalRegions::PyrExpSharedPtr &PyrExp,
1832  std::map<ShapeType, DNekScalMatSharedPtr> &maxRmat,
1833  std::map<ShapeType, Array<OneD, unsigned int>> &vertMapMaxR,
1834  std::map<ShapeType, Array<OneD, Array<OneD, unsigned int>>> &edgeMapMaxR,
1835  std::map<ShapeType, Array<OneD, Array<OneD, unsigned int>>> &faceMapMaxR)
1836 {
1837  int nRows = PyrExp->NumBndryCoeffs();
1838  NekDouble val;
1839  NekDouble zero = 0.0;
1840  DNekMatSharedPtr newmat =
1841  MemoryManager<DNekMat>::AllocateSharedPtr(nRows, nRows, zero, eFULL);
1842 
1843  // set diagonal to 1
1844  for (int i = 0; i < nRows; ++i)
1845  {
1846  newmat->SetValue(i, i, 1.0);
1847  }
1848 
1849  // The following lists specify the number of adjacent
1850  // edges to each vertex (nadj) then the Hex vert to
1851  // use for each pyramid ver in the vert-edge map (VEVert)
1852  // followed by the hex edge to use for each pyramid edge
1853  // in the vert-edge map (VEEdge)
1854  const int nadjedge[] = {3, 3, 3, 3, 4};
1855  const int VEHexVert[][4] = {{0, 0, 0, -1},
1856  {1, 1, 1, -1},
1857  {2, 2, 2, -1},
1858  {3, 3, 3, -1},
1859  {4, 5, 6, 7}};
1860  const int VEHexEdge[][4] = {{0, 3, 4, -1},
1861  {0, 1, 5, -1},
1862  {1, 2, 6, -1},
1863  {2, 3, 7, -1},
1864  {4, 5, 6, 7}};
1865  const int VEPyrEdge[][4] = {{0, 3, 4, -1},
1866  {0, 1, 5, -1},
1867  {1, 2, 6, -1},
1868  {2, 3, 7, -1},
1869  {4, 5, 6, 7}};
1870 
1871  // fill vertex to edge coupling
1872  for (int v = 0; v < 5; ++v)
1873  {
1874  for (int e = 0; e < nadjedge[v]; ++e)
1875  {
1876  for (int i = 0; i < nummodesmax - 2; ++i)
1877  {
1878  // Note this is using wrong shape but gives
1879  // answer that seems to have correct error!
1880  val = (*maxRmat[eHexahedron])(
1881  vertMapMaxR[eHexahedron][VEHexVert[v][e]],
1882  edgeMapMaxR[eHexahedron][VEHexEdge[v][e]][i]);
1883  newmat->SetValue(vertMapMaxR[ePyramid][v],
1884  edgeMapMaxR[ePyramid][VEPyrEdge[v][e]][i],
1885  val);
1886  }
1887  }
1888  }
1889 
1890  int nfacemodes;
1891  nfacemodes = (nummodesmax - 2) * (nummodesmax - 2);
1892  // First four verties are all adjacent to base face
1893  for (int v = 0; v < 4; ++v)
1894  {
1895  for (int i = 0; i < nfacemodes; ++i)
1896  {
1897  val = (*maxRmat[eHexahedron])(vertMapMaxR[eHexahedron][v],
1898  faceMapMaxR[eHexahedron][0][i]);
1899  newmat->SetValue(vertMapMaxR[ePyramid][v],
1900  faceMapMaxR[ePyramid][0][i], val);
1901  }
1902  }
1903 
1904  const int nadjface[] = {2, 2, 2, 2, 4};
1905  const int VFTetVert[][4] = {{0, 0, -1, -1},
1906  {1, 1, -1, -1},
1907  {2, 2, -1, -1},
1908  {0, 2, -1, -1},
1909  {3, 3, 3, 3}};
1910  const int VFTetFace[][4] = {{1, 3, -1, -1},
1911  {1, 2, -1, -1},
1912  {2, 3, -1, -1},
1913  {1, 3, -1, -1},
1914  {1, 2, 1, 2}};
1915  const int VFPyrFace[][4] = {{1, 4, -1, -1},
1916  {1, 2, -1, -1},
1917  {2, 3, -1, -1},
1918  {3, 4, -1, -1},
1919  {1, 2, 3, 4}};
1920 
1921  // next handle all triangular faces from tetrahedron
1922  nfacemodes = (nummodesmax - 3) * (nummodesmax - 2) / 2;
1923  for (int v = 0; v < 5; ++v)
1924  {
1925  for (int f = 0; f < nadjface[v]; ++f)
1926  {
1927  for (int i = 0; i < nfacemodes; ++i)
1928  {
1929  val = (*maxRmat[eTetrahedron])(
1930  vertMapMaxR[eTetrahedron][VFTetVert[v][f]],
1931  faceMapMaxR[eTetrahedron][VFTetFace[v][f]][i]);
1932  newmat->SetValue(vertMapMaxR[ePyramid][v],
1933  faceMapMaxR[ePyramid][VFPyrFace[v][f]][i],
1934  val);
1935  }
1936  }
1937  }
1938 
1939  // Edge to face coupling
1940  // all base edges are coupled to face 0
1941  nfacemodes = (nummodesmax - 2) * (nummodesmax - 2);
1942  for (int e = 0; e < 4; ++e)
1943  {
1944  for (int i = 0; i < nummodesmax - 2; ++i)
1945  {
1946  for (int j = 0; j < nfacemodes; ++j)
1947  {
1948  int edgemapid = edgeMapMaxR[eHexahedron][e][i];
1949  int facemapid = faceMapMaxR[eHexahedron][0][j];
1950 
1951  val = (*maxRmat[eHexahedron])(edgemapid, facemapid);
1952  newmat->SetValue(edgeMapMaxR[ePyramid][e][i],
1953  faceMapMaxR[ePyramid][0][j], val);
1954  }
1955  }
1956  }
1957 
1958  const int nadjface1[] = {1, 1, 1, 1, 2, 2, 2, 2};
1959  const int EFTetEdge[][2] = {{0, -1}, {1, -1}, {0, -1}, {2, -1},
1960  {3, 3}, {4, 4}, {5, 5}, {3, 5}};
1961  const int EFTetFace[][2] = {{1, -1}, {2, -1}, {1, -1}, {3, -1},
1962  {1, 3}, {1, 2}, {2, 3}, {1, 3}};
1963  const int EFPyrFace[][2] = {{1, -1}, {2, -1}, {3, -1}, {4, -1},
1964  {1, 4}, {1, 2}, {2, 3}, {3, 4}};
1965 
1966  // next handle all triangular faces from tetrahedron
1967  nfacemodes = (nummodesmax - 3) * (nummodesmax - 2) / 2;
1968  for (int e = 0; e < 8; ++e)
1969  {
1970  for (int f = 0; f < nadjface1[e]; ++f)
1971  {
1972  for (int i = 0; i < nummodesmax - 2; ++i)
1973  {
1974  for (int j = 0; j < nfacemodes; ++j)
1975  {
1976  int edgemapid =
1977  edgeMapMaxR[eTetrahedron][EFTetEdge[e][f]][i];
1978  int facemapid =
1979  faceMapMaxR[eTetrahedron][EFTetFace[e][f]][j];
1980 
1981  val = (*maxRmat[eTetrahedron])(edgemapid, facemapid);
1982  newmat->SetValue(edgeMapMaxR[ePyramid][e][i],
1983  faceMapMaxR[ePyramid][EFPyrFace[e][f]][j],
1984  val);
1985  }
1986  }
1987  }
1988  }
1989 
1990  DNekScalMatSharedPtr PyrR;
1992  maxRmat[ePyramid] = PyrR;
1993 }
1994 
1996  int nummodesmax, LocalRegions::TetExpSharedPtr &TetExp,
1997  std::map<ShapeType, DNekScalMatSharedPtr> &maxRmat,
1998  std::map<ShapeType, Array<OneD, unsigned int>> &vertMapMaxR,
1999  std::map<ShapeType, Array<OneD, Array<OneD, unsigned int>>> &edgeMapMaxR,
2000  std::map<ShapeType, Array<OneD, Array<OneD, unsigned int>>> &faceMapMaxR)
2001 {
2002  boost::ignore_unused(faceMapMaxR);
2003 
2004  int nRows = TetExp->NumBndryCoeffs();
2005  NekDouble val;
2006  NekDouble zero = 0.0;
2007  DNekMatSharedPtr newmat =
2008  MemoryManager<DNekMat>::AllocateSharedPtr(nRows, nRows, zero, eFULL);
2009 
2010  // copy existing system
2011  for (int i = 0; i < nRows; ++i)
2012  {
2013  for (int j = 0; j < nRows; ++j)
2014  {
2015  val = (*maxRmat[eTetrahedron])(i, j);
2016  newmat->SetValue(i, j, val);
2017  }
2018  }
2019 
2020  // The following lists specify the number of adjacent
2021  // edges to each vertex (nadj) then the Hex vert to
2022  // use for each pyramid ver in the vert-edge map (VEVert)
2023  // followed by the hex edge to use for each Tet edge
2024  // in the vert-edge map (VEEdge)
2025  const int VEHexVert[][4] = {{0, 0, 0}, {1, 1, 1}, {2, 2, 2}, {4, 5, 6}};
2026  const int VEHexEdge[][4] = {{0, 3, 4}, {0, 1, 5}, {1, 2, 6}, {4, 5, 6}};
2027  const int VETetEdge[][4] = {{0, 2, 3}, {0, 1, 4}, {1, 2, 5}, {3, 4, 5}};
2028 
2029  // fill vertex to edge coupling
2030  for (int v = 0; v < 4; ++v)
2031  {
2032  for (int e = 0; e < 3; ++e)
2033  {
2034  for (int i = 0; i < nummodesmax - 2; ++i)
2035  {
2036  // Note this is using wrong shape but gives
2037  // answer that seems to have correct error!
2038  val = (*maxRmat[eHexahedron])(
2039  vertMapMaxR[eHexahedron][VEHexVert[v][e]],
2040  edgeMapMaxR[eHexahedron][VEHexEdge[v][e]][i]);
2041  newmat->SetValue(vertMapMaxR[eTetrahedron][v],
2042  edgeMapMaxR[eTetrahedron][VETetEdge[v][e]][i],
2043  val);
2044  }
2045  }
2046  }
2047 
2048  DNekScalMatSharedPtr TetR =
2050 
2051  maxRmat[eTetrahedron] = TetR;
2052 }
2053 
2055  int nummodesmax, LocalRegions::PrismExpSharedPtr &PrismExp,
2056  std::map<ShapeType, DNekScalMatSharedPtr> &maxRmat,
2057  std::map<ShapeType, Array<OneD, unsigned int>> &vertMapMaxR,
2058  std::map<ShapeType, Array<OneD, Array<OneD, unsigned int>>> &edgeMapMaxR,
2059  std::map<ShapeType, Array<OneD, Array<OneD, unsigned int>>> &faceMapMaxR,
2060  bool UseTetOnly)
2061 {
2062  int nRows = PrismExp->NumBndryCoeffs();
2063  NekDouble val;
2064  NekDouble zero = 0.0;
2065  DNekMatSharedPtr newmat =
2066  MemoryManager<DNekMat>::AllocateSharedPtr(nRows, nRows, zero, eFULL);
2067 
2068  int nfacemodes;
2069 
2070  if (UseTetOnly)
2071  {
2072  // copy existing system
2073  for (int i = 0; i < nRows; ++i)
2074  {
2075  for (int j = 0; j < nRows; ++j)
2076  {
2077  val = (*maxRmat[ePrism])(i, j);
2078  newmat->SetValue(i, j, val);
2079  }
2080  }
2081 
2082  // Reset vertex to edge mapping from tet.
2083  const int VETetVert[][2] = {{0, 0}, {1, 1}, {1, 1},
2084  {0, 0}, {3, 3}, {3, 3}};
2085  const int VETetEdge[][2] = {{0, 3}, {0, 4}, {0, 4},
2086  {0, 3}, {3, 4}, {4, 3}};
2087  const int VEPrismEdge[][2] = {{0, 4}, {0, 5}, {2, 6},
2088  {2, 7}, {4, 5}, {6, 7}};
2089 
2090  // fill vertex to edge coupling
2091  for (int v = 0; v < 6; ++v)
2092  {
2093  for (int e = 0; e < 2; ++e)
2094  {
2095  for (int i = 0; i < nummodesmax - 2; ++i)
2096  {
2097  // Note this is using wrong shape but gives
2098  // answer that seems to have correct error!
2099  val = (*maxRmat[eTetrahedron])(
2100  vertMapMaxR[eTetrahedron][VETetVert[v][e]],
2101  edgeMapMaxR[eTetrahedron][VETetEdge[v][e]][i]);
2102  newmat->SetValue(vertMapMaxR[ePrism][v],
2103  edgeMapMaxR[ePrism][VEPrismEdge[v][e]][i],
2104  val);
2105  }
2106  }
2107  }
2108  }
2109  else
2110  {
2111 
2112  // set diagonal to 1
2113  for (int i = 0; i < nRows; ++i)
2114  {
2115  newmat->SetValue(i, i, 1.0);
2116  }
2117 
2118  // Set vertex to edge mapping from Hex.
2119 
2120  // The following lists specify the number of adjacent
2121  // edges to each vertex (nadj) then the Hex vert to
2122  // use for each prism ver in the vert-edge map (VEVert)
2123  // followed by the hex edge to use for each prism edge
2124  // in the vert-edge map (VEEdge)
2125  const int VEHexVert[][3] = {{0, 0, 0}, {1, 1, 1}, {2, 2, 2},
2126  {3, 3, 3}, {4, 5, 5}, {6, 7, 7}};
2127  const int VEHexEdge[][3] = {{0, 3, 4}, {0, 1, 5}, {1, 2, 6},
2128  {2, 3, 7}, {4, 5, 9}, {6, 7, 11}};
2129  const int VEPrismEdge[][3] = {{0, 3, 4}, {0, 1, 5}, {1, 2, 6},
2130  {2, 3, 7}, {4, 5, 8}, {6, 7, 8}};
2131 
2132  // fill vertex to edge coupling
2133  for (int v = 0; v < 6; ++v)
2134  {
2135  for (int e = 0; e < 3; ++e)
2136  {
2137  for (int i = 0; i < nummodesmax - 2; ++i)
2138  {
2139  // Note this is using wrong shape but gives
2140  // answer that seems to have correct error!
2141  val = (*maxRmat[eHexahedron])(
2142  vertMapMaxR[eHexahedron][VEHexVert[v][e]],
2143  edgeMapMaxR[eHexahedron][VEHexEdge[v][e]][i]);
2144  newmat->SetValue(vertMapMaxR[ePrism][v],
2145  edgeMapMaxR[ePrism][VEPrismEdge[v][e]][i],
2146  val);
2147  }
2148  }
2149  }
2150 
2151  // Setup vertex to face mapping from Hex
2152  const int VFHexVert[][2] = {{0, 0}, {1, 1}, {4, 5},
2153  {2, 2}, {3, 3}, {6, 7}};
2154  const int VFHexFace[][2] = {{0, 4}, {0, 2}, {4, 2},
2155  {0, 2}, {0, 4}, {2, 4}};
2156 
2157  const int VQFPrismVert[][2] = {{0, 0}, {1, 1}, {4, 4},
2158  {2, 2}, {3, 3}, {5, 5}};
2159  const int VQFPrismFace[][2] = {{0, 4}, {0, 2}, {4, 2},
2160  {0, 2}, {0, 4}, {2, 4}};
2161 
2162  nfacemodes = (nummodesmax - 2) * (nummodesmax - 2);
2163  // Replace two Quad faces on every vertex
2164  for (int v = 0; v < 6; ++v)
2165  {
2166  for (int f = 0; f < 2; ++f)
2167  {
2168  for (int i = 0; i < nfacemodes; ++i)
2169  {
2170  val = (*maxRmat[eHexahedron])(
2171  vertMapMaxR[eHexahedron][VFHexVert[v][f]],
2172  faceMapMaxR[eHexahedron][VFHexFace[v][f]][i]);
2173  newmat->SetValue(vertMapMaxR[ePrism][VQFPrismVert[v][f]],
2174  faceMapMaxR[ePrism][VQFPrismFace[v][f]][i],
2175  val);
2176  }
2177  }
2178  }
2179 
2180  // Mapping of Hex Edge-Face mappings to Prism Edge-Face Mappings
2181  const int nadjface[] = {1, 2, 1, 2, 1, 1, 1, 1, 2};
2182  const int EFHexEdge[][2] = {{0, -1}, {1, 1}, {2, -1}, {3, 3}, {4, -1},
2183  {5, -1}, {6, -1}, {7, -1}, {9, 11}};
2184  const int EFHexFace[][2] = {{0, -1}, {0, 2}, {0, -1}, {0, 4}, {4, -1},
2185  {2, -1}, {2, -1}, {4, -1}, {2, 4}};
2186  const int EQFPrismEdge[][2] = {{0, -1}, {1, 1}, {2, -1},
2187  {3, 3}, {4, -1}, {5, -1},
2188  {6, -1}, {7, -1}, {8, 8}};
2189  const int EQFPrismFace[][2] = {{0, -1}, {0, 2}, {0, -1},
2190  {0, 4}, {4, -1}, {2, -1},
2191  {2, -1}, {4, -1}, {2, 4}};
2192 
2193  // all base edges are coupled to face 0
2194  nfacemodes = (nummodesmax - 2) * (nummodesmax - 2);
2195  for (int e = 0; e < 9; ++e)
2196  {
2197  for (int f = 0; f < nadjface[e]; ++f)
2198  {
2199  for (int i = 0; i < nummodesmax - 2; ++i)
2200  {
2201  for (int j = 0; j < nfacemodes; ++j)
2202  {
2203  int edgemapid =
2204  edgeMapMaxR[eHexahedron][EFHexEdge[e][f]][i];
2205  int facemapid =
2206  faceMapMaxR[eHexahedron][EFHexFace[e][f]][j];
2207 
2208  val = (*maxRmat[eHexahedron])(edgemapid, facemapid);
2209 
2210  int edgemapid1 =
2211  edgeMapMaxR[ePrism][EQFPrismEdge[e][f]][i];
2212  int facemapid1 =
2213  faceMapMaxR[ePrism][EQFPrismFace[e][f]][j];
2214  newmat->SetValue(edgemapid1, facemapid1, val);
2215  }
2216  }
2217  }
2218  }
2219  }
2220 
2221  const int VFTetVert[] = {0, 1, 3, 1, 0, 3};
2222  const int VFTetFace[] = {1, 1, 1, 1, 1, 1};
2223  const int VTFPrismVert[] = {0, 1, 4, 2, 3, 5};
2224  const int VTFPrismFace[] = {1, 1, 1, 3, 3, 3};
2225 
2226  // Handle all triangular faces from tetrahedron
2227  nfacemodes = (nummodesmax - 3) * (nummodesmax - 2) / 2;
2228  for (int v = 0; v < 6; ++v)
2229  {
2230  for (int i = 0; i < nfacemodes; ++i)
2231  {
2232  val = (*maxRmat[eTetrahedron])(
2233  vertMapMaxR[eTetrahedron][VFTetVert[v]],
2234  faceMapMaxR[eTetrahedron][VFTetFace[v]][i]);
2235 
2236  newmat->SetValue(vertMapMaxR[ePrism][VTFPrismVert[v]],
2237  faceMapMaxR[ePrism][VTFPrismFace[v]][i], val);
2238  }
2239  }
2240 
2241  // Mapping of Tet Edge-Face mappings to Prism Edge-Face Mappings
2242  const int EFTetEdge[] = {0, 3, 4, 0, 4, 3};
2243  const int EFTetFace[] = {1, 1, 1, 1, 1, 1};
2244  const int ETFPrismEdge[] = {0, 4, 5, 2, 6, 7};
2245  const int ETFPrismFace[] = {1, 1, 1, 3, 3, 3};
2246 
2247  // handle all edge to triangular faces from tetrahedron
2248  // (only 6 this time)
2249  nfacemodes = (nummodesmax - 3) * (nummodesmax - 2) / 2;
2250  for (int e = 0; e < 6; ++e)
2251  {
2252  for (int i = 0; i < nummodesmax - 2; ++i)
2253  {
2254  for (int j = 0; j < nfacemodes; ++j)
2255  {
2256  int edgemapid = edgeMapMaxR[eTetrahedron][EFTetEdge[e]][i];
2257  int facemapid = faceMapMaxR[eTetrahedron][EFTetFace[e]][j];
2258  val = (*maxRmat[eTetrahedron])(edgemapid, facemapid);
2259 
2260  newmat->SetValue(edgeMapMaxR[ePrism][ETFPrismEdge[e]][i],
2261  faceMapMaxR[ePrism][ETFPrismFace[e]][j], val);
2262  }
2263  }
2264  }
2265 
2266  DNekScalMatSharedPtr PrismR =
2268  maxRmat[ePrism] = PrismR;
2269 }
2270 
2275 {
2276  NekDouble val;
2277  NekDouble zero = 0.0;
2278 
2279  int nRows = locExp->NumBndryCoeffs();
2280  DNekMatSharedPtr newmat =
2281  MemoryManager<DNekMat>::AllocateSharedPtr(nRows, nRows, zero, eFULL);
2282 
2283  Array<OneD, unsigned int> vlocmap;
2286 
2287  locExp->GetInverseBoundaryMaps(vlocmap, elocmap, flocmap);
2288 
2289  // fill diagonal
2290  for (int i = 0; i < nRows; ++i)
2291  {
2292  val = 1.0;
2293  newmat->SetValue(i, i, val);
2294  }
2295 
2296  int nverts = locExp->GetNverts();
2297  int nedges = locExp->GetNedges();
2298  int nfaces = locExp->GetNtraces();
2299 
2300  // fill vertex to edge coupling
2301  for (int e = 0; e < nedges; ++e)
2302  {
2303  int nEdgeInteriorCoeffs = locExp->GetEdgeNcoeffs(e) - 2;
2304 
2305  for (int v = 0; v < nverts; ++v)
2306  {
2307  for (int i = 0; i < nEdgeInteriorCoeffs; ++i)
2308  {
2309  val = (*maxRmat)(vmap[v], emap[e][i]);
2310  newmat->SetValue(vlocmap[v], elocmap[e][i], val);
2311  }
2312  }
2313  }
2314 
2315  for (int f = 0; f < nfaces; ++f)
2316  {
2317  // Get details to extrac this face from max reference matrix
2318  StdRegions::Orientation FwdOrient =
2320  int m0, m1; // Local face expansion orders.
2321 
2322  int nFaceInteriorCoeffs = locExp->GetTraceIntNcoeffs(f);
2323 
2324  locExp->GetTraceNumModes(f, m0, m1, FwdOrient);
2325 
2326  Array<OneD, unsigned int> fmapRmat =
2327  maxExp->GetTraceInverseBoundaryMap(f, FwdOrient, m0, m1);
2328 
2329  // fill in vertex to face coupling
2330  for (int v = 0; v < nverts; ++v)
2331  {
2332  for (int i = 0; i < nFaceInteriorCoeffs; ++i)
2333  {
2334  val = (*maxRmat)(vmap[v], fmapRmat[i]);
2335  newmat->SetValue(vlocmap[v], flocmap[f][i], val);
2336  }
2337  }
2338 
2339  // fill in edges to face coupling
2340  for (int e = 0; e < nedges; ++e)
2341  {
2342  int nEdgeInteriorCoeffs = locExp->GetEdgeNcoeffs(e) - 2;
2343 
2344  for (int j = 0; j < nEdgeInteriorCoeffs; ++j)
2345  {
2346 
2347  for (int i = 0; i < nFaceInteriorCoeffs; ++i)
2348  {
2349  val = (*maxRmat)(emap[e][j], fmapRmat[i]);
2350  newmat->SetValue(elocmap[e][j], flocmap[f][i], val);
2351  }
2352  }
2353  }
2354  }
2355 
2356  return newmat;
2357 }
2358 } // namespace MultiRegions
2359 } // 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
#define sign(a, b)
return the sign(b)*a
Definition: Polylib.cpp:49
Describes the specification for a Basis.
Definition: Basis.h:50
tKey RegisterCreatorFunction(tKey idKey, CreatorFunction classCreator, std::string pDesc="")
Register a class with the factory.
Definition: NekFactory.hpp:198
Defines a specification for a set of points.
Definition: Points.h:59
SpatialDomains::GeometrySharedPtr GetGeom() const
Definition: Expansion.cpp:171
static std::shared_ptr< DataType > AllocateSharedPtr(const Args &...args)
Allocate a shared pointer from the memory pool.
const StdRegions::ConstFactorMap & GetConstFactors() const
Returns all the constants.
StdRegions::MatrixType GetMatrixType() const
Return the matrix type.
LibUtilities::CommSharedPtr m_comm
const std::weak_ptr< GlobalLinSys > m_linsys
std::weak_ptr< AssemblyMap > m_locToGloMap
virtual void v_DoTransformCoeffsFromLowEnergy(Array< OneD, NekDouble > &pInOut) override
transform the solution coeffiicents from low energy back to the original coefficient space.
SpatialDomains::HexGeomSharedPtr CreateRefHexGeom(void)
Sets up the reference hexahedral element needed to construct a low energy basis.
void ReSetPrismMaxRMat(int nummodesmax, LocalRegions::PrismExpSharedPtr &PirsmExp, ShapeToDNekMap &maxRmat, ShapeToIntArrayMap &vertMapMaxR, ShapeToIntArrayArrayMap &edgeMapMaxR, ShapeToIntArrayArrayMap &faceMapMaxR, bool UseTetOnly)
DNekMatSharedPtr ExtractLocMat(LocalRegions::Expansion3DSharedPtr &locExp, DNekScalMatSharedPtr &maxRmat, LocalRegions::Expansion3DSharedPtr &expMax, Array< OneD, unsigned int > &vertMapMaxR, Array< OneD, Array< OneD, unsigned int >> &edgeMapMaxR)
std::vector< std::pair< int, int > > m_sameBlock
virtual void v_DoTransformCoeffsToLowEnergy(const Array< OneD, NekDouble > &pInput, Array< OneD, NekDouble > &pOutput) override
Multiply by the block tranposed inverse transformation matrix (R^T)^{-1} which is equivlaent to trans...
virtual DNekScalMatSharedPtr v_TransformedSchurCompl(int n, int offset, const std::shared_ptr< DNekScalMat > &loc_mat) override
Set up the transformed block matrix system.
virtual void v_DoPreconditioner(const Array< OneD, NekDouble > &pInput, Array< OneD, NekDouble > &pOutput) override
virtual void v_BuildPreconditioner() override
Construct the low energy preconditioner from .
void ReSetTetMaxRMat(int nummodesmax, LocalRegions::TetExpSharedPtr &TetExp, ShapeToDNekMap &maxRmat, ShapeToIntArrayMap &vertMapMaxR, ShapeToIntArrayArrayMap &edgeMapMaxR, ShapeToIntArrayArrayMap &faceMapMaxR)
SpatialDomains::TetGeomSharedPtr CreateRefTetGeom(void)
Sets up the reference tretrahedral element needed to construct a low energy basis.
virtual void v_DoTransformBasisFromLowEnergy(const Array< OneD, NekDouble > &pInput, Array< OneD, NekDouble > &pOutput) override
Multiply by the block inverse transformation matrix This transforms the bassi from Low Energy to orig...
virtual void v_DoTransformBasisToLowEnergy(Array< OneD, NekDouble > &pInOut) override
Transform the basis vector to low energy space.
SpatialDomains::PrismGeomSharedPtr CreateRefPrismGeom(void)
Sets up the reference prismatic element needed to construct a low energy basis.
void SetUpReferenceElements(ShapeToDNekMap &maxRmat, ShapeToExpMap &maxElmt, ShapeToIntArrayMap &vertMapMaxR, ShapeToIntArrayArrayMap &edgeMapMaxR)
Loop expansion and determine different variants of the transformation matrix.
void SetUpPyrMaxRMat(int nummodesmax, LocalRegions::PyrExpSharedPtr &PyrExp, ShapeToDNekMap &maxRmat, ShapeToIntArrayMap &vertMapMaxR, ShapeToIntArrayArrayMap &edgeMapMaxR, ShapeToIntArrayArrayMap &faceMapMaxR)
SpatialDomains::PyrGeomSharedPtr CreateRefPyrGeom(void)
Sets up the reference prismatic element needed to construct a low energy basis mapping arrays.
int GetEdgeNcoeffs(const int i) const
This function returns the number of expansion coefficients belonging to the i-th edge.
int GetNedges() const
return the number of edges in 3D expansion
LibUtilities::ShapeType DetShapeType() const
This function returns the shape of the expansion domain.
Definition: StdExpansion.h:373
static void Dgemm(const char &transa, const char &transb, const int &m, const int &n, const int &k, const double &alpha, const double *a, const int &lda, const double *b, const int &ldb, const double &beta, double *c, const int &ldc)
BLAS level 3: Matrix-matrix multiply C = A x B where op(A)[m x k], op(B)[k x n], C[m x n] DGEMM perfo...
Definition: Blas.hpp:368
static void Gather(Nektar::Array< OneD, NekDouble > pU, gs_op pOp, gs_data *pGsh, Nektar::Array< OneD, NekDouble > pBuffer=NullNekDouble1DArray)
Performs a gather-scatter operation of the provided values.
Definition: GsLib.hpp:270
@ gs_add
Definition: GsLib.hpp:62
@ gs_min
Definition: GsLib.hpp:64
static gs_data * Init(const Nektar::Array< OneD, long > pId, const LibUtilities::CommSharedPtr &pComm, bool verbose=true)
Initialise Gather-Scatter map.
Definition: GsLib.hpp:192
@ eGaussLobattoLegendre
1D Gauss-Lobatto-Legendre quadrature points
Definition: PointsType.h:53
@ eModified_B
Principle Modified Functions .
Definition: BasisType.h:51
@ eModified_C
Principle Modified Functions .
Definition: BasisType.h:52
@ eModifiedPyr_C
Principle Modified Functions.
Definition: BasisType.h:55
@ eModified_A
Principle Modified Functions .
Definition: BasisType.h:50
std::shared_ptr< PrismExp > PrismExpSharedPtr
Definition: PrismExp.h:209
std::shared_ptr< Expansion > ExpansionSharedPtr
Definition: Expansion.h:68
std::shared_ptr< HexExp > HexExpSharedPtr
Definition: HexExp.h:260
std::shared_ptr< Expansion2D > Expansion2DSharedPtr
Definition: Expansion1D.h:47
std::shared_ptr< PyrExp > PyrExpSharedPtr
Definition: PyrExp.h:185
std::shared_ptr< Expansion3D > Expansion3DSharedPtr
Definition: Expansion2D.h:50
std::shared_ptr< TetExp > TetExpSharedPtr
Definition: TetExp.h:214
PreconFactory & GetPreconFactory()
std::shared_ptr< AssemblyMap > AssemblyMapSharedPtr
Definition: AssemblyMap.h:51
std::map< int, std::vector< PeriodicEntity > > PeriodicMap
StdRegions::Orientation DeterminePeriodicFaceOrient(StdRegions::Orientation faceOrient, StdRegions::Orientation perFaceOrient)
Determine relative orientation between two faces.
std::shared_ptr< QuadGeom > QuadGeomSharedPtr
Definition: HexGeom.h:46
std::shared_ptr< PrismGeom > PrismGeomSharedPtr
Definition: PrismGeom.h:85
std::shared_ptr< HexGeom > HexGeomSharedPtr
Definition: HexGeom.h:87
std::shared_ptr< SegGeom > SegGeomSharedPtr
Definition: Geometry2D.h:62
std::shared_ptr< PyrGeom > PyrGeomSharedPtr
Definition: PyrGeom.h:77
std::shared_ptr< TetGeom > TetGeomSharedPtr
Definition: TetGeom.h:85
std::shared_ptr< PointGeom > PointGeomSharedPtr
Definition: Geometry.h:59
std::shared_ptr< Geometry2D > Geometry2DSharedPtr
Definition: Geometry.h:65
std::shared_ptr< TriGeom > TriGeomSharedPtr
Definition: TriGeom.h:58
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
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 Assmb(int n, const T *x, const int *y, T *z)
Assemble z[y[i]] += x[i]; z should be zero'd first.
Definition: Vmath.cpp:862
scalarT< T > sqrt(scalarT< T > in)
Definition: scalar.hpp:294