Nektar++
Loading...
Searching...
No Matches
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
40#include <cmath>
41
42using namespace std;
43
44namespace Nektar
45{
46using namespace LibUtilities;
47
48namespace MultiRegions
49{
50/**
51 * Registers the class with the Factory.
52 */
56 "LowEnergy Preconditioning");
57
58/**
59 * @class PreconditionerLowEnergy
60 *
61 * This class implements low energy preconditioning for the conjugate
62 * gradient matrix solver.
63 */
64
66 const std::shared_ptr<GlobalLinSys> &plinsys,
67 const AssemblyMapSharedPtr &pLocToGloMap)
68 : Preconditioner(plinsys, pLocToGloMap)
69{
70}
71
73{
74 GlobalSysSolnType solvertype = m_locToGloMap.lock()->GetGlobalSysSolnType();
75
76 ASSERTL0(solvertype == eIterativeStaticCond ||
77 solvertype == ePETScStaticCond,
78 "Solver type not valid");
79
80 std::shared_ptr<MultiRegions::ExpList> expList =
81 ((m_linsys.lock())->GetLocMat()).lock();
82
84
85 locExpansion = expList->GetExp(0);
86
87 int nDim = locExpansion->GetShapeDimension();
88
89 ASSERTL0(nDim == 3, "Preconditioner type only valid in 3D");
90
91 // Set up block transformation matrix
93
94 // Sets up variable p mask
96}
97
98/**
99 * \brief Construct the low energy preconditioner from
100 * \f$\mathbf{S}_{2}\f$
101 *
102 * \f[\mathbf{M}^{-1}=\left[\begin{array}{ccc}
103 * Diag[(\mathbf{S_{2}})_{vv}] & & \\ & (\mathbf{S}_{2})_{eb} & \\ & &
104 * (\mathbf{S}_{2})_{fb} \end{array}\right] \f]
105 *
106 * where \f$\mathbf{R}\f$ is the transformation matrix and
107 * \f$\mathbf{S}_{2}\f$ the Schur complement of the modified basis,
108 * given by
109 *
110 * \f[\mathbf{S}_{2}=\mathbf{R}\mathbf{S}_{1}\mathbf{R}^{T}\f]
111 *
112 * where \f$\mathbf{S}_{1}\f$ is the local schur complement matrix for
113 * each element.
114 */
116{
117 std::shared_ptr<MultiRegions::ExpList> expList =
118 ((m_linsys.lock())->GetLocMat()).lock();
120 GlobalLinSysKey linSysKey = (m_linsys.lock())->GetKey();
121
122 LibUtilities::CommSharedPtr vComm = expList->GetComm()->GetSpaceComm();
123
124 int i, j, k;
125 int nVerts, nEdges, nFaces;
126 int eid, fid, n, cnt, nmodes, nedgemodes, nfacemodes;
127 int nedgemodesloc;
128 NekDouble zero = 0.0;
129
130 int vMap1, vMap2, sign1, sign2;
131 int m, v, eMap1, eMap2, fMap1, fMap2;
132 int offset, globalrow, globalcol, nCoeffs;
133
134 // Periodic information
135 PeriodicMap periodicVerts;
136 PeriodicMap periodicEdges;
137 PeriodicMap periodicFaces;
138 expList->GetPeriodicEntities(periodicVerts, periodicEdges, periodicFaces);
139
140 // matrix storage
141 MatrixStorage storage = eFULL;
142 MatrixStorage vertstorage = eDIAGONAL;
143 MatrixStorage blkmatStorage = eDIAGONAL;
144
145 // local element static condensed matrices
147 DNekScalMatSharedPtr bnd_mat;
148
149 DNekMatSharedPtr pRSRT;
150
151 DNekMat RS;
152 DNekMat RSRT;
153
154 auto asmMap = m_locToGloMap.lock();
155
156 int nDirBnd = asmMap->GetNumGlobalDirBndCoeffs();
157 int nNonDirVerts = asmMap->GetNumNonDirVertexModes();
158
159 // Vertex, edge and face preconditioner matrices
161 nNonDirVerts, nNonDirVerts, zero, vertstorage);
162
163 Array<OneD, NekDouble> vertArray(nNonDirVerts, 0.0);
164 Array<OneD, long> VertBlockToUniversalMap(nNonDirVerts, -1);
165
166 // maps for different element types
167 int n_exp = expList->GetNumElmts();
168 int nNonDirEdgeIDs = asmMap->GetNumNonDirEdges();
169 int nNonDirFaceIDs = asmMap->GetNumNonDirFaces();
170
171 set<int> edgeDirMap;
172 set<int> faceDirMap;
173 map<int, int> uniqueEdgeMap;
174 map<int, int> uniqueFaceMap;
175
176 // this should be of size total number of local edges + faces
177 Array<OneD, int> modeoffset(1 + nNonDirEdgeIDs + nNonDirFaceIDs, 0);
178 Array<OneD, int> globaloffset(1 + nNonDirEdgeIDs + nNonDirFaceIDs, 0);
179
180 const Array<OneD, const ExpListSharedPtr> &bndCondExp =
181 expList->GetBndCondExpansions();
184 &bndConditions = expList->GetBndConditions();
185
186 int meshVertId;
187 int meshEdgeId;
188 int meshFaceId;
189
190 const Array<OneD, const int> &extradiredges = asmMap->GetExtraDirEdges();
191 for (i = 0; i < extradiredges.size(); ++i)
192 {
193 meshEdgeId = extradiredges[i];
194 edgeDirMap.insert(meshEdgeId);
195 }
196
197 // Determine which boundary edges and faces have dirichlet values
198 for (i = 0; i < bndCondExp.size(); i++)
199 {
200 cnt = 0;
201 for (j = 0; j < bndCondExp[i]->GetNumElmts(); j++)
202 {
203 bndCondFaceExp =
204 std::dynamic_pointer_cast<LocalRegions::Expansion2D>(
205 bndCondExp[i]->GetExp(j));
206 if (bndConditions[i]->GetBoundaryConditionType() ==
208 {
209 for (k = 0; k < bndCondFaceExp->GetNtraces(); k++)
210 {
211 meshEdgeId = bndCondFaceExp->GetGeom()->GetEid(k);
212 if (edgeDirMap.count(meshEdgeId) == 0)
213 {
214 edgeDirMap.insert(meshEdgeId);
215 }
216 }
217 meshFaceId = bndCondFaceExp->GetGeom()->GetGlobalID();
218 faceDirMap.insert(meshFaceId);
219 }
220 }
221 }
222
223 int dof = 0;
224 int maxFaceDof = 0;
225 int maxEdgeDof = 0;
226 int nlocalNonDirEdges = 0;
227 int nlocalNonDirFaces = 0;
228 int ntotalentries = 0;
229
230 map<int, int> EdgeSize;
231 map<int, int> FaceSize;
232 map<int, pair<int, int>> FaceModes;
233
234 /// - Count edges, face and add up min edges and min face sizes
235 for (n = 0; n < n_exp; ++n)
236 {
237 locExpansion = expList->GetExp(n)->as<LocalRegions::Expansion3D>();
238
239 nEdges = locExpansion->GetNedges();
240 for (j = 0; j < nEdges; ++j)
241 {
242 int nEdgeInteriorCoeffs = locExpansion->GetEdgeNcoeffs(j) - 2;
243 meshEdgeId = locExpansion->as<LocalRegions::Expansion3D>()
244 ->GetGeom3D()
245 ->GetEid(j);
246 if (EdgeSize.count(meshEdgeId) == 0)
247 {
248 EdgeSize[meshEdgeId] = nEdgeInteriorCoeffs;
249 }
250 else
251 {
252 EdgeSize[meshEdgeId] =
253 min(EdgeSize[meshEdgeId], nEdgeInteriorCoeffs);
254 }
255 }
256
257 nFaces = locExpansion->GetNtraces();
258 for (j = 0; j < nFaces; ++j)
259 {
260 int nFaceInteriorCoeffs = locExpansion->GetTraceIntNcoeffs(j);
261 meshFaceId = locExpansion->GetGeom3D()->GetFid(j);
262
263 if (FaceSize.count(meshFaceId) == 0)
264 {
265 FaceSize[meshFaceId] = nFaceInteriorCoeffs;
266
267 int m0, m1;
268 locExpansion->GetTraceNumModes(j, m0, m1,
269 locExpansion->GetTraceOrient(j));
270 FaceModes[meshFaceId] = pair<int, int>(m0, m1);
271 }
272 else
273 {
274 if (nFaceInteriorCoeffs < FaceSize[meshFaceId])
275 {
276 FaceSize[meshFaceId] = nFaceInteriorCoeffs;
277 int m0, m1;
278 locExpansion->GetTraceNumModes(
279 j, m0, m1, locExpansion->GetTraceOrient(j));
280 FaceModes[meshFaceId] = pair<int, int>(m0, m1);
281 }
282 }
283 }
284 }
285
286 bool verbose = expList->GetSession()->DefinesCmdLineArgument("verbose");
287
288 // For parallel runs need to check have minimum of edges and faces over
289 // partition boundaries
290 if (vComm->GetSize() > 1)
291 {
292 int EdgeSizeLen = EdgeSize.size();
293 int FaceSizeLen = FaceSize.size();
294 Array<OneD, long> FacetMap(EdgeSizeLen + FaceSizeLen, -1);
295 Array<OneD, NekDouble> FacetLen(EdgeSizeLen + FaceSizeLen, -1);
296
297 map<int, int>::iterator it;
298
299 cnt = 0;
300 int maxid = 0;
301 for (it = EdgeSize.begin(); it != EdgeSize.end(); ++it, ++cnt)
302 {
303 FacetMap[cnt] = it->first;
304 maxid = max(it->first, maxid);
305 FacetLen[cnt] = it->second;
306 }
307 maxid++;
308
309 vComm->AllReduce(maxid, ReduceMax);
310
311 for (it = FaceSize.begin(); it != FaceSize.end(); ++it, ++cnt)
312 {
313 FacetMap[cnt] = it->first + maxid;
314 FacetLen[cnt] = it->second;
315 }
316
317 // Exchange vertex data over different processes
318 Gs::gs_data *tmp = Gs::Init(FacetMap, vComm, verbose);
319 Gs::Gather(FacetLen, Gs::gs_min, tmp);
320 Gs::Free(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 vComm->AllReduce(maxEdgeDof, ReduceMax);
491 vComm->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 vComm->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 meshEdgeId = locExpansion->as<LocalRegions::Expansion3D>()
714 ->GetGeom3D()
715 ->GetEid(eid);
716
717 nedgemodes = EdgeSize[meshEdgeId];
718 if (nedgemodes)
719 {
720 nedgemodesloc = locExpansion->GetEdgeNcoeffs(eid) - 2;
721 DNekMatSharedPtr m_locMat =
723 nedgemodes, nedgemodes, zero, storage);
724
725 Array<OneD, unsigned int> edgemodearray =
726 locExpansion->GetEdgeInverseBoundaryMap(eid);
727
728 if (edgeDirMap.count(meshEdgeId) == 0)
729 {
730 for (v = 0; v < nedgemodesloc; ++v)
731 {
732 eMap1 = edgemodearray[v];
733 sign1 = asmMap->GetLocalToGlobalBndSign(cnt + eMap1);
734
735 if (sign1 == 0)
736 {
737 continue;
738 }
739
740 for (m = 0; m < nedgemodesloc; ++m)
741 {
742 eMap2 = edgemodearray[m];
743
744 // modal connectivity between elements
745 sign2 =
746 asmMap->GetLocalToGlobalBndSign(cnt + eMap2);
747
748 NekDouble globalEdgeValue =
749 sign1 * sign2 * RSRT(eMap1, eMap2);
750
751 if (sign2 != 0)
752 {
753 // if(eMap1 == eMap2)
754 BlockArray[matrixoffset + v * nedgemodes + m] =
755 globalEdgeValue;
756 }
757 }
758 }
759 matrixoffset += nedgemodes * nedgemodes;
760 }
761 }
762 }
763
764 // loop over faces of the element and return the face map
765 for (fid = 0; fid < nFaces; ++fid)
766 {
767 meshFaceId = locExpansion->as<LocalRegions::Expansion3D>()
768 ->GetGeom3D()
769 ->GetFid(fid);
770
771 nfacemodes = FaceSize[meshFaceId];
772 if (nfacemodes > 0)
773 {
774 DNekMatSharedPtr m_locMat =
776 nfacemodes, nfacemodes, zero, storage);
777
778 if (faceDirMap.count(meshFaceId) == 0)
779 {
780 Array<OneD, unsigned int> facemodearray;
781 StdRegions::Orientation faceOrient =
782 locExpansion->GetTraceOrient(fid);
783
784 auto pIt = periodicFaces.find(meshFaceId);
785 if (pIt != periodicFaces.end())
786 {
787 if (meshFaceId == min(meshFaceId, pIt->second[0].id))
788 {
789 faceOrient = DeterminePeriodicFaceOrient(
790 faceOrient, pIt->second[0].orient);
791 }
792 }
793
794 facemodearray = locExpansion->GetTraceInverseBoundaryMap(
795 fid, faceOrient, FaceModes[meshFaceId].first,
796 FaceModes[meshFaceId].second);
797
798 for (v = 0; v < nfacemodes; ++v)
799 {
800 fMap1 = facemodearray[v];
801
802 sign1 = asmMap->GetLocalToGlobalBndSign(cnt + fMap1);
803
804 ASSERTL1(sign1 != 0,
805 "Something is wrong since we "
806 "shoudl only be extracting modes for "
807 "lowest order expansion");
808
809 for (m = 0; m < nfacemodes; ++m)
810 {
811 fMap2 = facemodearray[m];
812
813 // modal connectivity between elements
814 sign2 =
815 asmMap->GetLocalToGlobalBndSign(cnt + fMap2);
816
817 ASSERTL1(sign2 != 0,
818 "Something is wrong since "
819 "we shoudl only be extracting modes for "
820 "lowest order expansion");
821
822 // Get the face-face value from the
823 // low energy matrix (S2)
824 NekDouble globalFaceValue =
825 sign1 * sign2 * RSRT(fMap1, fMap2);
826
827 // local face value to global face value
828 // if(fMap1 == fMap2)
829 BlockArray[matrixoffset + v * nfacemodes + m] =
830 globalFaceValue;
831 }
832 }
833 matrixoffset += nfacemodes * nfacemodes;
834 }
835 }
836 }
837
838 // offset for the expansion
839 cnt += nCoeffs;
840 }
841
842 // Exchange vertex data over different processes
843 Gs::gs_data *tmp = Gs::Init(VertBlockToUniversalMap, vComm, verbose);
844 Gs::Gather(vertArray, Gs::gs_add, tmp);
845 Gs::Free(tmp);
846
847 Array<OneD, NekDouble> GlobalBlock(ntotalentries, 0.0);
848 if (ntotalentries)
849 {
850 // Assemble edge matrices of each process
851 Vmath::Assmb(BlockArray.size(), BlockArray, localToGlobalMatrixMap,
852 GlobalBlock);
853 }
854
855 // Exchange edge & face data over different processes
856 Gs::gs_data *tmp1 = Gs::Init(BlockToUniversalMap, vComm, verbose);
857 Gs::Gather(GlobalBlock, Gs::gs_add, tmp1);
858 Gs::Free(tmp1);
859
860 // Populate vertex block
861 for (int i = 0; i < nNonDirVerts; ++i)
862 {
863 VertBlk->SetValue(i, i, 1.0 / vertArray[i]);
864 }
865
866 // Set the first block to be the diagonal of the vertex space
867 m_BlkMat->SetBlock(0, 0, VertBlk);
868
869 // Build the edge and face matrices from the vector
870 DNekMatSharedPtr gmat;
871
872 offset = 0;
873 // -1 since we ignore vert block
874 for (int loc = 0; loc < n_blks.size() - 1; ++loc)
875 {
876 nmodes = n_blks[1 + loc];
877 gmat = MemoryManager<DNekMat>::AllocateSharedPtr(nmodes, nmodes, zero,
878 storage);
879
880 for (v = 0; v < nmodes; ++v)
881 {
882 for (m = 0; m < nmodes; ++m)
883 {
884 NekDouble Value = GlobalBlock[offset + v * nmodes + m];
885 gmat->SetValue(v, m, Value);
886 }
887 }
888 m_BlkMat->SetBlock(1 + loc, 1 + loc, gmat);
889 offset += modeoffset[loc];
890 }
891
892 // invert blocks.
893 int totblks = m_BlkMat->GetNumberOfBlockRows();
894 for (i = 1; i < totblks; ++i)
895 {
896 unsigned int nmodes = m_BlkMat->GetNumberOfRowsInBlockRow(i);
897 if (nmodes)
898 {
899 DNekMatSharedPtr tmp_mat =
901 storage);
902
903 tmp_mat = m_BlkMat->GetBlock(i, i);
904 tmp_mat->Invert();
905
906 m_BlkMat->SetBlock(i, i, tmp_mat);
907 }
908 }
909}
910
911/**
912 * Apply the low energy preconditioner during the conjugate gradient
913 * routine
914 */
916 const Array<OneD, NekDouble> &pInput, Array<OneD, NekDouble> &pOutput,
917 const bool &isLocal)
918
919{
920 ASSERTL0(isLocal == false, "PreconditionerLowEnergy is only currently "
921 "set up for Global iteratives sovles");
922 int nDir = m_locToGloMap.lock()->GetNumGlobalDirBndCoeffs();
923 int nGlobal = m_locToGloMap.lock()->GetNumGlobalBndCoeffs();
924 int nNonDir = nGlobal - nDir;
925 DNekBlkMat &M = (*m_BlkMat);
926
927 NekVector<NekDouble> r(nNonDir, pInput, eWrapper);
928
929 NekVector<NekDouble> z(nNonDir, pOutput, eWrapper);
930
931 z = M * r;
932}
933
934/**
935 * Set a block transformation matrices for each element type. These are
936 * needed in routines that transform the schur complement matrix to and
937 * from the low energy basis.
938 */
940{
941 std::shared_ptr<MultiRegions::ExpList> expList =
942 ((m_linsys.lock())->GetLocMat()).lock();
945 map<int, int> EdgeSize;
946
947 int n;
948
949 std::map<ShapeType, DNekScalMatSharedPtr> maxRmat;
950 map<ShapeType, LocalRegions::Expansion3DSharedPtr> maxElmt;
951 map<ShapeType, Array<OneD, unsigned int>> vertMapMaxR;
952 map<ShapeType, Array<OneD, Array<OneD, unsigned int>>> edgeMapMaxR;
953
954 // Sets up reference element and builds transformation matrix for
955 // maximum polynomial order meshes
956 SetUpReferenceElements(maxRmat, maxElmt, vertMapMaxR, edgeMapMaxR);
957
958 const Array<OneD, const unsigned int> &nbdry_size =
959 m_locToGloMap.lock()->GetNumLocalBndCoeffsPerPatch();
960
961 int n_exp = expList->GetNumElmts();
962
963 MatrixStorage blkmatStorage = eDIAGONAL;
964
965 // Variants of R matrices required for low energy preconditioning
967 nbdry_size, nbdry_size, blkmatStorage);
969 nbdry_size, nbdry_size, blkmatStorage);
970
971 DNekMatSharedPtr rmat, invrmat;
972
973 int offset = 0;
974
975 // Set up transformation matrices whilst checking to see if
976 // consecutive matrices are the same and if so reuse the
977 // matrices and store how many consecutive offsets there
978 // are
979 for (n = 0; n < n_exp; ++n)
980 {
981 locExp = expList->GetExp(n)->as<LocalRegions::Expansion3D>();
982
983 ShapeType eltype = locExp->DetShapeType();
984
985 int nbndcoeffs = locExp->NumBndryCoeffs();
986
987 if (m_sameBlock.size() == 0)
988 {
989 rmat = ExtractLocMat(locExp, maxRmat[eltype], maxElmt[eltype],
990 vertMapMaxR[eltype], edgeMapMaxR[eltype]);
991 // Block R matrix
992 m_RBlk->SetBlock(n, n, rmat);
993
995 invrmat->Invert();
996
997 // Block inverse R matrix
998 m_InvRBlk->SetBlock(n, n, invrmat);
999
1000 m_sameBlock.push_back(pair<int, int>(1, nbndcoeffs));
1001 locExpSav = locExp;
1002 }
1003 else
1004 {
1005 bool reuse = true;
1006
1007 // check to see if same as previous matrix and
1008 // reuse if we can
1009 for (int i = 0; i < 3; ++i)
1010 {
1011 if (locExpSav->GetBasis(i) != locExp->GetBasis(i))
1012 {
1013 reuse = false;
1014 break;
1015 }
1016 }
1017
1018 if (reuse)
1019 {
1020 m_RBlk->SetBlock(n, n, rmat);
1021 m_InvRBlk->SetBlock(n, n, invrmat);
1022
1023 m_sameBlock[offset] =
1024 (pair<int, int>(m_sameBlock[offset].first + 1, nbndcoeffs));
1025 }
1026 else
1027 {
1028 rmat = ExtractLocMat(locExp, maxRmat[eltype], maxElmt[eltype],
1029 vertMapMaxR[eltype], edgeMapMaxR[eltype]);
1030
1031 // Block R matrix
1032 m_RBlk->SetBlock(n, n, rmat);
1033
1035 invrmat->Invert();
1036 // Block inverse R matrix
1037 m_InvRBlk->SetBlock(n, n, invrmat);
1038
1039 m_sameBlock.push_back(pair<int, int>(1, nbndcoeffs));
1040 offset++;
1041 locExpSav = locExp;
1042 }
1043 }
1044 }
1045}
1046
1047/**
1048 * \brief Transform the basis vector to low energy space
1049 *
1050 * As the conjugate gradient system is solved for the low energy basis,
1051 * the solution vector \f$\mathbf{x}\f$ must be transformed to the low
1052 * energy basis i.e. \f$\overline{\mathbf{x}}=\mathbf{R}\mathbf{x}\f$.
1053 */
1055 Array<OneD, NekDouble> &pInOut)
1056{
1057 int nLocBndDofs = m_locToGloMap.lock()->GetNumLocalBndCoeffs();
1058
1059 // Block transformation matrix
1060 DNekBlkMat &R = *m_RBlk;
1061
1062 Array<OneD, NekDouble> pLocalIn(nLocBndDofs, pInOut.data());
1063
1064 // Apply mask in case of variable P
1065 Vmath::Vmul(nLocBndDofs, pLocalIn, 1, m_variablePmask, 1, pLocalIn, 1);
1066
1067 // Multiply by the block transformation matrix
1068 int cnt = 0;
1069 int cnt1 = 0;
1070 for (int i = 0; i < m_sameBlock.size(); ++i)
1071 {
1072 int nexp = m_sameBlock[i].first;
1073 int nbndcoeffs = m_sameBlock[i].second;
1074 Blas::Dgemm('N', 'N', nbndcoeffs, nexp, nbndcoeffs, 1.0,
1075 &(R.GetBlock(cnt1, cnt1)->GetPtr()[0]), nbndcoeffs,
1076 pLocalIn.data() + cnt, nbndcoeffs, 0.0, pInOut.data() + cnt,
1077 nbndcoeffs);
1078 cnt += nbndcoeffs * nexp;
1079 cnt1 += nexp;
1080 }
1081}
1082
1083/**
1084 * \brief transform the solution coeffiicents from low energy
1085 * back to the original coefficient space.
1086 *
1087 * After the conjugate gradient routine the output vector is in the low
1088 * energy basis and must be trasnformed back to the original basis in
1089 * order to get the correct solution out. the solution vector
1090 * i.e. \f$\mathbf{x}=\mathbf{R^{T}}\mathbf{\overline{x}}\f$.
1091 */
1093 Array<OneD, NekDouble> &pInOut)
1094{
1095 int nLocBndDofs = m_locToGloMap.lock()->GetNumLocalBndCoeffs();
1096
1097 ASSERTL1(pInOut.size() >= nLocBndDofs,
1098 "Output array is not greater than the nLocBndDofs");
1099
1100 // Block transposed transformation matrix
1101 DNekBlkMat &R = *m_RBlk;
1102
1103 Array<OneD, NekDouble> pLocalIn(nLocBndDofs, pInOut.data());
1104
1105 // Multiply by the transpose of block transformation matrix
1106 int cnt = 0;
1107 int cnt1 = 0;
1108 for (int i = 0; i < m_sameBlock.size(); ++i)
1109 {
1110 int nexp = m_sameBlock[i].first;
1111 int nbndcoeffs = m_sameBlock[i].second;
1112 Blas::Dgemm('T', 'N', nbndcoeffs, nexp, nbndcoeffs, 1.0,
1113 &(R.GetBlock(cnt1, cnt1)->GetPtr()[0]), nbndcoeffs,
1114 pLocalIn.data() + cnt, nbndcoeffs, 0.0, pInOut.data() + cnt,
1115 nbndcoeffs);
1116 cnt += nbndcoeffs * nexp;
1117 cnt1 += nexp;
1118 }
1119
1120 Vmath::Vmul(nLocBndDofs, pInOut, 1, m_variablePmask, 1, pInOut, 1);
1121}
1122
1123/**
1124 * \brief Multiply by the block inverse transformation matrix
1125 * This transforms the bassi from Low Energy to original basis
1126 *
1127 * Note; not typically required
1128 */
1129
1131 const Array<OneD, NekDouble> &pInput, Array<OneD, NekDouble> &pOutput)
1132{
1133 int nLocBndDofs = m_locToGloMap.lock()->GetNumLocalBndCoeffs();
1134
1135 ASSERTL1(pInput.size() >= nLocBndDofs,
1136 "Input array is smaller than nLocBndDofs");
1137 ASSERTL1(pOutput.size() >= nLocBndDofs,
1138 "Output array is smaller than nLocBndDofs");
1139
1140 // Block inverse transformation matrix
1141 DNekBlkMat &invR = *m_InvRBlk;
1142
1143 Array<OneD, NekDouble> pLocalIn(nLocBndDofs, pInput.data());
1144
1145 // Multiply by the inverse transformation matrix
1146 int cnt = 0;
1147 int cnt1 = 0;
1148 for (int i = 0; i < m_sameBlock.size(); ++i)
1149 {
1150 int nexp = m_sameBlock[i].first;
1151 int nbndcoeffs = m_sameBlock[i].second;
1152 Blas::Dgemm('N', 'N', nbndcoeffs, nexp, nbndcoeffs, 1.0,
1153 &(invR.GetBlock(cnt1, cnt1)->GetPtr()[0]), nbndcoeffs,
1154 pLocalIn.data() + cnt, nbndcoeffs, 0.0,
1155 pOutput.data() + cnt, nbndcoeffs);
1156 cnt += nbndcoeffs * nexp;
1157 cnt1 += nexp;
1158 }
1159}
1160
1161/**
1162 * \brief Multiply by the block tranposed inverse
1163 * transformation matrix (R^T)^{-1} which is equivlaent to
1164 * transforming coefficients to LowEnergy space
1165 *
1166 * In JCP 2001 paper on low energy this is seen as (C^T)^{-1}
1167 */
1169 const Array<OneD, NekDouble> &pInput, Array<OneD, NekDouble> &pOutput)
1170{
1171 int nLocBndDofs = m_locToGloMap.lock()->GetNumLocalBndCoeffs();
1172
1173 ASSERTL1(pInput.size() >= nLocBndDofs,
1174 "Input array is less than nLocBndDofs");
1175 ASSERTL1(pOutput.size() >= nLocBndDofs,
1176 "Output array is less than nLocBndDofs");
1177
1178 // Block inverse transformation matrix
1179 DNekBlkMat &invR = *m_InvRBlk;
1180
1181 Array<OneD, NekDouble> pLocalIn(nLocBndDofs, pInput.data());
1182
1183 // Multiply by the transpose of block transformation matrix
1184 int cnt = 0;
1185 int cnt1 = 0;
1186 for (int i = 0; i < m_sameBlock.size(); ++i)
1187 {
1188 int nexp = m_sameBlock[i].first;
1189 int nbndcoeffs = m_sameBlock[i].second;
1190 Blas::Dgemm('T', 'N', nbndcoeffs, nexp, nbndcoeffs, 1.0,
1191 &(invR.GetBlock(cnt1, cnt1)->GetPtr()[0]), nbndcoeffs,
1192 pLocalIn.data() + cnt, nbndcoeffs, 0.0,
1193 pOutput.data() + cnt, nbndcoeffs);
1194 cnt += nbndcoeffs * nexp;
1195 cnt1 += nexp;
1196 }
1197}
1198
1199/**
1200 * \brief Set up the transformed block matrix system
1201 *
1202 * Sets up a block elemental matrix in which each of the block matrix is
1203 * the low energy equivalent
1204 * i.e. \f$\mathbf{S}_{2}=\mathbf{R}\mathbf{S}_{1}\mathbf{R}^{T}\f$
1205 */
1207 int n, int bndoffset, const std::shared_ptr<DNekScalMat> &loc_mat)
1208{
1209 std::shared_ptr<MultiRegions::ExpList> expList =
1210 ((m_linsys.lock())->GetLocMat()).lock();
1211
1213 locExpansion = expList->GetExp(n);
1214 unsigned int nbnd = locExpansion->NumBndryCoeffs();
1215
1216 MatrixStorage storage = eFULL;
1217 DNekMatSharedPtr pS2 =
1218 MemoryManager<DNekMat>::AllocateSharedPtr(nbnd, nbnd, 0.0, storage);
1219
1220 // transformation matrices
1221 DNekMat &R = (*m_RBlk->GetBlock(n, n));
1222
1223 // Original Schur Complement
1224 DNekScalMat &S1 = (*loc_mat);
1225
1226 DNekMat Sloc(nbnd, nbnd);
1227
1228 // For variable p we need to just use the active modes
1229 NekDouble val;
1230
1231 for (int i = 0; i < nbnd; ++i)
1232 {
1233 for (int j = 0; j < nbnd; ++j)
1234 {
1235 val = S1(i, j) * m_variablePmask[bndoffset + i] *
1236 m_variablePmask[bndoffset + j];
1237 Sloc.SetValue(i, j, val);
1238 }
1239 }
1240
1241 // create low energy matrix
1242 DNekMat &S2 = (*pS2);
1243
1244 S2 = R * Sloc * Transpose(R);
1245
1246 DNekScalMatSharedPtr return_val;
1247 return_val = MemoryManager<DNekScalMat>::AllocateSharedPtr(1.0, pS2);
1248
1249 return return_val;
1250}
1251
1252/**
1253 * Create the mask array
1254 */
1256{
1257 auto asmMap = m_locToGloMap.lock();
1258 unsigned int nLocBnd = asmMap->GetNumLocalBndCoeffs();
1259
1260 m_signChange = asmMap->GetSignChange();
1261
1262 // Construct a mask array
1264
1265 if (m_signChange)
1266 {
1267 unsigned int i;
1269 asmMap->GetLocalToGlobalBndSign();
1270
1271 for (i = 0; i < nLocBnd; ++i)
1272 {
1273 m_variablePmask[i] = fabs(sign[i]);
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
1312 for (int i = 0; i < nEdges; ++i)
1313 {
1314 std::array<SpatialDomains::PointGeom *, 2> vertsArray;
1315 for (int j = 0; j < 2; ++j)
1316 {
1317 vertsArray[j] = verts[vertexConnectivity[i][j]].get();
1318 }
1320 i, three, vertsArray);
1321 }
1322 for (int i = 0; i < nVerts; ++i)
1323 {
1324 m_holder.m_pointVec.push_back(std::move(verts[i]));
1325 }
1326
1327 ////////////////////////
1328 // Set up Prism faces //
1329 ////////////////////////
1330
1331 constexpr int nFaces = 5;
1332 // quad-edge connectivity base-face0, vertical-quadface2, vertical-quadface4
1333 const int quadEdgeConnectivity[][4] = {
1334 {0, 1, 2, 3}, {1, 6, 8, 5}, {3, 7, 8, 4}};
1335 // QuadId ordered as 0, 1, 2, otherwise return false
1336 const int quadId[] = {0, -1, 1, -1, 2};
1337
1338 // triangle-edge connectivity side-triface-1, side triface-3
1339 const int triEdgeConnectivity[][3] = {{0, 5, 4}, {2, 6, 7}};
1340 // TriId ordered as 0, 1, otherwise return false
1341 const int triId[] = {-1, 0, -1, 1, -1};
1342
1343 // Populate the list of faces
1344 std::array<SpatialDomains::Geometry2D *, nFaces> faces;
1345 for (int f = 0; f < nFaces; ++f)
1346 {
1347 if (f == 1 || f == 3)
1348 {
1349 int i = triId[f];
1350 std::array<SpatialDomains::SegGeom *, 3> edgeArray;
1351 for (int j = 0; j < 3; ++j)
1352 {
1353 edgeArray[j] = edges[triEdgeConnectivity[i][j]].get();
1354 }
1355 auto tmp =
1357 i, edgeArray);
1358 faces[f] = tmp.get();
1359 m_holder.m_triVec.push_back(std::move(tmp));
1360 }
1361 else
1362 {
1363 int i = quadId[f];
1364 std::array<SpatialDomains::SegGeom *, 4> edgeArray;
1365 for (int j = 0; j < 4; ++j)
1366 {
1367 edgeArray[j] = edges[quadEdgeConnectivity[i][j]].get();
1368 }
1369 auto tmp =
1371 i, edgeArray);
1372 faces[f] = tmp.get();
1373 m_holder.m_quadVec.push_back(std::move(tmp));
1374 }
1375 }
1376 for (int i = 0; i < nEdges; ++i)
1377 {
1378 m_holder.m_segVec.push_back(std::move(edges[i]));
1379 }
1380
1383
1384 return geom;
1385}
1386
1387/**
1388 *\brief Sets up the reference prismatic element needed to construct
1389 *a low energy basis mapping arrays
1390 */
1392{
1393 //////////////////////////
1394 // Set up Pyramid element //
1395 //////////////////////////
1396
1397 const int nVerts = 5;
1398 const double point[][3] = {{-1, -1, 0},
1399 {1, -1, 0},
1400 {1, 1, 0},
1401 {-1, 1, 0},
1402 {0, 0, sqrt(double(2))}};
1403
1404 // boost::shared_ptr<SpatialDomains::PointGeom> verts[6];
1405 const int three = 3;
1407 for (int i = 0; i < nVerts; ++i)
1408 {
1410 three, i, point[i][0], point[i][1], point[i][2]);
1411 }
1412 const int nEdges = 8;
1413 const int vertexConnectivity[][2] = {{0, 1}, {1, 2}, {2, 3}, {3, 0},
1414 {0, 4}, {1, 4}, {2, 4}, {3, 4}};
1415
1416 // Populate the list of edges
1418 for (int i = 0; i < nEdges; ++i)
1419 {
1420 std::array<SpatialDomains::PointGeom *, 2> vertsArray;
1421 for (int j = 0; j < 2; ++j)
1422 {
1423 vertsArray[j] = verts[vertexConnectivity[i][j]].get();
1424 }
1426 i, three, vertsArray);
1427 }
1428
1429 ////////////////////////
1430 // Set up Pyramid faces //
1431 ////////////////////////
1432
1433 constexpr int nFaces = 5;
1434 // quad-edge connectivity base-face0,
1435 const int quadEdgeConnectivity[][4] = {{0, 1, 2, 3}};
1436
1437 // triangle-edge connectivity side-triface-1, side triface-2
1438 const int triEdgeConnectivity[][3] = {
1439 {0, 5, 4}, {1, 6, 5}, {2, 7, 6}, {3, 4, 7}};
1440
1441 // Populate the list of faces
1442 std::array<SpatialDomains::Geometry2D *, nFaces> faces;
1443 for (int f = 0; f < nFaces; ++f)
1444 {
1445 if (f == 0)
1446 {
1447 std::array<SpatialDomains::SegGeom *, 4> edgeArray;
1448 for (int j = 0; j < 4; ++j)
1449 {
1450 edgeArray[j] = edges[quadEdgeConnectivity[f][j]].get();
1451 }
1452
1453 auto tmp =
1455 f, edgeArray);
1456 faces[f] = tmp.get();
1457 m_holder.m_quadVec.push_back(std::move(tmp));
1458 }
1459 else
1460 {
1461 int i = f - 1;
1462 std::array<SpatialDomains::SegGeom *, 3> edgeArray;
1463 for (int j = 0; j < 3; ++j)
1464 {
1465 edgeArray[j] = edges[triEdgeConnectivity[i][j]].get();
1466 }
1467 auto tmp =
1469 f, edgeArray);
1470 faces[f] = tmp.get();
1471 m_holder.m_triVec.push_back(std::move(tmp));
1472 }
1473 }
1474 for (int i = 0; i < nEdges; ++i)
1475 {
1476 m_holder.m_segVec.push_back(std::move(edges[i]));
1477 }
1478
1481
1482 return geom;
1483}
1484
1485/**
1486 *\brief Sets up the reference tretrahedral element needed to construct
1487 *a low energy basis
1488 */
1490{
1491 /////////////////////////////////
1492 // Set up Tetrahedron vertices //
1493 /////////////////////////////////
1494
1495 int i, j;
1496 const int three = 3;
1497 const int nVerts = 4;
1498 const double point[][3] = {{-1, -1 / sqrt(double(3)), -1 / sqrt(double(6))},
1499 {1, -1 / sqrt(double(3)), -1 / sqrt(double(6))},
1500 {0, 2 / sqrt(double(3)), -1 / sqrt(double(6))},
1501 {0, 0, 3 / sqrt(double(6))}};
1502
1504 for (i = 0; i < nVerts; ++i)
1505 {
1507 three, i, point[i][0], point[i][1], point[i][2]);
1508 }
1509
1510 //////////////////////////////
1511 // Set up Tetrahedron Edges //
1512 //////////////////////////////
1513
1514 // SegGeom (int id, const int coordim), EdgeComponent(id, coordim)
1515 const int nEdges = 6;
1516 const int vertexConnectivity[][2] = {{0, 1}, {1, 2}, {0, 2},
1517 {0, 3}, {1, 3}, {2, 3}};
1518
1519 // Populate the list of edges
1521 for (i = 0; i < nEdges; ++i)
1522 {
1523 std::array<SpatialDomains::PointGeom *, 2> vertsArray;
1524 for (j = 0; j < 2; ++j)
1525 {
1526 vertsArray[j] = verts[vertexConnectivity[i][j]].get();
1527 }
1528
1530 i, three, vertsArray);
1531 }
1532 for (i = 0; i < nVerts; ++i)
1533 {
1534 m_holder.m_pointVec.push_back(std::move(verts[i]));
1535 }
1536
1537 //////////////////////////////
1538 // Set up Tetrahedron faces //
1539 //////////////////////////////
1540
1541 constexpr int nFaces = 4;
1542 const int edgeConnectivity[][3] = {
1543 {0, 1, 2}, {0, 4, 3}, {1, 5, 4}, {2, 5, 3}};
1544
1545 // Populate the list of faces
1546 std::array<SpatialDomains::TriGeom *, nFaces> faces;
1547 for (i = 0; i < nFaces; ++i)
1548 {
1549 std::array<SpatialDomains::SegGeom *, 3> edgeArray;
1550 for (j = 0; j < 3; ++j)
1551 {
1552 edgeArray[j] = edges[edgeConnectivity[i][j]].get();
1553 }
1554
1556 i, edgeArray);
1557 faces[i] = tmp.get();
1558 m_holder.m_triVec.push_back(std::move(tmp));
1559 }
1560 for (i = 0; i < nEdges; ++i)
1561 {
1562 m_holder.m_segVec.push_back(std::move(edges[i]));
1563 }
1564
1567
1568 return geom;
1569}
1570
1571/**
1572 *\brief Sets up the reference hexahedral element needed to construct
1573 *a low energy basis
1574 */
1576{
1577 ////////////////////////////////
1578 // Set up Hexahedron vertices //
1579 ////////////////////////////////
1580
1581 const int three = 3;
1582
1583 const int nVerts = 8;
1584 const double point[][3] = {{0, 0, 0}, {1, 0, 0}, {1, 1, 0}, {0, 1, 0},
1585 {0, 0, 1}, {1, 0, 1}, {1, 1, 1}, {0, 1, 1}};
1586
1587 // Populate the list of verts
1589 for (int i = 0; i < nVerts; ++i)
1590 {
1592 three, i, point[i][0], point[i][1], point[i][2]);
1593 }
1594
1595 /////////////////////////////
1596 // Set up Hexahedron Edges //
1597 /////////////////////////////
1598
1599 // SegGeom (int id, const int coordim), EdgeComponent(id, coordim)
1600 const int nEdges = 12;
1601 const int vertexConnectivity[][2] = {{0, 1}, {1, 2}, {2, 3}, {0, 3},
1602 {0, 4}, {1, 5}, {2, 6}, {3, 7},
1603 {4, 5}, {5, 6}, {6, 7}, {4, 7}};
1604
1605 // Populate the list of edges
1607 for (int i = 0; i < nEdges; ++i)
1608 {
1609 std::array<SpatialDomains::PointGeom *, 2> vertsArray;
1610 for (int j = 0; j < 2; ++j)
1611 {
1612 vertsArray[j] = verts[vertexConnectivity[i][j]].get();
1613 }
1615 i, three, vertsArray);
1616 }
1617 for (int i = 0; i < nVerts; ++i)
1618 {
1619 m_holder.m_pointVec.push_back(std::move(verts[i]));
1620 }
1621
1622 /////////////////////////////
1623 // Set up Hexahedron faces //
1624 /////////////////////////////
1625
1626 constexpr int nFaces = 6;
1627 const int edgeConnectivity[][4] = {{0, 1, 2, 3}, {0, 5, 8, 4},
1628 {1, 6, 9, 5}, {2, 7, 10, 6},
1629 {3, 7, 11, 4}, {8, 9, 10, 11}};
1630
1631 // Populate the list of faces
1632 std::array<SpatialDomains::QuadGeom *, nFaces> faces;
1633 for (int i = 0; i < nFaces; ++i)
1634 {
1635 std::array<SpatialDomains::SegGeom *, 4> edgeArray;
1636 for (int j = 0; j < 4; ++j)
1637 {
1638 edgeArray[j] = edges[edgeConnectivity[i][j]].get();
1639 }
1641 i, edgeArray);
1642 faces[i] = tmp.get();
1643 m_holder.m_quadVec.push_back(std::move(tmp));
1644 }
1645 for (int i = 0; i < nEdges; ++i)
1646 {
1647 m_holder.m_segVec.push_back(std::move(edges[i]));
1648 }
1649
1652
1653 return geom;
1654}
1655
1656/**
1657 * \brief Loop expansion and determine different variants of the
1658 * transformation matrix
1659 *
1660 * Sets up multiple reference elements based on the element expansion.
1661 */
1663 std::map<ShapeType, DNekScalMatSharedPtr> &maxRmat,
1664 map<ShapeType, LocalRegions::Expansion3DSharedPtr> &maxElmt,
1665 map<ShapeType, Array<OneD, unsigned int>> &vertMapMaxR,
1666 map<ShapeType, Array<OneD, Array<OneD, unsigned int>>> &edgeMapMaxR)
1667{
1668 std::shared_ptr<MultiRegions::ExpList> expList =
1669 ((m_linsys.lock())->GetLocMat()).lock();
1670 GlobalLinSysKey linSysKey = (m_linsys.lock())->GetKey();
1671
1672 LibUtilities::CommSharedPtr vComm = expList->GetComm()->GetSpaceComm();
1673
1675
1676 // face maps for pyramid and hybrid meshes - not need to return.
1677 map<ShapeType, Array<OneD, Array<OneD, unsigned int>>> faceMapMaxR;
1678
1679 /* Determine the maximum expansion order for all elements */
1680 int nummodesmax = 0;
1682
1683 for (int n = 0; n < expList->GetNumElmts(); ++n)
1684 {
1685 locExp = expList->GetExp(n);
1686
1687 nummodesmax = max(nummodesmax, locExp->GetBasisNumModes(0));
1688 nummodesmax = max(nummodesmax, locExp->GetBasisNumModes(1));
1689 nummodesmax = max(nummodesmax, locExp->GetBasisNumModes(2));
1690
1691 Shapes[locExp->DetShapeType()] = 1;
1692 }
1693
1694 vComm->AllReduce(nummodesmax, ReduceMax);
1695 vComm->AllReduce(Shapes, ReduceMax);
1696
1697 if (Shapes[ePyramid] || Shapes[ePrism]) // if Pyramids or Prisms used then
1698 // need Tet and Hex expansion
1699 {
1700 Shapes[eTetrahedron] = 1;
1701 Shapes[eHexahedron] = 1;
1702 }
1703
1704 StdRegions::MatrixType PreconR;
1705 if (linSysKey.GetMatrixType() == StdRegions::eMass)
1706 {
1707 PreconR = StdRegions::ePreconRMass;
1708 }
1709 else
1710 {
1711 PreconR = StdRegions::ePreconR;
1712 }
1713
1717
1718 /*
1719 * Set up a transformation matrices for equal max order
1720 * polynomial meshes
1721 */
1722
1723 if (Shapes[eHexahedron])
1724 {
1726 // Bases for Hex element
1727 const BasisKey HexBa(eModified_A, nummodesmax,
1728 PointsKey(nummodesmax + 1, eGaussLobattoLegendre));
1729 const BasisKey HexBb(eModified_A, nummodesmax,
1730 PointsKey(nummodesmax + 1, eGaussLobattoLegendre));
1731 const BasisKey HexBc(eModified_A, nummodesmax,
1732 PointsKey(nummodesmax + 1, eGaussLobattoLegendre));
1733
1734 // Create reference Hexahdedral expansion
1736
1738 HexBa, HexBb, HexBc, hexgeom.get());
1739 m_holder.m_hexVec.push_back(std::move(hexgeom));
1740
1741 maxElmt[eHexahedron] = HexExp;
1742
1743 // Hex:
1744 HexExp->GetInverseBoundaryMaps(vmap, emap, fmap);
1745 vertMapMaxR[eHexahedron] = vmap;
1746 edgeMapMaxR[eHexahedron] = emap;
1747 faceMapMaxR[eHexahedron] = fmap;
1748
1749 // Get hexahedral transformation matrix
1750 LocalRegions::MatrixKey HexR(PreconR, eHexahedron, *HexExp,
1751 linSysKey.GetConstFactors());
1752 maxRmat[eHexahedron] = HexExp->GetLocMatrix(HexR);
1753 HexExp->DropLocMatrix(HexR); // Need to delete reference from manager
1754 }
1755
1756 if (Shapes[eTetrahedron])
1757 {
1759 // Bases for Tetrahedral element
1760 const BasisKey TetBa(eModified_A, nummodesmax,
1761 PointsKey(nummodesmax + 1, eGaussLobattoLegendre));
1762 const BasisKey TetBb(eModified_B, nummodesmax,
1763 PointsKey(nummodesmax, eGaussRadauMAlpha1Beta0));
1764 const BasisKey TetBc(eModified_C, nummodesmax,
1765 PointsKey(nummodesmax, eGaussRadauMAlpha2Beta0));
1766
1767 // Create reference tetrahedral expansion
1769
1771 TetBa, TetBb, TetBc, tetgeom.get());
1772 m_holder.m_tetVec.push_back(std::move(tetgeom));
1773
1774 maxElmt[eTetrahedron] = TetExp;
1775
1776 TetExp->GetInverseBoundaryMaps(vmap, emap, fmap);
1777 vertMapMaxR[eTetrahedron] = vmap;
1778 edgeMapMaxR[eTetrahedron] = emap;
1779 faceMapMaxR[eTetrahedron] = fmap;
1780
1781 // Get tetrahedral transformation matrix
1782 LocalRegions::MatrixKey TetR(PreconR, eTetrahedron, *TetExp,
1783 linSysKey.GetConstFactors());
1784 maxRmat[eTetrahedron] = TetExp->GetLocMatrix(TetR);
1785 TetExp->DropLocMatrix(TetR); // Need to delete reference from manager
1786
1787 if ((Shapes[ePyramid]) || (Shapes[eHexahedron]))
1788 {
1789 ReSetTetMaxRMat(nummodesmax, TetExp, maxRmat, vertMapMaxR,
1790 edgeMapMaxR, faceMapMaxR);
1791 }
1792 }
1793
1794 if (Shapes[ePyramid])
1795 {
1797
1798 // Bases for Pyramid element
1799 const BasisKey PyrBa(eModified_A, nummodesmax,
1800 PointsKey(nummodesmax + 1, eGaussLobattoLegendre));
1801 const BasisKey PyrBb(eModified_A, nummodesmax,
1802 PointsKey(nummodesmax + 1, eGaussLobattoLegendre));
1803 const BasisKey PyrBc(eModifiedPyr_C, nummodesmax,
1804 PointsKey(nummodesmax, eGaussRadauMAlpha2Beta0));
1805
1806 // Create reference pyramid expansion
1808
1810 PyrBa, PyrBb, PyrBc, pyrgeom.get());
1811 m_holder.m_pyrVec.push_back(std::move(pyrgeom));
1812
1813 maxElmt[ePyramid] = PyrExp;
1814
1815 // Pyramid:
1816 PyrExp->GetInverseBoundaryMaps(vmap, emap, fmap);
1817 vertMapMaxR[ePyramid] = vmap;
1818 edgeMapMaxR[ePyramid] = emap;
1819 faceMapMaxR[ePyramid] = fmap;
1820
1821 // Set up Pyramid Transformation Matrix based on Tet
1822 // and Hex expansion
1823 SetUpPyrMaxRMat(nummodesmax, PyrExp, maxRmat, vertMapMaxR, edgeMapMaxR,
1824 faceMapMaxR);
1825 }
1826
1827 if (Shapes[ePrism])
1828 {
1830 // Bases for Prism element
1831 const BasisKey PrismBa(
1832 eModified_A, nummodesmax,
1833 PointsKey(nummodesmax + 1, eGaussLobattoLegendre));
1834 const BasisKey PrismBb(
1835 eModified_A, nummodesmax,
1836 PointsKey(nummodesmax + 1, eGaussLobattoLegendre));
1837 const BasisKey PrismBc(eModified_B, nummodesmax,
1838 PointsKey(nummodesmax, eGaussRadauMAlpha1Beta0));
1839
1840 // Create reference prismatic expansion
1842
1844 PrismBa, PrismBb, PrismBc, prismgeom.get());
1845 m_holder.m_prismVec.push_back(std::move(prismgeom));
1846 maxElmt[ePrism] = PrismExp;
1847
1848 // Prism:
1849 PrismExp->GetInverseBoundaryMaps(vmap, emap, fmap);
1850 vertMapMaxR[ePrism] = vmap;
1851 edgeMapMaxR[ePrism] = emap;
1852
1853 faceMapMaxR[ePrism] = fmap;
1854
1855 if ((Shapes[ePyramid]) || (Shapes[eHexahedron]))
1856 {
1857 ReSetPrismMaxRMat(nummodesmax, PrismExp, maxRmat, vertMapMaxR,
1858 edgeMapMaxR, faceMapMaxR, false);
1859 }
1860 else
1861 {
1862 // Get prismatic transformation matrix
1863 LocalRegions::MatrixKey PrismR(PreconR, ePrism, *PrismExp,
1864 linSysKey.GetConstFactors());
1865 maxRmat[ePrism] = PrismExp->GetLocMatrix(PrismR);
1866 PrismExp->DropLocMatrix(
1867 PrismR); // Need to delete reference from manager
1868
1869 if (Shapes[eTetrahedron]) // reset triangular faces from Tet
1870 {
1871 ReSetPrismMaxRMat(nummodesmax, PrismExp, maxRmat, vertMapMaxR,
1872 edgeMapMaxR, faceMapMaxR, true);
1873 }
1874 }
1875 }
1876}
1877
1879 int nummodesmax, LocalRegions::PyrExpSharedPtr &PyrExp,
1880 std::map<ShapeType, DNekScalMatSharedPtr> &maxRmat,
1881 std::map<ShapeType, Array<OneD, unsigned int>> &vertMapMaxR,
1882 std::map<ShapeType, Array<OneD, Array<OneD, unsigned int>>> &edgeMapMaxR,
1883 std::map<ShapeType, Array<OneD, Array<OneD, unsigned int>>> &faceMapMaxR)
1884{
1885 int nRows = PyrExp->NumBndryCoeffs();
1886 NekDouble val;
1887 NekDouble zero = 0.0;
1888 DNekMatSharedPtr newmat =
1890
1891 // set diagonal to 1
1892 for (int i = 0; i < nRows; ++i)
1893 {
1894 newmat->SetValue(i, i, 1.0);
1895 }
1896
1897 // The following lists specify the number of adjacent
1898 // edges to each vertex (nadj) then the Hex vert to
1899 // use for each pyramid ver in the vert-edge map (VEVert)
1900 // followed by the hex edge to use for each pyramid edge
1901 // in the vert-edge map (VEEdge)
1902 const int nadjedge[] = {3, 3, 3, 3, 4};
1903 const int VEHexVert[][4] = {{0, 0, 0, -1},
1904 {1, 1, 1, -1},
1905 {2, 2, 2, -1},
1906 {3, 3, 3, -1},
1907 {4, 5, 6, 7}};
1908 const int VEHexEdge[][4] = {{0, 3, 4, -1},
1909 {0, 1, 5, -1},
1910 {1, 2, 6, -1},
1911 {2, 3, 7, -1},
1912 {4, 5, 6, 7}};
1913 const int VEPyrEdge[][4] = {{0, 3, 4, -1},
1914 {0, 1, 5, -1},
1915 {1, 2, 6, -1},
1916 {2, 3, 7, -1},
1917 {4, 5, 6, 7}};
1918
1919 // fill vertex to edge coupling
1920 for (int v = 0; v < 5; ++v)
1921 {
1922 for (int e = 0; e < nadjedge[v]; ++e)
1923 {
1924 for (int i = 0; i < nummodesmax - 2; ++i)
1925 {
1926 // Note this is using wrong shape but gives
1927 // answer that seems to have correct error!
1928 val = (*maxRmat[eHexahedron])(
1929 vertMapMaxR[eHexahedron][VEHexVert[v][e]],
1930 edgeMapMaxR[eHexahedron][VEHexEdge[v][e]][i]);
1931 newmat->SetValue(vertMapMaxR[ePyramid][v],
1932 edgeMapMaxR[ePyramid][VEPyrEdge[v][e]][i],
1933 val);
1934 }
1935 }
1936 }
1937
1938 int nfacemodes;
1939 nfacemodes = (nummodesmax - 2) * (nummodesmax - 2);
1940 // First four verties are all adjacent to base face
1941 for (int v = 0; v < 4; ++v)
1942 {
1943 for (int i = 0; i < nfacemodes; ++i)
1944 {
1945 val = (*maxRmat[eHexahedron])(vertMapMaxR[eHexahedron][v],
1946 faceMapMaxR[eHexahedron][0][i]);
1947 newmat->SetValue(vertMapMaxR[ePyramid][v],
1948 faceMapMaxR[ePyramid][0][i], val);
1949 }
1950 }
1951
1952 const int nadjface[] = {2, 2, 2, 2, 4};
1953 const int VFTetVert[][4] = {{0, 0, -1, -1},
1954 {1, 1, -1, -1},
1955 {2, 2, -1, -1},
1956 {0, 2, -1, -1},
1957 {3, 3, 3, 3}};
1958 const int VFTetFace[][4] = {{1, 3, -1, -1},
1959 {1, 2, -1, -1},
1960 {2, 3, -1, -1},
1961 {1, 3, -1, -1},
1962 {1, 2, 1, 2}};
1963 const int VFPyrFace[][4] = {{1, 4, -1, -1},
1964 {1, 2, -1, -1},
1965 {2, 3, -1, -1},
1966 {3, 4, -1, -1},
1967 {1, 2, 3, 4}};
1968
1969 // next handle all triangular faces from tetrahedron
1970 nfacemodes = (nummodesmax - 3) * (nummodesmax - 2) / 2;
1971 for (int v = 0; v < 5; ++v)
1972 {
1973 for (int f = 0; f < nadjface[v]; ++f)
1974 {
1975 for (int i = 0; i < nfacemodes; ++i)
1976 {
1977 val = (*maxRmat[eTetrahedron])(
1978 vertMapMaxR[eTetrahedron][VFTetVert[v][f]],
1979 faceMapMaxR[eTetrahedron][VFTetFace[v][f]][i]);
1980 newmat->SetValue(vertMapMaxR[ePyramid][v],
1981 faceMapMaxR[ePyramid][VFPyrFace[v][f]][i],
1982 val);
1983 }
1984 }
1985 }
1986
1987 // Edge to face coupling
1988 // all base edges are coupled to face 0
1989 nfacemodes = (nummodesmax - 2) * (nummodesmax - 2);
1990 for (int e = 0; e < 4; ++e)
1991 {
1992 for (int i = 0; i < nummodesmax - 2; ++i)
1993 {
1994 for (int j = 0; j < nfacemodes; ++j)
1995 {
1996 int edgemapid = edgeMapMaxR[eHexahedron][e][i];
1997 int facemapid = faceMapMaxR[eHexahedron][0][j];
1998
1999 val = (*maxRmat[eHexahedron])(edgemapid, facemapid);
2000 newmat->SetValue(edgeMapMaxR[ePyramid][e][i],
2001 faceMapMaxR[ePyramid][0][j], val);
2002 }
2003 }
2004 }
2005
2006 const int nadjface1[] = {1, 1, 1, 1, 2, 2, 2, 2};
2007 const int EFTetEdge[][2] = {{0, -1}, {1, -1}, {0, -1}, {2, -1},
2008 {3, 3}, {4, 4}, {5, 5}, {3, 5}};
2009 const int EFTetFace[][2] = {{1, -1}, {2, -1}, {1, -1}, {3, -1},
2010 {1, 3}, {1, 2}, {2, 3}, {1, 3}};
2011 const int EFPyrFace[][2] = {{1, -1}, {2, -1}, {3, -1}, {4, -1},
2012 {1, 4}, {1, 2}, {2, 3}, {3, 4}};
2013
2014 // next handle all triangular faces from tetrahedron
2015 nfacemodes = (nummodesmax - 3) * (nummodesmax - 2) / 2;
2016 for (int e = 0; e < 8; ++e)
2017 {
2018 for (int f = 0; f < nadjface1[e]; ++f)
2019 {
2020 for (int i = 0; i < nummodesmax - 2; ++i)
2021 {
2022 for (int j = 0; j < nfacemodes; ++j)
2023 {
2024 int edgemapid =
2025 edgeMapMaxR[eTetrahedron][EFTetEdge[e][f]][i];
2026 int facemapid =
2027 faceMapMaxR[eTetrahedron][EFTetFace[e][f]][j];
2028
2029 val = (*maxRmat[eTetrahedron])(edgemapid, facemapid);
2030 newmat->SetValue(edgeMapMaxR[ePyramid][e][i],
2031 faceMapMaxR[ePyramid][EFPyrFace[e][f]][j],
2032 val);
2033 }
2034 }
2035 }
2036 }
2037
2040 maxRmat[ePyramid] = PyrR;
2041}
2042
2044 int nummodesmax, LocalRegions::TetExpSharedPtr &TetExp,
2045 std::map<ShapeType, DNekScalMatSharedPtr> &maxRmat,
2046 std::map<ShapeType, Array<OneD, unsigned int>> &vertMapMaxR,
2047 std::map<ShapeType, Array<OneD, Array<OneD, unsigned int>>> &edgeMapMaxR,
2048 [[maybe_unused]] std::map<ShapeType, Array<OneD, Array<OneD, unsigned int>>>
2049 &faceMapMaxR)
2050{
2051 int nRows = TetExp->NumBndryCoeffs();
2052 NekDouble val;
2053 NekDouble zero = 0.0;
2054 DNekMatSharedPtr newmat =
2056
2057 // copy existing system
2058 for (int i = 0; i < nRows; ++i)
2059 {
2060 for (int j = 0; j < nRows; ++j)
2061 {
2062 val = (*maxRmat[eTetrahedron])(i, j);
2063 newmat->SetValue(i, j, val);
2064 }
2065 }
2066
2067 // The following lists specify the number of adjacent
2068 // edges to each vertex (nadj) then the Hex vert to
2069 // use for each pyramid ver in the vert-edge map (VEVert)
2070 // followed by the hex edge to use for each Tet edge
2071 // in the vert-edge map (VEEdge)
2072 const int VEHexVert[][4] = {{0, 0, 0}, {1, 1, 1}, {2, 2, 2}, {4, 5, 6}};
2073 const int VEHexEdge[][4] = {{0, 3, 4}, {0, 1, 5}, {1, 2, 6}, {4, 5, 6}};
2074 const int VETetEdge[][4] = {{0, 2, 3}, {0, 1, 4}, {1, 2, 5}, {3, 4, 5}};
2075
2076 // fill vertex to edge coupling
2077 for (int v = 0; v < 4; ++v)
2078 {
2079 for (int e = 0; e < 3; ++e)
2080 {
2081 for (int i = 0; i < nummodesmax - 2; ++i)
2082 {
2083 // Note this is using wrong shape but gives
2084 // answer that seems to have correct error!
2085 val = (*maxRmat[eHexahedron])(
2086 vertMapMaxR[eHexahedron][VEHexVert[v][e]],
2087 edgeMapMaxR[eHexahedron][VEHexEdge[v][e]][i]);
2088 newmat->SetValue(vertMapMaxR[eTetrahedron][v],
2089 edgeMapMaxR[eTetrahedron][VETetEdge[v][e]][i],
2090 val);
2091 }
2092 }
2093 }
2094
2097
2098 maxRmat[eTetrahedron] = TetR;
2099}
2100
2102 int nummodesmax, LocalRegions::PrismExpSharedPtr &PrismExp,
2103 std::map<ShapeType, DNekScalMatSharedPtr> &maxRmat,
2104 std::map<ShapeType, Array<OneD, unsigned int>> &vertMapMaxR,
2105 std::map<ShapeType, Array<OneD, Array<OneD, unsigned int>>> &edgeMapMaxR,
2106 std::map<ShapeType, Array<OneD, Array<OneD, unsigned int>>> &faceMapMaxR,
2107 bool UseTetOnly)
2108{
2109 int nRows = PrismExp->NumBndryCoeffs();
2110 NekDouble val;
2111 NekDouble zero = 0.0;
2112 DNekMatSharedPtr newmat =
2114
2115 int nfacemodes;
2116
2117 if (UseTetOnly)
2118 {
2119 // copy existing system
2120 for (int i = 0; i < nRows; ++i)
2121 {
2122 for (int j = 0; j < nRows; ++j)
2123 {
2124 val = (*maxRmat[ePrism])(i, j);
2125 newmat->SetValue(i, j, val);
2126 }
2127 }
2128
2129 // Reset vertex to edge mapping from tet.
2130 const int VETetVert[][2] = {{0, 0}, {1, 1}, {1, 1},
2131 {0, 0}, {3, 3}, {3, 3}};
2132 const int VETetEdge[][2] = {{0, 3}, {0, 4}, {0, 4},
2133 {0, 3}, {3, 4}, {4, 3}};
2134 const int VEPrismEdge[][2] = {{0, 4}, {0, 5}, {2, 6},
2135 {2, 7}, {4, 5}, {6, 7}};
2136
2137 // fill vertex to edge coupling
2138 for (int v = 0; v < 6; ++v)
2139 {
2140 for (int e = 0; e < 2; ++e)
2141 {
2142 for (int i = 0; i < nummodesmax - 2; ++i)
2143 {
2144 // Note this is using wrong shape but gives
2145 // answer that seems to have correct error!
2146 val = (*maxRmat[eTetrahedron])(
2147 vertMapMaxR[eTetrahedron][VETetVert[v][e]],
2148 edgeMapMaxR[eTetrahedron][VETetEdge[v][e]][i]);
2149 newmat->SetValue(vertMapMaxR[ePrism][v],
2150 edgeMapMaxR[ePrism][VEPrismEdge[v][e]][i],
2151 val);
2152 }
2153 }
2154 }
2155 }
2156 else
2157 {
2158 // set diagonal to 1
2159 for (int i = 0; i < nRows; ++i)
2160 {
2161 newmat->SetValue(i, i, 1.0);
2162 }
2163
2164 // Set vertex to edge mapping from Hex.
2165
2166 // The following lists specify the number of adjacent
2167 // edges to each vertex (nadj) then the Hex vert to
2168 // use for each prism ver in the vert-edge map (VEVert)
2169 // followed by the hex edge to use for each prism edge
2170 // in the vert-edge map (VEEdge)
2171 const int VEHexVert[][3] = {{0, 0, 0}, {1, 1, 1}, {2, 2, 2},
2172 {3, 3, 3}, {4, 5, 5}, {6, 7, 7}};
2173 const int VEHexEdge[][3] = {{0, 3, 4}, {0, 1, 5}, {1, 2, 6},
2174 {2, 3, 7}, {4, 5, 9}, {6, 7, 11}};
2175 const int VEPrismEdge[][3] = {{0, 3, 4}, {0, 1, 5}, {1, 2, 6},
2176 {2, 3, 7}, {4, 5, 8}, {6, 7, 8}};
2177
2178 // fill vertex to edge coupling
2179 for (int v = 0; v < 6; ++v)
2180 {
2181 for (int e = 0; e < 3; ++e)
2182 {
2183 for (int i = 0; i < nummodesmax - 2; ++i)
2184 {
2185 // Note this is using wrong shape but gives
2186 // answer that seems to have correct error!
2187 val = (*maxRmat[eHexahedron])(
2188 vertMapMaxR[eHexahedron][VEHexVert[v][e]],
2189 edgeMapMaxR[eHexahedron][VEHexEdge[v][e]][i]);
2190 newmat->SetValue(vertMapMaxR[ePrism][v],
2191 edgeMapMaxR[ePrism][VEPrismEdge[v][e]][i],
2192 val);
2193 }
2194 }
2195 }
2196
2197 // Setup vertex to face mapping from Hex
2198 const int VFHexVert[][2] = {{0, 0}, {1, 1}, {4, 5},
2199 {2, 2}, {3, 3}, {6, 7}};
2200 const int VFHexFace[][2] = {{0, 4}, {0, 2}, {4, 2},
2201 {0, 2}, {0, 4}, {2, 4}};
2202
2203 const int VQFPrismVert[][2] = {{0, 0}, {1, 1}, {4, 4},
2204 {2, 2}, {3, 3}, {5, 5}};
2205 const int VQFPrismFace[][2] = {{0, 4}, {0, 2}, {4, 2},
2206 {0, 2}, {0, 4}, {2, 4}};
2207
2208 nfacemodes = (nummodesmax - 2) * (nummodesmax - 2);
2209 // Replace two Quad faces on every vertex
2210 for (int v = 0; v < 6; ++v)
2211 {
2212 for (int f = 0; f < 2; ++f)
2213 {
2214 for (int i = 0; i < nfacemodes; ++i)
2215 {
2216 val = (*maxRmat[eHexahedron])(
2217 vertMapMaxR[eHexahedron][VFHexVert[v][f]],
2218 faceMapMaxR[eHexahedron][VFHexFace[v][f]][i]);
2219 newmat->SetValue(vertMapMaxR[ePrism][VQFPrismVert[v][f]],
2220 faceMapMaxR[ePrism][VQFPrismFace[v][f]][i],
2221 val);
2222 }
2223 }
2224 }
2225
2226 // Mapping of Hex Edge-Face mappings to Prism Edge-Face Mappings
2227 const int nadjface[] = {1, 2, 1, 2, 1, 1, 1, 1, 2};
2228 const int EFHexEdge[][2] = {{0, -1}, {1, 1}, {2, -1}, {3, 3}, {4, -1},
2229 {5, -1}, {6, -1}, {7, -1}, {9, 11}};
2230 const int EFHexFace[][2] = {{0, -1}, {0, 2}, {0, -1}, {0, 4}, {4, -1},
2231 {2, -1}, {2, -1}, {4, -1}, {2, 4}};
2232 const int EQFPrismEdge[][2] = {{0, -1}, {1, 1}, {2, -1},
2233 {3, 3}, {4, -1}, {5, -1},
2234 {6, -1}, {7, -1}, {8, 8}};
2235 const int EQFPrismFace[][2] = {{0, -1}, {0, 2}, {0, -1},
2236 {0, 4}, {4, -1}, {2, -1},
2237 {2, -1}, {4, -1}, {2, 4}};
2238
2239 // all base edges are coupled to face 0
2240 nfacemodes = (nummodesmax - 2) * (nummodesmax - 2);
2241 for (int e = 0; e < 9; ++e)
2242 {
2243 for (int f = 0; f < nadjface[e]; ++f)
2244 {
2245 for (int i = 0; i < nummodesmax - 2; ++i)
2246 {
2247 for (int j = 0; j < nfacemodes; ++j)
2248 {
2249 int edgemapid =
2250 edgeMapMaxR[eHexahedron][EFHexEdge[e][f]][i];
2251 int facemapid =
2252 faceMapMaxR[eHexahedron][EFHexFace[e][f]][j];
2253
2254 val = (*maxRmat[eHexahedron])(edgemapid, facemapid);
2255
2256 int edgemapid1 =
2257 edgeMapMaxR[ePrism][EQFPrismEdge[e][f]][i];
2258 int facemapid1 =
2259 faceMapMaxR[ePrism][EQFPrismFace[e][f]][j];
2260 newmat->SetValue(edgemapid1, facemapid1, val);
2261 }
2262 }
2263 }
2264 }
2265 }
2266
2267 const int VFTetVert[] = {0, 1, 3, 1, 0, 3};
2268 const int VFTetFace[] = {1, 1, 1, 1, 1, 1};
2269 const int VTFPrismVert[] = {0, 1, 4, 2, 3, 5};
2270 const int VTFPrismFace[] = {1, 1, 1, 3, 3, 3};
2271
2272 // Handle all triangular faces from tetrahedron
2273 nfacemodes = (nummodesmax - 3) * (nummodesmax - 2) / 2;
2274 for (int v = 0; v < 6; ++v)
2275 {
2276 for (int i = 0; i < nfacemodes; ++i)
2277 {
2278 val = (*maxRmat[eTetrahedron])(
2279 vertMapMaxR[eTetrahedron][VFTetVert[v]],
2280 faceMapMaxR[eTetrahedron][VFTetFace[v]][i]);
2281
2282 newmat->SetValue(vertMapMaxR[ePrism][VTFPrismVert[v]],
2283 faceMapMaxR[ePrism][VTFPrismFace[v]][i], val);
2284 }
2285 }
2286
2287 // Mapping of Tet Edge-Face mappings to Prism Edge-Face Mappings
2288 const int EFTetEdge[] = {0, 3, 4, 0, 4, 3};
2289 const int EFTetFace[] = {1, 1, 1, 1, 1, 1};
2290 const int ETFPrismEdge[] = {0, 4, 5, 2, 6, 7};
2291 const int ETFPrismFace[] = {1, 1, 1, 3, 3, 3};
2292
2293 // handle all edge to triangular faces from tetrahedron
2294 // (only 6 this time)
2295 nfacemodes = (nummodesmax - 3) * (nummodesmax - 2) / 2;
2296 for (int e = 0; e < 6; ++e)
2297 {
2298 for (int i = 0; i < nummodesmax - 2; ++i)
2299 {
2300 for (int j = 0; j < nfacemodes; ++j)
2301 {
2302 int edgemapid = edgeMapMaxR[eTetrahedron][EFTetEdge[e]][i];
2303 int facemapid = faceMapMaxR[eTetrahedron][EFTetFace[e]][j];
2304 val = (*maxRmat[eTetrahedron])(edgemapid, facemapid);
2305
2306 newmat->SetValue(edgeMapMaxR[ePrism][ETFPrismEdge[e]][i],
2307 faceMapMaxR[ePrism][ETFPrismFace[e]][j], val);
2308 }
2309 }
2310 }
2311
2312 DNekScalMatSharedPtr PrismR =
2314 maxRmat[ePrism] = PrismR;
2315}
2316
2321{
2322 NekDouble val;
2323 NekDouble zero = 0.0;
2324
2325 int nRows = locExp->NumBndryCoeffs();
2326 DNekMatSharedPtr newmat =
2328
2332
2333 locExp->GetInverseBoundaryMaps(vlocmap, elocmap, flocmap);
2334
2335 // fill diagonal
2336 for (int i = 0; i < nRows; ++i)
2337 {
2338 val = 1.0;
2339 newmat->SetValue(i, i, val);
2340 }
2341
2342 int nverts = locExp->GetNverts();
2343 int nedges = locExp->GetNedges();
2344 int nfaces = locExp->GetNtraces();
2345
2346 // fill vertex to edge coupling
2347 for (int e = 0; e < nedges; ++e)
2348 {
2349 int nEdgeInteriorCoeffs = locExp->GetEdgeNcoeffs(e) - 2;
2350
2351 for (int v = 0; v < nverts; ++v)
2352 {
2353 for (int i = 0; i < nEdgeInteriorCoeffs; ++i)
2354 {
2355 val = (*maxRmat)(vmap[v], emap[e][i]);
2356 newmat->SetValue(vlocmap[v], elocmap[e][i], val);
2357 }
2358 }
2359 }
2360
2361 for (int f = 0; f < nfaces; ++f)
2362 {
2363 // Get details to extrac this face from max reference matrix
2364 StdRegions::Orientation FwdOrient =
2366 int m0, m1; // Local face expansion orders.
2367
2368 int nFaceInteriorCoeffs = locExp->GetTraceIntNcoeffs(f);
2369
2370 locExp->GetTraceNumModes(f, m0, m1, FwdOrient);
2371
2372 Array<OneD, unsigned int> fmapRmat =
2373 maxExp->GetTraceInverseBoundaryMap(f, FwdOrient, m0, m1);
2374
2375 // fill in vertex to face coupling
2376 for (int v = 0; v < nverts; ++v)
2377 {
2378 for (int i = 0; i < nFaceInteriorCoeffs; ++i)
2379 {
2380 val = (*maxRmat)(vmap[v], fmapRmat[i]);
2381 newmat->SetValue(vlocmap[v], flocmap[f][i], val);
2382 }
2383 }
2384
2385 // fill in edges to face coupling
2386 for (int e = 0; e < nedges; ++e)
2387 {
2388 int nEdgeInteriorCoeffs = locExp->GetEdgeNcoeffs(e) - 2;
2389
2390 for (int j = 0; j < nEdgeInteriorCoeffs; ++j)
2391 {
2392 for (int i = 0; i < nFaceInteriorCoeffs; ++i)
2393 {
2394 val = (*maxRmat)(emap[e][j], fmapRmat[i]);
2395 newmat->SetValue(elocmap[e][j], flocmap[f][i], val);
2396 }
2397 }
2398 }
2399 }
2400
2401 return newmat;
2402}
2403} // namespace MultiRegions
2404} // namespace Nektar
#define ASSERTL0(condition, msg)
#define ASSERTL1(condition, msg)
Assert Level 1 – Debugging which is used whether in FULLDEBUG or DEBUG compilation mode....
#define sign(a, b)
return the sign(b)*a
Definition Polylib.cpp:47
Describes the specification for a Basis.
Definition Basis.h:45
tKey RegisterCreatorFunction(tKey idKey, CreatorFunction classCreator, std::string pDesc="")
Register a class with the factory.
Defines a specification for a set of points.
Definition Points.h:50
SpatialDomains::Geometry * GetGeom() const
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.
const std::weak_ptr< GlobalLinSys > m_linsys
std::weak_ptr< AssemblyMap > m_locToGloMap
void v_DoTransformCoeffsFromLowEnergy(Array< OneD, NekDouble > &pInOut) override
transform the solution coeffiicents from low energy back to the original coefficient space.
void ReSetPrismMaxRMat(int nummodesmax, LocalRegions::PrismExpSharedPtr &PirsmExp, ShapeToDNekMap &maxRmat, ShapeToIntArrayMap &vertMapMaxR, ShapeToIntArrayArrayMap &edgeMapMaxR, ShapeToIntArrayArrayMap &faceMapMaxR, bool UseTetOnly)
SpatialDomains::PyrGeomUniquePtr CreateRefPyrGeom(void)
Sets up the reference prismatic element needed to construct a low energy basis mapping arrays.
std::vector< std::pair< int, int > > m_sameBlock
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...
DNekScalMatSharedPtr v_TransformedSchurCompl(int n, int offset, const std::shared_ptr< DNekScalMat > &loc_mat) override
Set up the transformed block matrix system.
DNekMatSharedPtr ExtractLocMat(LocalRegions::Expansion3DSharedPtr &locExp, DNekScalMatSharedPtr &maxRmat, LocalRegions::Expansion3DSharedPtr &expMax, Array< OneD, unsigned int > &vertMapMaxR, Array< OneD, Array< OneD, unsigned int > > &edgeMapMaxR)
SpatialDomains::HexGeomUniquePtr CreateRefHexGeom(void)
Sets up the reference hexahedral element needed to construct a low energy basis.
void v_BuildPreconditioner() override
Construct the low energy preconditioner from .
SpatialDomains::PrismGeomUniquePtr CreateRefPrismGeom(void)
Sets up the reference prismatic element needed to construct a low energy basis.
void ReSetTetMaxRMat(int nummodesmax, LocalRegions::TetExpSharedPtr &TetExp, ShapeToDNekMap &maxRmat, ShapeToIntArrayMap &vertMapMaxR, ShapeToIntArrayArrayMap &edgeMapMaxR, ShapeToIntArrayArrayMap &faceMapMaxR)
static PreconditionerSharedPtr create(const std::shared_ptr< GlobalLinSys > &plinsys, const std::shared_ptr< AssemblyMap > &pLocToGloMap)
Creates an instance of this class.
PreconditionerLowEnergy(const std::shared_ptr< GlobalLinSys > &plinsys, const AssemblyMapSharedPtr &pLocToGloMap)
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...
void v_DoTransformBasisToLowEnergy(Array< OneD, NekDouble > &pInOut) override
Transform the basis vector to low energy space.
void SetUpReferenceElements(ShapeToDNekMap &maxRmat, ShapeToExpMap &maxElmt, ShapeToIntArrayMap &vertMapMaxR, ShapeToIntArrayArrayMap &edgeMapMaxR)
Loop expansion and determine different variants of the transformation matrix.
void v_DoPreconditioner(const Array< OneD, NekDouble > &pInput, Array< OneD, NekDouble > &pOutput, const bool &isLocal=false) override
void SetUpPyrMaxRMat(int nummodesmax, LocalRegions::PyrExpSharedPtr &PyrExp, ShapeToDNekMap &maxRmat, ShapeToIntArrayMap &vertMapMaxR, ShapeToIntArrayArrayMap &edgeMapMaxR, ShapeToIntArrayArrayMap &faceMapMaxR)
SpatialDomains::TetGeomUniquePtr CreateRefTetGeom(void)
Sets up the reference tretrahedral element needed to construct a low energy basis.
static std::unique_ptr< DataType, UniquePtrDeleter > AllocateUniquePtr(const Args &...args)
std::vector< QuadGeomUniquePtr > m_quadVec
Definition MeshGraph.h:115
std::vector< PrismGeomUniquePtr > m_prismVec
Definition MeshGraph.h:118
std::vector< PyrGeomUniquePtr > m_pyrVec
Definition MeshGraph.h:117
std::vector< HexGeomUniquePtr > m_hexVec
Definition MeshGraph.h:119
std::vector< PointGeomUniquePtr > m_pointVec
Definition MeshGraph.h:112
std::vector< SegGeomUniquePtr > m_segVec
Definition MeshGraph.h:113
std::vector< TriGeomUniquePtr > m_triVec
Definition MeshGraph.h:114
std::vector< TetGeomUniquePtr > m_tetVec
Definition MeshGraph.h:116
int GetFid(int i) const
Get the ID of face i of this object.
Definition Geometry.cpp:118
int GetEid(int i) const
Get the ID of edge i of this object.
Definition Geometry.cpp:110
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.
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:383
static gs_data * Init(const Nektar::Array< OneD, long > &pId, const LibUtilities::CommSharedPtr &pComm, bool verbose=true)
Initialise Gather-Scatter map.
Definition GsLib.hpp:190
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:278
@ gs_add
Definition GsLib.hpp:60
@ gs_min
Definition GsLib.hpp:62
static void Free(gs_data *pGsh)
Deallocates GSLib mapping data without finalising MPI.
Definition GsLib.hpp:263
@ eGaussLobattoLegendre
1D Gauss-Lobatto-Legendre quadrature points
Definition PointsType.h:51
std::shared_ptr< Comm > CommSharedPtr
Pointer to a Communicator object.
Definition Comm.h:55
@ eModified_B
Principle Modified Functions .
Definition BasisType.h:49
@ eModified_C
Principle Modified Functions .
Definition BasisType.h:50
@ eModifiedPyr_C
Principle Modified Functions.
Definition BasisType.h:53
@ eModified_A
Principle Modified Functions .
Definition BasisType.h:48
std::shared_ptr< PrismExp > PrismExpSharedPtr
Definition PrismExp.h:207
std::shared_ptr< Expansion > ExpansionSharedPtr
Definition Expansion.h:66
std::shared_ptr< HexExp > HexExpSharedPtr
Definition HexExp.h:258
std::shared_ptr< Expansion2D > Expansion2DSharedPtr
Definition Expansion1D.h:46
std::shared_ptr< PyrExp > PyrExpSharedPtr
Definition PyrExp.h:183
std::shared_ptr< Expansion3D > Expansion3DSharedPtr
Definition Expansion2D.h:47
std::shared_ptr< TetExp > TetExpSharedPtr
Definition TetExp.h:212
PreconFactory & GetPreconFactory()
std::shared_ptr< AssemblyMap > AssemblyMapSharedPtr
Definition AssemblyMap.h:50
std::map< int, std::vector< PeriodicEntity > > PeriodicMap
StdRegions::Orientation DeterminePeriodicFaceOrient(StdRegions::Orientation faceOrient, StdRegions::Orientation perFaceOrient)
Determine relative orientation between two faces.
unique_ptr_objpool< HexGeom > HexGeomUniquePtr
Definition MeshGraph.h:104
unique_ptr_objpool< PyrGeom > PyrGeomUniquePtr
Definition MeshGraph.h:102
unique_ptr_objpool< PrismGeom > PrismGeomUniquePtr
Definition MeshGraph.h:103
unique_ptr_objpool< SegGeom > SegGeomUniquePtr
Definition MeshGraph.h:98
unique_ptr_objpool< PointGeom > PointGeomUniquePtr
Definition MeshGraph.h:93
unique_ptr_objpool< TetGeom > TetGeomUniquePtr
Definition MeshGraph.h:101
std::shared_ptr< DNekScalMat > DNekScalMatSharedPtr
NekMatrix< NekMatrix< NekDouble, StandardMatrixTag >, BlockMatrixTag > DNekBlkMat
std::shared_ptr< DNekScalBlkMat > DNekScalBlkMatSharedPtr
NekMatrix< InnerMatrixType, BlockMatrixTag > Transpose(NekMatrix< InnerMatrixType, BlockMatrixTag > &rhs)
std::shared_ptr< DNekMat > DNekMatSharedPtr
void Vmul(int n, const T *x, const int incx, const T *y, const int incy, T *z, const int incz)
Multiply vector z = x*y.
Definition Vmath.hpp:72
void 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.hpp:577
STL namespace.
scalarT< T > max(scalarT< T > lhs, scalarT< T > rhs)
Definition scalar.hpp:305
scalarT< T > min(scalarT< T > lhs, scalarT< T > rhs)
Definition scalar.hpp:300
scalarT< T > sqrt(scalarT< T > in)
Definition scalar.hpp:290