Nektar++
Loading...
Searching...
No Matches
Public Member Functions | Static Public Member Functions | Static Public Attributes | Protected Member Functions | Protected Attributes | Private Types | Private Member Functions | List of all members
Nektar::MultiRegions::PreconditionerLowEnergy Class Reference

#include <PreconditionerLowEnergy.h>

Inheritance diagram for Nektar::MultiRegions::PreconditionerLowEnergy:
[legend]

Public Member Functions

 PreconditionerLowEnergy (const std::shared_ptr< GlobalLinSys > &plinsys, const AssemblyMapSharedPtr &pLocToGloMap)
 
 ~PreconditionerLowEnergy () override
 
- Public Member Functions inherited from Nektar::MultiRegions::Preconditioner
 Preconditioner (const std::shared_ptr< GlobalLinSys > &plinsys, const AssemblyMapSharedPtr &pLocToGloMap)
 
virtual ~Preconditioner ()
 
void DoPreconditioner (const Array< OneD, NekDouble > &pInput, Array< OneD, NekDouble > &pOutput, const bool &IsLocal=false)
 
void DoAssembleLoc (const Array< OneD, NekDouble > &pInput, Array< OneD, NekDouble > &pOutput, const bool &ZeroDir)
 Apply an assembly and scatter back to lcoal array.
 
void DoPreconditionerWithNonVertOutput (const Array< OneD, NekDouble > &pInput, Array< OneD, NekDouble > &pOutput, const Array< OneD, NekDouble > &pNonVertOutput, Array< OneD, NekDouble > &pVertForce=NullNekDouble1DArray)
 
void DoTransformBasisToLowEnergy (Array< OneD, NekDouble > &pInOut)
 
void DoTransformCoeffsFromLowEnergy (Array< OneD, NekDouble > &pInOut)
 
void DoTransformCoeffsToLowEnergy (const Array< OneD, NekDouble > &pInput, Array< OneD, NekDouble > &pOutput)
 
void DoTransformBasisFromLowEnergy (const Array< OneD, NekDouble > &pInput, Array< OneD, NekDouble > &pOutput)
 
void BuildPreconditioner ()
 
void InitObject ()
 
Array< OneD, NekDoubleAssembleStaticCondGlobalDiagonals ()
 Performs global assembly of diagonal entries to global Schur complement matrix.
 
const DNekScalBlkMatSharedPtrGetBlockTransformedSchurCompl () const
 
const DNekScalBlkMatSharedPtrGetBlockCMatrix () const
 
const DNekScalBlkMatSharedPtrGetBlockInvDMatrix () const
 
const DNekScalBlkMatSharedPtrGetBlockSchurCompl () const
 
const DNekScalBlkMatSharedPtrGetBlockTransformationMatrix () const
 
const DNekScalBlkMatSharedPtrGetBlockTransposedTransformationMatrix () const
 
DNekScalMatSharedPtr TransformedSchurCompl (int offset, int bndoffset, const std::shared_ptr< DNekScalMat > &loc_mat)
 

Static Public Member Functions

static PreconditionerSharedPtr create (const std::shared_ptr< GlobalLinSys > &plinsys, const std::shared_ptr< AssemblyMap > &pLocToGloMap)
 Creates an instance of this class.
 

Static Public Attributes

static std::string className
 Name of class.
 

Protected Member Functions

void v_InitObject () override
 
void v_DoPreconditioner (const Array< OneD, NekDouble > &pInput, Array< OneD, NekDouble > &pOutput, const bool &isLocal=false) override
 
void v_BuildPreconditioner () override
 Construct the low energy preconditioner from \(\mathbf{S}_{2}\).
 
DNekScalMatSharedPtr v_TransformedSchurCompl (int n, int offset, const std::shared_ptr< DNekScalMat > &loc_mat) override
 Set up the transformed block matrix system.
 
void v_DoTransformBasisToLowEnergy (Array< OneD, NekDouble > &pInOut) override
 Transform the basis vector to low energy space.
 
void v_DoTransformCoeffsFromLowEnergy (Array< OneD, NekDouble > &pInOut) override
 transform the solution coeffiicents from low energy back to the original coefficient space.
 
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 original basis.
 
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 transforming coefficients to LowEnergy space.
 
- Protected Member Functions inherited from Nektar::MultiRegions::Preconditioner
virtual void v_DoPreconditionerWithNonVertOutput (const Array< OneD, NekDouble > &pInput, Array< OneD, NekDouble > &pOutput, const Array< OneD, NekDouble > &pNonVertOutput, Array< OneD, NekDouble > &pVertForce)
 Apply a preconditioner to the conjugate gradient method with an output for non-vertex degrees of freedom.
 

Protected Attributes

DNekBlkMatSharedPtr m_BlkMat
 
DNekBlkMatSharedPtr m_RBlk
 
DNekBlkMatSharedPtr m_InvRBlk
 
SpatialDomains::EntityHolder m_holder
 
Array< OneD, NekDoublem_variablePmask
 
bool m_signChange
 
std::vector< std::pair< int, int > > m_sameBlock
 
- Protected Attributes inherited from Nektar::MultiRegions::Preconditioner
const std::weak_ptr< GlobalLinSysm_linsys
 
std::string m_preconType
 
DNekMatSharedPtr m_preconditioner
 
std::weak_ptr< AssemblyMapm_locToGloMap
 

Private Types

typedef std::map< LibUtilities::ShapeType, DNekScalMatSharedPtrShapeToDNekMap
 
typedef std::map< LibUtilities::ShapeType, LocalRegions::Expansion3DSharedPtrShapeToExpMap
 
typedef std::map< LibUtilities::ShapeType, Array< OneD, unsigned int > > ShapeToIntArrayMap
 
typedef std::map< LibUtilities::ShapeType, Array< OneD, Array< OneD, unsigned int > > > ShapeToIntArrayArrayMap
 

Private Member Functions

void SetupBlockTransformationMatrix (void)
 
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)
 
void ReSetTetMaxRMat (int nummodesmax, LocalRegions::TetExpSharedPtr &TetExp, ShapeToDNekMap &maxRmat, ShapeToIntArrayMap &vertMapMaxR, ShapeToIntArrayArrayMap &edgeMapMaxR, ShapeToIntArrayArrayMap &faceMapMaxR)
 
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)
 
void CreateVariablePMask (void)
 
SpatialDomains::TetGeomUniquePtr CreateRefTetGeom (void)
 Sets up the reference tretrahedral element needed to construct a low energy basis.
 
SpatialDomains::PyrGeomUniquePtr CreateRefPyrGeom (void)
 Sets up the reference prismatic element needed to construct a low energy basis mapping arrays.
 
SpatialDomains::PrismGeomUniquePtr CreateRefPrismGeom (void)
 Sets up the reference prismatic element needed to construct a low energy basis.
 
SpatialDomains::HexGeomUniquePtr CreateRefHexGeom (void)
 Sets up the reference hexahedral element needed to construct a low energy basis.
 

Detailed Description

This class implements low energy preconditioning for the conjugate gradient matrix solver.

Definition at line 51 of file PreconditionerLowEnergy.h.

Member Typedef Documentation

◆ ShapeToDNekMap

Definition at line 121 of file PreconditionerLowEnergy.h.

◆ ShapeToExpMap

Definition at line 124 of file PreconditionerLowEnergy.h.

◆ ShapeToIntArrayArrayMap

Definition at line 129 of file PreconditionerLowEnergy.h.

◆ ShapeToIntArrayMap

Definition at line 126 of file PreconditionerLowEnergy.h.

Constructor & Destructor Documentation

◆ PreconditionerLowEnergy()

Nektar::MultiRegions::PreconditionerLowEnergy::PreconditionerLowEnergy ( const std::shared_ptr< GlobalLinSys > &  plinsys,
const AssemblyMapSharedPtr pLocToGloMap 
)

Definition at line 65 of file PreconditionerLowEnergy.cpp.

68 : Preconditioner(plinsys, pLocToGloMap)
69{
70}
Preconditioner(const std::shared_ptr< GlobalLinSys > &plinsys, const AssemblyMapSharedPtr &pLocToGloMap)

◆ ~PreconditionerLowEnergy()

Nektar::MultiRegions::PreconditionerLowEnergy::~PreconditionerLowEnergy ( )
inlineoverride

Definition at line 74 of file PreconditionerLowEnergy.h.

75 {
76 }

Member Function Documentation

◆ create()

static PreconditionerSharedPtr Nektar::MultiRegions::PreconditionerLowEnergy::create ( const std::shared_ptr< GlobalLinSys > &  plinsys,
const std::shared_ptr< AssemblyMap > &  pLocToGloMap 
)
inlinestatic

Creates an instance of this class.

Definition at line 55 of file PreconditionerLowEnergy.h.

58 {
61 plinsys, pLocToGloMap);
62 p->InitObject();
63 return p;
64 }
static std::shared_ptr< DataType > AllocateSharedPtr(const Args &...args)
Allocate a shared pointer from the memory pool.
std::shared_ptr< Preconditioner > PreconditionerSharedPtr
std::vector< double > p(NPUPPER)

References Nektar::MemoryManager< DataType >::AllocateSharedPtr().

◆ CreateRefHexGeom()

SpatialDomains::HexGeomUniquePtr Nektar::MultiRegions::PreconditionerLowEnergy::CreateRefHexGeom ( void  )
private

Sets up the reference hexahedral element needed to construct a low energy basis.

Definition at line 1575 of file PreconditionerLowEnergy.cpp.

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}
static std::unique_ptr< DataType, UniquePtrDeleter > AllocateUniquePtr(const Args &...args)
std::vector< QuadGeomUniquePtr > m_quadVec
Definition MeshGraph.h:115
std::vector< PointGeomUniquePtr > m_pointVec
Definition MeshGraph.h:112
std::vector< SegGeomUniquePtr > m_segVec
Definition MeshGraph.h:113
unique_ptr_objpool< HexGeom > HexGeomUniquePtr
Definition MeshGraph.h:104
unique_ptr_objpool< SegGeom > SegGeomUniquePtr
Definition MeshGraph.h:98
unique_ptr_objpool< PointGeom > PointGeomUniquePtr
Definition MeshGraph.h:93

References Nektar::ObjPoolManager< DataType >::AllocateUniquePtr(), m_holder, Nektar::SpatialDomains::EntityHolder::m_pointVec, Nektar::SpatialDomains::EntityHolder::m_quadVec, and Nektar::SpatialDomains::EntityHolder::m_segVec.

Referenced by SetUpReferenceElements().

◆ CreateRefPrismGeom()

SpatialDomains::PrismGeomUniquePtr Nektar::MultiRegions::PreconditionerLowEnergy::CreateRefPrismGeom ( void  )
private

Sets up the reference prismatic element needed to construct a low energy basis.

Definition at line 1282 of file PreconditionerLowEnergy.cpp.

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}
std::vector< TriGeomUniquePtr > m_triVec
Definition MeshGraph.h:114
unique_ptr_objpool< PrismGeom > PrismGeomUniquePtr
Definition MeshGraph.h:103
scalarT< T > sqrt(scalarT< T > in)
Definition scalar.hpp:290

References Nektar::ObjPoolManager< DataType >::AllocateUniquePtr(), m_holder, Nektar::SpatialDomains::EntityHolder::m_pointVec, Nektar::SpatialDomains::EntityHolder::m_quadVec, Nektar::SpatialDomains::EntityHolder::m_segVec, Nektar::SpatialDomains::EntityHolder::m_triVec, and tinysimd::sqrt().

Referenced by SetUpReferenceElements().

◆ CreateRefPyrGeom()

SpatialDomains::PyrGeomUniquePtr Nektar::MultiRegions::PreconditionerLowEnergy::CreateRefPyrGeom ( void  )
private

Sets up the reference prismatic element needed to construct a low energy basis mapping arrays.

Definition at line 1391 of file PreconditionerLowEnergy.cpp.

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}
unique_ptr_objpool< PyrGeom > PyrGeomUniquePtr
Definition MeshGraph.h:102

References Nektar::ObjPoolManager< DataType >::AllocateUniquePtr(), m_holder, Nektar::SpatialDomains::EntityHolder::m_quadVec, Nektar::SpatialDomains::EntityHolder::m_segVec, Nektar::SpatialDomains::EntityHolder::m_triVec, and tinysimd::sqrt().

Referenced by SetUpReferenceElements().

◆ CreateRefTetGeom()

SpatialDomains::TetGeomUniquePtr Nektar::MultiRegions::PreconditionerLowEnergy::CreateRefTetGeom ( void  )
private

Sets up the reference tretrahedral element needed to construct a low energy basis.

Definition at line 1489 of file PreconditionerLowEnergy.cpp.

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}
unique_ptr_objpool< TetGeom > TetGeomUniquePtr
Definition MeshGraph.h:101

References Nektar::ObjPoolManager< DataType >::AllocateUniquePtr(), m_holder, Nektar::SpatialDomains::EntityHolder::m_pointVec, Nektar::SpatialDomains::EntityHolder::m_segVec, Nektar::SpatialDomains::EntityHolder::m_triVec, and tinysimd::sqrt().

Referenced by SetUpReferenceElements().

◆ CreateVariablePMask()

void Nektar::MultiRegions::PreconditionerLowEnergy::CreateVariablePMask ( void  )
private

Create the mask array

Definition at line 1255 of file PreconditionerLowEnergy.cpp.

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
1263 m_variablePmask = Array<OneD, NekDouble>(nLocBnd, 1.0);
1264
1265 if (m_signChange)
1266 {
1267 unsigned int i;
1268 const Array<OneD, const NekDouble> &sign =
1269 asmMap->GetLocalToGlobalBndSign();
1270
1271 for (i = 0; i < nLocBnd; ++i)
1272 {
1273 m_variablePmask[i] = fabs(sign[i]);
1274 }
1275 }
1276}
#define sign(a, b)
return the sign(b)*a
Definition Polylib.cpp:47
std::weak_ptr< AssemblyMap > m_locToGloMap

References Nektar::MultiRegions::Preconditioner::m_locToGloMap, m_signChange, m_variablePmask, and sign.

Referenced by v_InitObject().

◆ ExtractLocMat()

DNekMatSharedPtr Nektar::MultiRegions::PreconditionerLowEnergy::ExtractLocMat ( LocalRegions::Expansion3DSharedPtr locExp,
DNekScalMatSharedPtr maxRmat,
LocalRegions::Expansion3DSharedPtr expMax,
Array< OneD, unsigned int > &  vertMapMaxR,
Array< OneD, Array< OneD, unsigned int > > &  edgeMapMaxR 
)
private

Definition at line 2317 of file PreconditionerLowEnergy.cpp.

2321{
2322 NekDouble val;
2323 NekDouble zero = 0.0;
2324
2325 int nRows = locExp->NumBndryCoeffs();
2326 DNekMatSharedPtr newmat =
2328
2329 Array<OneD, unsigned int> vlocmap;
2330 Array<OneD, Array<OneD, unsigned int>> elocmap;
2331 Array<OneD, Array<OneD, unsigned int>> flocmap;
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}
std::shared_ptr< DNekMat > DNekMatSharedPtr

References Nektar::MemoryManager< DataType >::AllocateSharedPtr(), Nektar::StdRegions::eDir1FwdDir1_Dir2FwdDir2, and Nektar::eFULL.

Referenced by SetupBlockTransformationMatrix().

◆ ReSetPrismMaxRMat()

void Nektar::MultiRegions::PreconditionerLowEnergy::ReSetPrismMaxRMat ( int  nummodesmax,
LocalRegions::PrismExpSharedPtr PirsmExp,
ShapeToDNekMap maxRmat,
ShapeToIntArrayMap vertMapMaxR,
ShapeToIntArrayArrayMap edgeMapMaxR,
ShapeToIntArrayArrayMap faceMapMaxR,
bool  UseTetOnly 
)
private

Definition at line 2101 of file PreconditionerLowEnergy.cpp.

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}
std::shared_ptr< DNekScalMat > DNekScalMatSharedPtr

References Nektar::MemoryManager< DataType >::AllocateSharedPtr(), Nektar::eFULL, Nektar::LibUtilities::eHexahedron, Nektar::LibUtilities::ePrism, and Nektar::LibUtilities::eTetrahedron.

Referenced by SetUpReferenceElements().

◆ ReSetTetMaxRMat()

void Nektar::MultiRegions::PreconditionerLowEnergy::ReSetTetMaxRMat ( int  nummodesmax,
LocalRegions::TetExpSharedPtr TetExp,
ShapeToDNekMap maxRmat,
ShapeToIntArrayMap vertMapMaxR,
ShapeToIntArrayArrayMap edgeMapMaxR,
ShapeToIntArrayArrayMap faceMapMaxR 
)
private

Definition at line 2043 of file PreconditionerLowEnergy.cpp.

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}

References Nektar::MemoryManager< DataType >::AllocateSharedPtr(), Nektar::eFULL, Nektar::LibUtilities::eHexahedron, and Nektar::LibUtilities::eTetrahedron.

Referenced by SetUpReferenceElements().

◆ SetupBlockTransformationMatrix()

void Nektar::MultiRegions::PreconditionerLowEnergy::SetupBlockTransformationMatrix ( void  )
private

Set a block transformation matrices for each element type. These are needed in routines that transform the schur complement matrix to and from the low energy basis.

Definition at line 939 of file PreconditionerLowEnergy.cpp.

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}
const std::weak_ptr< GlobalLinSys > m_linsys
std::vector< std::pair< int, int > > m_sameBlock
DNekMatSharedPtr ExtractLocMat(LocalRegions::Expansion3DSharedPtr &locExp, DNekScalMatSharedPtr &maxRmat, LocalRegions::Expansion3DSharedPtr &expMax, Array< OneD, unsigned int > &vertMapMaxR, Array< OneD, Array< OneD, unsigned int > > &edgeMapMaxR)
void SetUpReferenceElements(ShapeToDNekMap &maxRmat, ShapeToExpMap &maxElmt, ShapeToIntArrayMap &vertMapMaxR, ShapeToIntArrayArrayMap &edgeMapMaxR)
Loop expansion and determine different variants of the transformation matrix.
std::shared_ptr< Expansion3D > Expansion3DSharedPtr
Definition Expansion2D.h:47

References Nektar::MemoryManager< DataType >::AllocateSharedPtr(), Nektar::StdRegions::StdExpansion::DetShapeType(), Nektar::eDIAGONAL, ExtractLocMat(), m_InvRBlk, Nektar::MultiRegions::Preconditioner::m_linsys, Nektar::MultiRegions::Preconditioner::m_locToGloMap, m_RBlk, m_sameBlock, and SetUpReferenceElements().

Referenced by v_InitObject().

◆ SetUpPyrMaxRMat()

void Nektar::MultiRegions::PreconditionerLowEnergy::SetUpPyrMaxRMat ( int  nummodesmax,
LocalRegions::PyrExpSharedPtr PyrExp,
ShapeToDNekMap maxRmat,
ShapeToIntArrayMap vertMapMaxR,
ShapeToIntArrayArrayMap edgeMapMaxR,
ShapeToIntArrayArrayMap faceMapMaxR 
)
private

Definition at line 1878 of file PreconditionerLowEnergy.cpp.

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}

References Nektar::MemoryManager< DataType >::AllocateSharedPtr(), Nektar::eFULL, Nektar::LibUtilities::eHexahedron, Nektar::LibUtilities::ePyramid, and Nektar::LibUtilities::eTetrahedron.

Referenced by SetUpReferenceElements().

◆ SetUpReferenceElements()

void Nektar::MultiRegions::PreconditionerLowEnergy::SetUpReferenceElements ( ShapeToDNekMap maxRmat,
ShapeToExpMap maxElmt,
ShapeToIntArrayMap vertMapMaxR,
ShapeToIntArrayArrayMap edgeMapMaxR 
)
private

Loop expansion and determine different variants of the transformation matrix.

Sets up multiple reference elements based on the element expansion.

Definition at line 1662 of file PreconditionerLowEnergy.cpp.

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;
1681 Array<OneD, int> Shapes(LibUtilities::SIZE_ShapeType, 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
1714 Array<OneD, unsigned int> vmap;
1715 Array<OneD, Array<OneD, unsigned int>> emap;
1716 Array<OneD, Array<OneD, unsigned int>> fmap;
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}
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.
SpatialDomains::HexGeomUniquePtr CreateRefHexGeom(void)
Sets up the reference hexahedral element needed to construct a low energy basis.
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)
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.
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< TetGeomUniquePtr > m_tetVec
Definition MeshGraph.h:116
@ 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< PyrExp > PyrExpSharedPtr
Definition PyrExp.h:183
std::shared_ptr< TetExp > TetExpSharedPtr
Definition TetExp.h:212
scalarT< T > max(scalarT< T > lhs, scalarT< T > rhs)
Definition scalar.hpp:305

References Nektar::MemoryManager< DataType >::AllocateSharedPtr(), CreateRefHexGeom(), CreateRefPrismGeom(), CreateRefPyrGeom(), CreateRefTetGeom(), Nektar::LibUtilities::eGaussLobattoLegendre, Nektar::LibUtilities::eHexahedron, Nektar::StdRegions::eMass, Nektar::LibUtilities::eModified_A, Nektar::LibUtilities::eModified_B, Nektar::LibUtilities::eModified_C, Nektar::LibUtilities::eModifiedPyr_C, Nektar::StdRegions::ePreconR, Nektar::StdRegions::ePreconRMass, Nektar::LibUtilities::ePrism, Nektar::LibUtilities::ePyramid, Nektar::LibUtilities::eTetrahedron, Nektar::MultiRegions::GlobalMatrixKey::GetConstFactors(), Nektar::MultiRegions::GlobalMatrixKey::GetMatrixType(), Nektar::SpatialDomains::EntityHolder::m_hexVec, m_holder, Nektar::MultiRegions::Preconditioner::m_linsys, Nektar::SpatialDomains::EntityHolder::m_prismVec, Nektar::SpatialDomains::EntityHolder::m_pyrVec, Nektar::SpatialDomains::EntityHolder::m_tetVec, tinysimd::max(), Nektar::LibUtilities::ReduceMax, ReSetPrismMaxRMat(), ReSetTetMaxRMat(), SetUpPyrMaxRMat(), and Nektar::LibUtilities::SIZE_ShapeType.

Referenced by SetupBlockTransformationMatrix().

◆ v_BuildPreconditioner()

void Nektar::MultiRegions::PreconditionerLowEnergy::v_BuildPreconditioner ( )
overrideprotectedvirtual

Construct the low energy preconditioner from \(\mathbf{S}_{2}\).

\[\mathbf{M}^{-1}=\left[\begin{array}{ccc} Diag[(\mathbf{S_{2}})_{vv}] & & \\ & (\mathbf{S}_{2})_{eb} & \\ & & (\mathbf{S}_{2})_{fb} \end{array}\right] \]

where \(\mathbf{R}\) is the transformation matrix and \(\mathbf{S}_{2}\) the Schur complement of the modified basis, given by

\[\mathbf{S}_{2}=\mathbf{R}\mathbf{S}_{1}\mathbf{R}^{T}\]

where \(\mathbf{S}_{1}\) is the local schur complement matrix for each element.

  • Count edges, face and add up min edges and min face sizes

Reimplemented from Nektar::MultiRegions::Preconditioner.

Definition at line 115 of file PreconditionerLowEnergy.cpp.

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();
183 const Array<OneD, const SpatialDomains::BoundaryConditionShPtr>
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}
#define ASSERTL1(condition, msg)
Assert Level 1 – Debugging which is used whether in FULLDEBUG or DEBUG compilation mode....
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
std::shared_ptr< Expansion2D > Expansion2DSharedPtr
Definition Expansion1D.h:46
std::map< int, std::vector< PeriodicEntity > > PeriodicMap
StdRegions::Orientation DeterminePeriodicFaceOrient(StdRegions::Orientation faceOrient, StdRegions::Orientation perFaceOrient)
Determine relative orientation between two faces.
NekMatrix< NekMatrix< NekDouble, StandardMatrixTag >, ScaledMatrixTag > DNekScalMat
NekMatrix< NekDouble, StandardMatrixTag > DNekMat
std::shared_ptr< DNekScalBlkMat > DNekScalBlkMatSharedPtr
NekMatrix< InnerMatrixType, BlockMatrixTag > Transpose(NekMatrix< InnerMatrixType, BlockMatrixTag > &rhs)
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
scalarT< T > min(scalarT< T > lhs, scalarT< T > rhs)
Definition scalar.hpp:300

References Nektar::MemoryManager< DataType >::AllocateSharedPtr(), ASSERTL1, Vmath::Assmb(), Nektar::MultiRegions::DeterminePeriodicFaceOrient(), Nektar::eDIAGONAL, Nektar::SpatialDomains::eDirichlet, Nektar::eFULL, Gs::Free(), Gs::Gather(), Nektar::StdRegions::StdExpansion3D::GetEdgeNcoeffs(), Nektar::SpatialDomains::Geometry::GetEid(), Nektar::SpatialDomains::Geometry::GetFid(), Nektar::LocalRegions::Expansion::GetGeom(), Nektar::StdRegions::StdExpansion3D::GetNedges(), Gs::gs_add, Gs::gs_min, Gs::Init(), m_BlkMat, Nektar::MultiRegions::Preconditioner::m_linsys, Nektar::MultiRegions::Preconditioner::m_locToGloMap, m_RBlk, m_variablePmask, tinysimd::max(), tinysimd::min(), Nektar::StdRegions::StdExpansion::NumBndryCoeffs(), Nektar::LibUtilities::ReduceMax, and Nektar::Transpose().

◆ v_DoPreconditioner()

void Nektar::MultiRegions::PreconditionerLowEnergy::v_DoPreconditioner ( const Array< OneD, NekDouble > &  pInput,
Array< OneD, NekDouble > &  pOutput,
const bool &  isLocal = false 
)
overrideprotectedvirtual

Apply the low energy preconditioner during the conjugate gradient routine

Reimplemented from Nektar::MultiRegions::Preconditioner.

Definition at line 915 of file PreconditionerLowEnergy.cpp.

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}
#define ASSERTL0(condition, msg)
std::vector< double > z(NPUPPER)
NekMatrix< NekMatrix< NekDouble, StandardMatrixTag >, BlockMatrixTag > DNekBlkMat

References ASSERTL0, Nektar::eWrapper, and Nektar::MultiRegions::Preconditioner::m_locToGloMap.

◆ v_DoTransformBasisFromLowEnergy()

void Nektar::MultiRegions::PreconditionerLowEnergy::v_DoTransformBasisFromLowEnergy ( const Array< OneD, NekDouble > &  pInput,
Array< OneD, NekDouble > &  pOutput 
)
overrideprotectedvirtual

Multiply by the block inverse transformation matrix This transforms the bassi from Low Energy to original basis.

Note; not typically required

Reimplemented from Nektar::MultiRegions::Preconditioner.

Definition at line 1130 of file PreconditionerLowEnergy.cpp.

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}
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

References ASSERTL1, Blas::Dgemm(), m_InvRBlk, Nektar::MultiRegions::Preconditioner::m_locToGloMap, and m_sameBlock.

◆ v_DoTransformBasisToLowEnergy()

void Nektar::MultiRegions::PreconditionerLowEnergy::v_DoTransformBasisToLowEnergy ( Array< OneD, NekDouble > &  pInOut)
overrideprotectedvirtual

Transform the basis vector to low energy space.

As the conjugate gradient system is solved for the low energy basis, the solution vector \(\mathbf{x}\) must be transformed to the low energy basis i.e. \(\overline{\mathbf{x}}=\mathbf{R}\mathbf{x}\).

Reimplemented from Nektar::MultiRegions::Preconditioner.

Definition at line 1054 of file PreconditionerLowEnergy.cpp.

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}
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

References Blas::Dgemm(), Nektar::MultiRegions::Preconditioner::m_locToGloMap, m_RBlk, m_sameBlock, m_variablePmask, and Vmath::Vmul().

◆ v_DoTransformCoeffsFromLowEnergy()

void Nektar::MultiRegions::PreconditionerLowEnergy::v_DoTransformCoeffsFromLowEnergy ( Array< OneD, NekDouble > &  pInOut)
overrideprotectedvirtual

transform the solution coeffiicents from low energy back to the original coefficient space.

After the conjugate gradient routine the output vector is in the low energy basis and must be trasnformed back to the original basis in order to get the correct solution out. the solution vector i.e. \(\mathbf{x}=\mathbf{R^{T}}\mathbf{\overline{x}}\).

Reimplemented from Nektar::MultiRegions::Preconditioner.

Definition at line 1092 of file PreconditionerLowEnergy.cpp.

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}

References ASSERTL1, Blas::Dgemm(), Nektar::MultiRegions::Preconditioner::m_locToGloMap, m_RBlk, m_sameBlock, m_variablePmask, and Vmath::Vmul().

◆ v_DoTransformCoeffsToLowEnergy()

void Nektar::MultiRegions::PreconditionerLowEnergy::v_DoTransformCoeffsToLowEnergy ( const Array< OneD, NekDouble > &  pInput,
Array< OneD, NekDouble > &  pOutput 
)
overrideprotectedvirtual

Multiply by the block tranposed inverse transformation matrix (R^T)^{-1} which is equivlaent to transforming coefficients to LowEnergy space.

In JCP 2001 paper on low energy this is seen as (C^T)^{-1}

Reimplemented from Nektar::MultiRegions::Preconditioner.

Definition at line 1168 of file PreconditionerLowEnergy.cpp.

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}

References ASSERTL1, Blas::Dgemm(), m_InvRBlk, Nektar::MultiRegions::Preconditioner::m_locToGloMap, and m_sameBlock.

◆ v_InitObject()

void Nektar::MultiRegions::PreconditionerLowEnergy::v_InitObject ( )
overrideprotectedvirtual

Reimplemented from Nektar::MultiRegions::Preconditioner.

Definition at line 72 of file PreconditionerLowEnergy.cpp.

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}

References ASSERTL0, CreateVariablePMask(), Nektar::MultiRegions::eIterativeStaticCond, Nektar::MultiRegions::ePETScStaticCond, Nektar::MultiRegions::Preconditioner::m_linsys, Nektar::MultiRegions::Preconditioner::m_locToGloMap, and SetupBlockTransformationMatrix().

◆ v_TransformedSchurCompl()

DNekScalMatSharedPtr Nektar::MultiRegions::PreconditionerLowEnergy::v_TransformedSchurCompl ( int  n,
int  bndoffset,
const std::shared_ptr< DNekScalMat > &  loc_mat 
)
overrideprotectedvirtual

Set up the transformed block matrix system.

Sets up a block elemental matrix in which each of the block matrix is the low energy equivalent i.e. \(\mathbf{S}_{2}=\mathbf{R}\mathbf{S}_{1}\mathbf{R}^{T}\)

Reimplemented from Nektar::MultiRegions::Preconditioner.

Definition at line 1206 of file PreconditionerLowEnergy.cpp.

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}

References Nektar::MemoryManager< DataType >::AllocateSharedPtr(), Nektar::eFULL, Nektar::MultiRegions::Preconditioner::m_linsys, m_RBlk, m_variablePmask, and Nektar::Transpose().

Member Data Documentation

◆ className

string Nektar::MultiRegions::PreconditionerLowEnergy::className
static
Initial value:
=
"LowEnergy Preconditioning")
tKey RegisterCreatorFunction(tKey idKey, CreatorFunction classCreator, std::string pDesc="")
Register a class with the factory.
static PreconditionerSharedPtr create(const std::shared_ptr< GlobalLinSys > &plinsys, const std::shared_ptr< AssemblyMap > &pLocToGloMap)
Creates an instance of this class.
PreconFactory & GetPreconFactory()

Name of class.

Registers the class with the Factory.

Definition at line 67 of file PreconditionerLowEnergy.h.

◆ m_BlkMat

DNekBlkMatSharedPtr Nektar::MultiRegions::PreconditionerLowEnergy::m_BlkMat
protected

Definition at line 79 of file PreconditionerLowEnergy.h.

Referenced by v_BuildPreconditioner().

◆ m_holder

SpatialDomains::EntityHolder Nektar::MultiRegions::PreconditionerLowEnergy::m_holder
protected

◆ m_InvRBlk

DNekBlkMatSharedPtr Nektar::MultiRegions::PreconditionerLowEnergy::m_InvRBlk
protected

◆ m_RBlk

DNekBlkMatSharedPtr Nektar::MultiRegions::PreconditionerLowEnergy::m_RBlk
protected

◆ m_sameBlock

std::vector<std::pair<int, int> > Nektar::MultiRegions::PreconditionerLowEnergy::m_sameBlock
protected

◆ m_signChange

bool Nektar::MultiRegions::PreconditionerLowEnergy::m_signChange
protected

Definition at line 86 of file PreconditionerLowEnergy.h.

Referenced by CreateVariablePMask().

◆ m_variablePmask

Array<OneD, NekDouble> Nektar::MultiRegions::PreconditionerLowEnergy::m_variablePmask
protected