Nektar++
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)
 
virtual ~PreconditionerLowEnergy ()
 
- 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)
 
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. More...
 
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. More...
 

Static Public Attributes

static std::string className
 Name of class. More...
 

Protected Member Functions

virtual void v_InitObject () override
 
virtual void v_DoPreconditioner (const Array< OneD, NekDouble > &pInput, Array< OneD, NekDouble > &pOutput) override
 
virtual void v_BuildPreconditioner () override
 Construct the low energy preconditioner from \(\mathbf{S}_{2}\). More...
 
virtual DNekScalMatSharedPtr v_TransformedSchurCompl (int n, int offset, const std::shared_ptr< DNekScalMat > &loc_mat) override
 Set up the transformed block matrix system. More...
 
virtual void v_DoTransformBasisToLowEnergy (Array< OneD, NekDouble > &pInOut) override
 Transform the basis vector to low energy space. More...
 
virtual void v_DoTransformCoeffsFromLowEnergy (Array< OneD, NekDouble > &pInOut) override
 transform the solution coeffiicents from low energy back to the original coefficient space. More...
 
virtual void v_DoTransformBasisFromLowEnergy (const Array< OneD, NekDouble > &pInput, Array< OneD, NekDouble > &pOutput) override
 Multiply by the block inverse transformation matrix This transforms the bassi from Low Energy to original basis. More...
 
virtual void v_DoTransformCoeffsToLowEnergy (const Array< OneD, NekDouble > &pInput, Array< OneD, NekDouble > &pOutput) override
 Multiply by the block tranposed inverse transformation matrix (R^T)^{-1} which is equivlaent to transforming coefficients to LowEnergy space. More...
 
- 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. More...
 

Protected Attributes

DNekBlkMatSharedPtr m_BlkMat
 
DNekBlkMatSharedPtr m_RBlk
 
DNekBlkMatSharedPtr m_InvRBlk
 
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
 
PreconditionerType m_preconType
 
DNekMatSharedPtr m_preconditioner
 
std::weak_ptr< AssemblyMapm_locToGloMap
 
LibUtilities::CommSharedPtr m_comm
 

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. More...
 
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::TetGeomSharedPtr CreateRefTetGeom (void)
 Sets up the reference tretrahedral element needed to construct a low energy basis. More...
 
SpatialDomains::PyrGeomSharedPtr CreateRefPyrGeom (void)
 Sets up the reference prismatic element needed to construct a low energy basis mapping arrays. More...
 
SpatialDomains::PrismGeomSharedPtr CreateRefPrismGeom (void)
 Sets up the reference prismatic element needed to construct a low energy basis. More...
 
SpatialDomains::HexGeomSharedPtr CreateRefHexGeom (void)
 Sets up the reference hexahedral element needed to construct a low energy basis. More...
 

Detailed Description

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

Definition at line 53 of file PreconditionerLowEnergy.h.

Member Typedef Documentation

◆ ShapeToDNekMap

Definition at line 122 of file PreconditionerLowEnergy.h.

◆ ShapeToExpMap

Definition at line 125 of file PreconditionerLowEnergy.h.

◆ ShapeToIntArrayArrayMap

Definition at line 130 of file PreconditionerLowEnergy.h.

◆ ShapeToIntArrayMap

Definition at line 127 of file PreconditionerLowEnergy.h.

Constructor & Destructor Documentation

◆ PreconditionerLowEnergy()

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

Definition at line 66 of file PreconditionerLowEnergy.cpp.

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

◆ ~PreconditionerLowEnergy()

virtual Nektar::MultiRegions::PreconditionerLowEnergy::~PreconditionerLowEnergy ( )
inlinevirtual

Definition at line 76 of file PreconditionerLowEnergy.h.

77  {
78  }

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 57 of file PreconditionerLowEnergy.h.

60  {
63  plinsys, pLocToGloMap);
64  p->InitObject();
65  return p;
66  }
static std::shared_ptr< DataType > AllocateSharedPtr(const Args &...args)
Allocate a shared pointer from the memory pool.
std::shared_ptr< Preconditioner > PreconditionerSharedPtr
Definition: GlobalLinSys.h:60

References Nektar::MemoryManager< DataType >::AllocateSharedPtr(), and CellMLToNektar.cellml_metadata::p.

◆ CreateRefHexGeom()

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

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

Definition at line 1545 of file PreconditionerLowEnergy.cpp.

1546 {
1547  ////////////////////////////////
1548  // Set up Hexahedron vertices //
1549  ////////////////////////////////
1550 
1551  const int three = 3;
1552 
1553  const int nVerts = 8;
1554  const double point[][3] = {{0, 0, 0}, {1, 0, 0}, {1, 1, 0}, {0, 1, 0},
1555  {0, 0, 1}, {1, 0, 1}, {1, 1, 1}, {0, 1, 1}};
1556 
1557  // Populate the list of verts
1559  for (int i = 0; i < nVerts; ++i)
1560  {
1562  three, i, point[i][0], point[i][1], point[i][2]);
1563  }
1564 
1565  /////////////////////////////
1566  // Set up Hexahedron Edges //
1567  /////////////////////////////
1568 
1569  // SegGeom (int id, const int coordim), EdgeComponent(id, coordim)
1570  const int nEdges = 12;
1571  const int vertexConnectivity[][2] = {{0, 1}, {1, 2}, {2, 3}, {0, 3},
1572  {0, 4}, {1, 5}, {2, 6}, {3, 7},
1573  {4, 5}, {5, 6}, {6, 7}, {4, 7}};
1574 
1575  // Populate the list of edges
1576  SpatialDomains::SegGeomSharedPtr edges[nEdges];
1577  for (int i = 0; i < nEdges; ++i)
1578  {
1579  SpatialDomains::PointGeomSharedPtr vertsArray[2];
1580  for (int j = 0; j < 2; ++j)
1581  {
1582  vertsArray[j] = verts[vertexConnectivity[i][j]];
1583  }
1585  i, three, vertsArray);
1586  }
1587 
1588  /////////////////////////////
1589  // Set up Hexahedron faces //
1590  /////////////////////////////
1591 
1592  const int nFaces = 6;
1593  const int edgeConnectivity[][4] = {{0, 1, 2, 3}, {0, 5, 8, 4},
1594  {1, 6, 9, 5}, {2, 7, 10, 6},
1595  {3, 7, 11, 4}, {8, 9, 10, 11}};
1596 
1597  // Populate the list of faces
1598  SpatialDomains::QuadGeomSharedPtr faces[nFaces];
1599  for (int i = 0; i < nFaces; ++i)
1600  {
1601  SpatialDomains::SegGeomSharedPtr edgeArray[4];
1602  for (int j = 0; j < 4; ++j)
1603  {
1604  edgeArray[j] = edges[edgeConnectivity[i][j]];
1605  }
1607  i, edgeArray);
1608  }
1609 
1612 
1613  return geom;
1614 }
std::shared_ptr< QuadGeom > QuadGeomSharedPtr
Definition: HexGeom.h:46
std::shared_ptr< HexGeom > HexGeomSharedPtr
Definition: HexGeom.h:87
std::shared_ptr< SegGeom > SegGeomSharedPtr
Definition: Geometry2D.h:62
std::shared_ptr< PointGeom > PointGeomSharedPtr
Definition: Geometry.h:59

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

Referenced by SetUpReferenceElements().

◆ CreateRefPrismGeom()

SpatialDomains::PrismGeomSharedPtr 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
1311  SpatialDomains::SegGeomSharedPtr edges[nEdges];
1312  for (int i = 0; i < nEdges; ++i)
1313  {
1314  SpatialDomains::PointGeomSharedPtr vertsArray[2];
1315  for (int j = 0; j < 2; ++j)
1316  {
1317  vertsArray[j] = verts[vertexConnectivity[i][j]];
1318  }
1320  i, three, vertsArray);
1321  }
1322 
1323  ////////////////////////
1324  // Set up Prism faces //
1325  ////////////////////////
1326 
1327  const int nFaces = 5;
1328  // quad-edge connectivity base-face0, vertical-quadface2, vertical-quadface4
1329  const int quadEdgeConnectivity[][4] = {
1330  {0, 1, 2, 3}, {1, 6, 8, 5}, {3, 7, 8, 4}};
1331  // QuadId ordered as 0, 1, 2, otherwise return false
1332  const int quadId[] = {0, -1, 1, -1, 2};
1333 
1334  // triangle-edge connectivity side-triface-1, side triface-3
1335  const int triEdgeConnectivity[][3] = {{0, 5, 4}, {2, 6, 7}};
1336  // TriId ordered as 0, 1, otherwise return false
1337  const int triId[] = {-1, 0, -1, 1, -1};
1338 
1339  // Populate the list of faces
1341  for (int f = 0; f < nFaces; ++f)
1342  {
1343  if (f == 1 || f == 3)
1344  {
1345  int i = triId[f];
1346  SpatialDomains::SegGeomSharedPtr edgeArray[3];
1347  for (int j = 0; j < 3; ++j)
1348  {
1349  edgeArray[j] = edges[triEdgeConnectivity[i][j]];
1350  }
1351  faces[f] =
1353  f, edgeArray);
1354  }
1355  else
1356  {
1357  int i = quadId[f];
1358  SpatialDomains::SegGeomSharedPtr edgeArray[4];
1359  for (int j = 0; j < 4; ++j)
1360  {
1361  edgeArray[j] = edges[quadEdgeConnectivity[i][j]];
1362  }
1363  faces[f] =
1365  f, edgeArray);
1366  }
1367  }
1368 
1371 
1372  return geom;
1373 }
std::shared_ptr< PrismGeom > PrismGeomSharedPtr
Definition: PrismGeom.h:85
std::shared_ptr< Geometry2D > Geometry2DSharedPtr
Definition: Geometry.h:65
scalarT< T > sqrt(scalarT< T > in)
Definition: scalar.hpp:294

References Nektar::MemoryManager< DataType >::AllocateSharedPtr(), and tinysimd::sqrt().

Referenced by SetUpReferenceElements().

◆ CreateRefPyrGeom()

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

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

Definition at line 1379 of file PreconditionerLowEnergy.cpp.

1380 {
1381  //////////////////////////
1382  // Set up Pyramid element //
1383  //////////////////////////
1384 
1385  const int nVerts = 5;
1386  const double point[][3] = {{-1, -1, 0},
1387  {1, -1, 0},
1388  {1, 1, 0},
1389  {-1, 1, 0},
1390  {0, 0, sqrt(double(2))}};
1391 
1392  // boost::shared_ptr<SpatialDomains::PointGeom> verts[6];
1393  const int three = 3;
1395  for (int i = 0; i < nVerts; ++i)
1396  {
1398  three, i, point[i][0], point[i][1], point[i][2]);
1399  }
1400  const int nEdges = 8;
1401  const int vertexConnectivity[][2] = {{0, 1}, {1, 2}, {2, 3}, {3, 0},
1402  {0, 4}, {1, 4}, {2, 4}, {3, 4}};
1403 
1404  // Populate the list of edges
1405  SpatialDomains::SegGeomSharedPtr edges[nEdges];
1406  for (int i = 0; i < nEdges; ++i)
1407  {
1408  SpatialDomains::PointGeomSharedPtr vertsArray[2];
1409  for (int j = 0; j < 2; ++j)
1410  {
1411  vertsArray[j] = verts[vertexConnectivity[i][j]];
1412  }
1414  i, three, vertsArray);
1415  }
1416 
1417  ////////////////////////
1418  // Set up Pyramid faces //
1419  ////////////////////////
1420 
1421  const int nFaces = 5;
1422  // quad-edge connectivity base-face0,
1423  const int quadEdgeConnectivity[][4] = {{0, 1, 2, 3}};
1424 
1425  // triangle-edge connectivity side-triface-1, side triface-2
1426  const int triEdgeConnectivity[][3] = {
1427  {0, 5, 4}, {1, 6, 5}, {2, 7, 6}, {3, 4, 7}};
1428 
1429  // Populate the list of faces
1431  for (int f = 0; f < nFaces; ++f)
1432  {
1433  if (f == 0)
1434  {
1435  SpatialDomains::SegGeomSharedPtr edgeArray[4];
1436  for (int j = 0; j < 4; ++j)
1437  {
1438  edgeArray[j] = edges[quadEdgeConnectivity[f][j]];
1439  }
1440 
1441  faces[f] =
1443  f, edgeArray);
1444  }
1445  else
1446  {
1447  int i = f - 1;
1448  SpatialDomains::SegGeomSharedPtr edgeArray[3];
1449  for (int j = 0; j < 3; ++j)
1450  {
1451  edgeArray[j] = edges[triEdgeConnectivity[i][j]];
1452  }
1453  faces[f] =
1455  f, edgeArray);
1456  }
1457  }
1458 
1461 
1462  return geom;
1463 }
std::shared_ptr< PyrGeom > PyrGeomSharedPtr
Definition: PyrGeom.h:77

References Nektar::MemoryManager< DataType >::AllocateSharedPtr(), and tinysimd::sqrt().

Referenced by SetUpReferenceElements().

◆ CreateRefTetGeom()

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

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

Definition at line 1469 of file PreconditionerLowEnergy.cpp.

1470 {
1471  /////////////////////////////////
1472  // Set up Tetrahedron vertices //
1473  /////////////////////////////////
1474 
1475  int i, j;
1476  const int three = 3;
1477  const int nVerts = 4;
1478  const double point[][3] = {{-1, -1 / sqrt(double(3)), -1 / sqrt(double(6))},
1479  {1, -1 / sqrt(double(3)), -1 / sqrt(double(6))},
1480  {0, 2 / sqrt(double(3)), -1 / sqrt(double(6))},
1481  {0, 0, 3 / sqrt(double(6))}};
1482 
1483  std::shared_ptr<SpatialDomains::PointGeom> verts[4];
1484  for (i = 0; i < nVerts; ++i)
1485  {
1487  three, i, point[i][0], point[i][1], point[i][2]);
1488  }
1489 
1490  //////////////////////////////
1491  // Set up Tetrahedron Edges //
1492  //////////////////////////////
1493 
1494  // SegGeom (int id, const int coordim), EdgeComponent(id, coordim)
1495  const int nEdges = 6;
1496  const int vertexConnectivity[][2] = {{0, 1}, {1, 2}, {0, 2},
1497  {0, 3}, {1, 3}, {2, 3}};
1498 
1499  // Populate the list of edges
1500  SpatialDomains::SegGeomSharedPtr edges[nEdges];
1501  for (i = 0; i < nEdges; ++i)
1502  {
1503  std::shared_ptr<SpatialDomains::PointGeom> vertsArray[2];
1504  for (j = 0; j < 2; ++j)
1505  {
1506  vertsArray[j] = verts[vertexConnectivity[i][j]];
1507  }
1508 
1510  i, three, vertsArray);
1511  }
1512 
1513  //////////////////////////////
1514  // Set up Tetrahedron faces //
1515  //////////////////////////////
1516 
1517  const int nFaces = 4;
1518  const int edgeConnectivity[][3] = {
1519  {0, 1, 2}, {0, 4, 3}, {1, 5, 4}, {2, 5, 3}};
1520 
1521  // Populate the list of faces
1522  SpatialDomains::TriGeomSharedPtr faces[nFaces];
1523  for (i = 0; i < nFaces; ++i)
1524  {
1525  SpatialDomains::SegGeomSharedPtr edgeArray[3];
1526  for (j = 0; j < 3; ++j)
1527  {
1528  edgeArray[j] = edges[edgeConnectivity[i][j]];
1529  }
1530 
1532  i, edgeArray);
1533  }
1534 
1537 
1538  return geom;
1539 }
std::shared_ptr< TetGeom > TetGeomSharedPtr
Definition: TetGeom.h:85
std::shared_ptr< TriGeom > TriGeomSharedPtr
Definition: TriGeom.h:58

References Nektar::MemoryManager< DataType >::AllocateSharedPtr(), and tinysimd::sqrt().

Referenced by SetUpReferenceElements().

◆ CreateVariablePMask()

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

Create the inverse multiplicity map.

Definition at line 1252 of file PreconditionerLowEnergy.cpp.

1253 {
1254  unsigned int nLocBnd = m_locToGloMap.lock()->GetNumLocalBndCoeffs();
1255  unsigned int i;
1256  auto asmMap = m_locToGloMap.lock();
1257 
1258  const Array<OneD, const NekDouble> &sign =
1259  asmMap->GetLocalToGlobalBndSign();
1260 
1261  m_signChange = asmMap->GetSignChange();
1262 
1263  // Construct a map of 1/multiplicity
1264  m_variablePmask = Array<OneD, NekDouble>(nLocBnd);
1265  for (i = 0; i < nLocBnd; ++i)
1266  {
1267  if (m_signChange)
1268  {
1269  m_variablePmask[i] = fabs(sign[i]);
1270  }
1271  else
1272  {
1273  m_variablePmask[i] = 1.0;
1274  }
1275  }
1276 }
#define sign(a, b)
return the sign(b)*a
Definition: Polylib.cpp:49
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 2271 of file PreconditionerLowEnergy.cpp.

2275 {
2276  NekDouble val;
2277  NekDouble zero = 0.0;
2278 
2279  int nRows = locExp->NumBndryCoeffs();
2280  DNekMatSharedPtr newmat =
2281  MemoryManager<DNekMat>::AllocateSharedPtr(nRows, nRows, zero, eFULL);
2282 
2283  Array<OneD, unsigned int> vlocmap;
2284  Array<OneD, Array<OneD, unsigned int>> elocmap;
2285  Array<OneD, Array<OneD, unsigned int>> flocmap;
2286 
2287  locExp->GetInverseBoundaryMaps(vlocmap, elocmap, flocmap);
2288 
2289  // fill diagonal
2290  for (int i = 0; i < nRows; ++i)
2291  {
2292  val = 1.0;
2293  newmat->SetValue(i, i, val);
2294  }
2295 
2296  int nverts = locExp->GetNverts();
2297  int nedges = locExp->GetNedges();
2298  int nfaces = locExp->GetNtraces();
2299 
2300  // fill vertex to edge coupling
2301  for (int e = 0; e < nedges; ++e)
2302  {
2303  int nEdgeInteriorCoeffs = locExp->GetEdgeNcoeffs(e) - 2;
2304 
2305  for (int v = 0; v < nverts; ++v)
2306  {
2307  for (int i = 0; i < nEdgeInteriorCoeffs; ++i)
2308  {
2309  val = (*maxRmat)(vmap[v], emap[e][i]);
2310  newmat->SetValue(vlocmap[v], elocmap[e][i], val);
2311  }
2312  }
2313  }
2314 
2315  for (int f = 0; f < nfaces; ++f)
2316  {
2317  // Get details to extrac this face from max reference matrix
2318  StdRegions::Orientation FwdOrient =
2320  int m0, m1; // Local face expansion orders.
2321 
2322  int nFaceInteriorCoeffs = locExp->GetTraceIntNcoeffs(f);
2323 
2324  locExp->GetTraceNumModes(f, m0, m1, FwdOrient);
2325 
2326  Array<OneD, unsigned int> fmapRmat =
2327  maxExp->GetTraceInverseBoundaryMap(f, FwdOrient, m0, m1);
2328 
2329  // fill in vertex to face coupling
2330  for (int v = 0; v < nverts; ++v)
2331  {
2332  for (int i = 0; i < nFaceInteriorCoeffs; ++i)
2333  {
2334  val = (*maxRmat)(vmap[v], fmapRmat[i]);
2335  newmat->SetValue(vlocmap[v], flocmap[f][i], val);
2336  }
2337  }
2338 
2339  // fill in edges to face coupling
2340  for (int e = 0; e < nedges; ++e)
2341  {
2342  int nEdgeInteriorCoeffs = locExp->GetEdgeNcoeffs(e) - 2;
2343 
2344  for (int j = 0; j < nEdgeInteriorCoeffs; ++j)
2345  {
2346 
2347  for (int i = 0; i < nFaceInteriorCoeffs; ++i)
2348  {
2349  val = (*maxRmat)(emap[e][j], fmapRmat[i]);
2350  newmat->SetValue(elocmap[e][j], flocmap[f][i], val);
2351  }
2352  }
2353  }
2354  }
2355 
2356  return newmat;
2357 }
std::shared_ptr< DNekMat > DNekMatSharedPtr
Definition: NekTypeDefs.hpp:75
double NekDouble

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 2054 of file PreconditionerLowEnergy.cpp.

2061 {
2062  int nRows = PrismExp->NumBndryCoeffs();
2063  NekDouble val;
2064  NekDouble zero = 0.0;
2065  DNekMatSharedPtr newmat =
2066  MemoryManager<DNekMat>::AllocateSharedPtr(nRows, nRows, zero, eFULL);
2067 
2068  int nfacemodes;
2069 
2070  if (UseTetOnly)
2071  {
2072  // copy existing system
2073  for (int i = 0; i < nRows; ++i)
2074  {
2075  for (int j = 0; j < nRows; ++j)
2076  {
2077  val = (*maxRmat[ePrism])(i, j);
2078  newmat->SetValue(i, j, val);
2079  }
2080  }
2081 
2082  // Reset vertex to edge mapping from tet.
2083  const int VETetVert[][2] = {{0, 0}, {1, 1}, {1, 1},
2084  {0, 0}, {3, 3}, {3, 3}};
2085  const int VETetEdge[][2] = {{0, 3}, {0, 4}, {0, 4},
2086  {0, 3}, {3, 4}, {4, 3}};
2087  const int VEPrismEdge[][2] = {{0, 4}, {0, 5}, {2, 6},
2088  {2, 7}, {4, 5}, {6, 7}};
2089 
2090  // fill vertex to edge coupling
2091  for (int v = 0; v < 6; ++v)
2092  {
2093  for (int e = 0; e < 2; ++e)
2094  {
2095  for (int i = 0; i < nummodesmax - 2; ++i)
2096  {
2097  // Note this is using wrong shape but gives
2098  // answer that seems to have correct error!
2099  val = (*maxRmat[eTetrahedron])(
2100  vertMapMaxR[eTetrahedron][VETetVert[v][e]],
2101  edgeMapMaxR[eTetrahedron][VETetEdge[v][e]][i]);
2102  newmat->SetValue(vertMapMaxR[ePrism][v],
2103  edgeMapMaxR[ePrism][VEPrismEdge[v][e]][i],
2104  val);
2105  }
2106  }
2107  }
2108  }
2109  else
2110  {
2111 
2112  // set diagonal to 1
2113  for (int i = 0; i < nRows; ++i)
2114  {
2115  newmat->SetValue(i, i, 1.0);
2116  }
2117 
2118  // Set vertex to edge mapping from Hex.
2119 
2120  // The following lists specify the number of adjacent
2121  // edges to each vertex (nadj) then the Hex vert to
2122  // use for each prism ver in the vert-edge map (VEVert)
2123  // followed by the hex edge to use for each prism edge
2124  // in the vert-edge map (VEEdge)
2125  const int VEHexVert[][3] = {{0, 0, 0}, {1, 1, 1}, {2, 2, 2},
2126  {3, 3, 3}, {4, 5, 5}, {6, 7, 7}};
2127  const int VEHexEdge[][3] = {{0, 3, 4}, {0, 1, 5}, {1, 2, 6},
2128  {2, 3, 7}, {4, 5, 9}, {6, 7, 11}};
2129  const int VEPrismEdge[][3] = {{0, 3, 4}, {0, 1, 5}, {1, 2, 6},
2130  {2, 3, 7}, {4, 5, 8}, {6, 7, 8}};
2131 
2132  // fill vertex to edge coupling
2133  for (int v = 0; v < 6; ++v)
2134  {
2135  for (int e = 0; e < 3; ++e)
2136  {
2137  for (int i = 0; i < nummodesmax - 2; ++i)
2138  {
2139  // Note this is using wrong shape but gives
2140  // answer that seems to have correct error!
2141  val = (*maxRmat[eHexahedron])(
2142  vertMapMaxR[eHexahedron][VEHexVert[v][e]],
2143  edgeMapMaxR[eHexahedron][VEHexEdge[v][e]][i]);
2144  newmat->SetValue(vertMapMaxR[ePrism][v],
2145  edgeMapMaxR[ePrism][VEPrismEdge[v][e]][i],
2146  val);
2147  }
2148  }
2149  }
2150 
2151  // Setup vertex to face mapping from Hex
2152  const int VFHexVert[][2] = {{0, 0}, {1, 1}, {4, 5},
2153  {2, 2}, {3, 3}, {6, 7}};
2154  const int VFHexFace[][2] = {{0, 4}, {0, 2}, {4, 2},
2155  {0, 2}, {0, 4}, {2, 4}};
2156 
2157  const int VQFPrismVert[][2] = {{0, 0}, {1, 1}, {4, 4},
2158  {2, 2}, {3, 3}, {5, 5}};
2159  const int VQFPrismFace[][2] = {{0, 4}, {0, 2}, {4, 2},
2160  {0, 2}, {0, 4}, {2, 4}};
2161 
2162  nfacemodes = (nummodesmax - 2) * (nummodesmax - 2);
2163  // Replace two Quad faces on every vertex
2164  for (int v = 0; v < 6; ++v)
2165  {
2166  for (int f = 0; f < 2; ++f)
2167  {
2168  for (int i = 0; i < nfacemodes; ++i)
2169  {
2170  val = (*maxRmat[eHexahedron])(
2171  vertMapMaxR[eHexahedron][VFHexVert[v][f]],
2172  faceMapMaxR[eHexahedron][VFHexFace[v][f]][i]);
2173  newmat->SetValue(vertMapMaxR[ePrism][VQFPrismVert[v][f]],
2174  faceMapMaxR[ePrism][VQFPrismFace[v][f]][i],
2175  val);
2176  }
2177  }
2178  }
2179 
2180  // Mapping of Hex Edge-Face mappings to Prism Edge-Face Mappings
2181  const int nadjface[] = {1, 2, 1, 2, 1, 1, 1, 1, 2};
2182  const int EFHexEdge[][2] = {{0, -1}, {1, 1}, {2, -1}, {3, 3}, {4, -1},
2183  {5, -1}, {6, -1}, {7, -1}, {9, 11}};
2184  const int EFHexFace[][2] = {{0, -1}, {0, 2}, {0, -1}, {0, 4}, {4, -1},
2185  {2, -1}, {2, -1}, {4, -1}, {2, 4}};
2186  const int EQFPrismEdge[][2] = {{0, -1}, {1, 1}, {2, -1},
2187  {3, 3}, {4, -1}, {5, -1},
2188  {6, -1}, {7, -1}, {8, 8}};
2189  const int EQFPrismFace[][2] = {{0, -1}, {0, 2}, {0, -1},
2190  {0, 4}, {4, -1}, {2, -1},
2191  {2, -1}, {4, -1}, {2, 4}};
2192 
2193  // all base edges are coupled to face 0
2194  nfacemodes = (nummodesmax - 2) * (nummodesmax - 2);
2195  for (int e = 0; e < 9; ++e)
2196  {
2197  for (int f = 0; f < nadjface[e]; ++f)
2198  {
2199  for (int i = 0; i < nummodesmax - 2; ++i)
2200  {
2201  for (int j = 0; j < nfacemodes; ++j)
2202  {
2203  int edgemapid =
2204  edgeMapMaxR[eHexahedron][EFHexEdge[e][f]][i];
2205  int facemapid =
2206  faceMapMaxR[eHexahedron][EFHexFace[e][f]][j];
2207 
2208  val = (*maxRmat[eHexahedron])(edgemapid, facemapid);
2209 
2210  int edgemapid1 =
2211  edgeMapMaxR[ePrism][EQFPrismEdge[e][f]][i];
2212  int facemapid1 =
2213  faceMapMaxR[ePrism][EQFPrismFace[e][f]][j];
2214  newmat->SetValue(edgemapid1, facemapid1, val);
2215  }
2216  }
2217  }
2218  }
2219  }
2220 
2221  const int VFTetVert[] = {0, 1, 3, 1, 0, 3};
2222  const int VFTetFace[] = {1, 1, 1, 1, 1, 1};
2223  const int VTFPrismVert[] = {0, 1, 4, 2, 3, 5};
2224  const int VTFPrismFace[] = {1, 1, 1, 3, 3, 3};
2225 
2226  // Handle all triangular faces from tetrahedron
2227  nfacemodes = (nummodesmax - 3) * (nummodesmax - 2) / 2;
2228  for (int v = 0; v < 6; ++v)
2229  {
2230  for (int i = 0; i < nfacemodes; ++i)
2231  {
2232  val = (*maxRmat[eTetrahedron])(
2233  vertMapMaxR[eTetrahedron][VFTetVert[v]],
2234  faceMapMaxR[eTetrahedron][VFTetFace[v]][i]);
2235 
2236  newmat->SetValue(vertMapMaxR[ePrism][VTFPrismVert[v]],
2237  faceMapMaxR[ePrism][VTFPrismFace[v]][i], val);
2238  }
2239  }
2240 
2241  // Mapping of Tet Edge-Face mappings to Prism Edge-Face Mappings
2242  const int EFTetEdge[] = {0, 3, 4, 0, 4, 3};
2243  const int EFTetFace[] = {1, 1, 1, 1, 1, 1};
2244  const int ETFPrismEdge[] = {0, 4, 5, 2, 6, 7};
2245  const int ETFPrismFace[] = {1, 1, 1, 3, 3, 3};
2246 
2247  // handle all edge to triangular faces from tetrahedron
2248  // (only 6 this time)
2249  nfacemodes = (nummodesmax - 3) * (nummodesmax - 2) / 2;
2250  for (int e = 0; e < 6; ++e)
2251  {
2252  for (int i = 0; i < nummodesmax - 2; ++i)
2253  {
2254  for (int j = 0; j < nfacemodes; ++j)
2255  {
2256  int edgemapid = edgeMapMaxR[eTetrahedron][EFTetEdge[e]][i];
2257  int facemapid = faceMapMaxR[eTetrahedron][EFTetFace[e]][j];
2258  val = (*maxRmat[eTetrahedron])(edgemapid, facemapid);
2259 
2260  newmat->SetValue(edgeMapMaxR[ePrism][ETFPrismEdge[e]][i],
2261  faceMapMaxR[ePrism][ETFPrismFace[e]][j], val);
2262  }
2263  }
2264  }
2265 
2266  DNekScalMatSharedPtr PrismR =
2268  maxRmat[ePrism] = PrismR;
2269 }
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 1995 of file PreconditionerLowEnergy.cpp.

2001 {
2002  boost::ignore_unused(faceMapMaxR);
2003 
2004  int nRows = TetExp->NumBndryCoeffs();
2005  NekDouble val;
2006  NekDouble zero = 0.0;
2007  DNekMatSharedPtr newmat =
2008  MemoryManager<DNekMat>::AllocateSharedPtr(nRows, nRows, zero, eFULL);
2009 
2010  // copy existing system
2011  for (int i = 0; i < nRows; ++i)
2012  {
2013  for (int j = 0; j < nRows; ++j)
2014  {
2015  val = (*maxRmat[eTetrahedron])(i, j);
2016  newmat->SetValue(i, j, val);
2017  }
2018  }
2019 
2020  // The following lists specify the number of adjacent
2021  // edges to each vertex (nadj) then the Hex vert to
2022  // use for each pyramid ver in the vert-edge map (VEVert)
2023  // followed by the hex edge to use for each Tet edge
2024  // in the vert-edge map (VEEdge)
2025  const int VEHexVert[][4] = {{0, 0, 0}, {1, 1, 1}, {2, 2, 2}, {4, 5, 6}};
2026  const int VEHexEdge[][4] = {{0, 3, 4}, {0, 1, 5}, {1, 2, 6}, {4, 5, 6}};
2027  const int VETetEdge[][4] = {{0, 2, 3}, {0, 1, 4}, {1, 2, 5}, {3, 4, 5}};
2028 
2029  // fill vertex to edge coupling
2030  for (int v = 0; v < 4; ++v)
2031  {
2032  for (int e = 0; e < 3; ++e)
2033  {
2034  for (int i = 0; i < nummodesmax - 2; ++i)
2035  {
2036  // Note this is using wrong shape but gives
2037  // answer that seems to have correct error!
2038  val = (*maxRmat[eHexahedron])(
2039  vertMapMaxR[eHexahedron][VEHexVert[v][e]],
2040  edgeMapMaxR[eHexahedron][VEHexEdge[v][e]][i]);
2041  newmat->SetValue(vertMapMaxR[eTetrahedron][v],
2042  edgeMapMaxR[eTetrahedron][VETetEdge[v][e]][i],
2043  val);
2044  }
2045  }
2046  }
2047 
2048  DNekScalMatSharedPtr TetR =
2050 
2051  maxRmat[eTetrahedron] = TetR;
2052 }

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 936 of file PreconditionerLowEnergy.cpp.

937 {
938  std::shared_ptr<MultiRegions::ExpList> expList =
939  ((m_linsys.lock())->GetLocMat()).lock();
942  map<int, int> EdgeSize;
943 
944  int n;
945 
946  std::map<ShapeType, DNekScalMatSharedPtr> maxRmat;
947  map<ShapeType, LocalRegions::Expansion3DSharedPtr> maxElmt;
948  map<ShapeType, Array<OneD, unsigned int>> vertMapMaxR;
949  map<ShapeType, Array<OneD, Array<OneD, unsigned int>>> edgeMapMaxR;
950 
951  // Sets up reference element and builds transformation matrix for
952  // maximum polynomial order meshes
953  SetUpReferenceElements(maxRmat, maxElmt, vertMapMaxR, edgeMapMaxR);
954 
955  const Array<OneD, const unsigned int> &nbdry_size =
956  m_locToGloMap.lock()->GetNumLocalBndCoeffsPerPatch();
957 
958  int n_exp = expList->GetNumElmts();
959 
960  MatrixStorage blkmatStorage = eDIAGONAL;
961 
962  // Variants of R matrices required for low energy preconditioning
964  nbdry_size, nbdry_size, blkmatStorage);
966  nbdry_size, nbdry_size, blkmatStorage);
967 
968  DNekMatSharedPtr rmat, invrmat;
969 
970  int offset = 0;
971 
972  // Set up transformation matrices whilst checking to see if
973  // consecutive matrices are the same and if so reuse the
974  // matrices and store how many consecutive offsets there
975  // are
976  for (n = 0; n < n_exp; ++n)
977  {
978  locExp = expList->GetExp(n)->as<LocalRegions::Expansion3D>();
979 
980  ShapeType eltype = locExp->DetShapeType();
981 
982  int nbndcoeffs = locExp->NumBndryCoeffs();
983 
984  if (m_sameBlock.size() == 0)
985  {
986  rmat = ExtractLocMat(locExp, maxRmat[eltype], maxElmt[eltype],
987  vertMapMaxR[eltype], edgeMapMaxR[eltype]);
988  // Block R matrix
989  m_RBlk->SetBlock(n, n, rmat);
990 
992  invrmat->Invert();
993 
994  // Block inverse R matrix
995  m_InvRBlk->SetBlock(n, n, invrmat);
996 
997  m_sameBlock.push_back(pair<int, int>(1, nbndcoeffs));
998  locExpSav = locExp;
999  }
1000  else
1001  {
1002  bool reuse = true;
1003 
1004  // check to see if same as previous matrix and
1005  // reuse if we can
1006  for (int i = 0; i < 3; ++i)
1007  {
1008  if (locExpSav->GetBasis(i) != locExp->GetBasis(i))
1009  {
1010  reuse = false;
1011  break;
1012  }
1013  }
1014 
1015  if (reuse)
1016  {
1017  m_RBlk->SetBlock(n, n, rmat);
1018  m_InvRBlk->SetBlock(n, n, invrmat);
1019 
1020  m_sameBlock[offset] =
1021  (pair<int, int>(m_sameBlock[offset].first + 1, nbndcoeffs));
1022  }
1023  else
1024  {
1025  rmat = ExtractLocMat(locExp, maxRmat[eltype], maxElmt[eltype],
1026  vertMapMaxR[eltype], edgeMapMaxR[eltype]);
1027 
1028  // Block R matrix
1029  m_RBlk->SetBlock(n, n, rmat);
1030 
1032  invrmat->Invert();
1033  // Block inverse R matrix
1034  m_InvRBlk->SetBlock(n, n, invrmat);
1035 
1036  m_sameBlock.push_back(pair<int, int>(1, nbndcoeffs));
1037  offset++;
1038  locExpSav = locExp;
1039  }
1040  }
1041  }
1042 }
const std::weak_ptr< GlobalLinSys > m_linsys
DNekMatSharedPtr ExtractLocMat(LocalRegions::Expansion3DSharedPtr &locExp, DNekScalMatSharedPtr &maxRmat, LocalRegions::Expansion3DSharedPtr &expMax, Array< OneD, unsigned int > &vertMapMaxR, Array< OneD, Array< OneD, unsigned int >> &edgeMapMaxR)
std::vector< std::pair< int, int > > m_sameBlock
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:50

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 1830 of file PreconditionerLowEnergy.cpp.

1836 {
1837  int nRows = PyrExp->NumBndryCoeffs();
1838  NekDouble val;
1839  NekDouble zero = 0.0;
1840  DNekMatSharedPtr newmat =
1841  MemoryManager<DNekMat>::AllocateSharedPtr(nRows, nRows, zero, eFULL);
1842 
1843  // set diagonal to 1
1844  for (int i = 0; i < nRows; ++i)
1845  {
1846  newmat->SetValue(i, i, 1.0);
1847  }
1848 
1849  // The following lists specify the number of adjacent
1850  // edges to each vertex (nadj) then the Hex vert to
1851  // use for each pyramid ver in the vert-edge map (VEVert)
1852  // followed by the hex edge to use for each pyramid edge
1853  // in the vert-edge map (VEEdge)
1854  const int nadjedge[] = {3, 3, 3, 3, 4};
1855  const int VEHexVert[][4] = {{0, 0, 0, -1},
1856  {1, 1, 1, -1},
1857  {2, 2, 2, -1},
1858  {3, 3, 3, -1},
1859  {4, 5, 6, 7}};
1860  const int VEHexEdge[][4] = {{0, 3, 4, -1},
1861  {0, 1, 5, -1},
1862  {1, 2, 6, -1},
1863  {2, 3, 7, -1},
1864  {4, 5, 6, 7}};
1865  const int VEPyrEdge[][4] = {{0, 3, 4, -1},
1866  {0, 1, 5, -1},
1867  {1, 2, 6, -1},
1868  {2, 3, 7, -1},
1869  {4, 5, 6, 7}};
1870 
1871  // fill vertex to edge coupling
1872  for (int v = 0; v < 5; ++v)
1873  {
1874  for (int e = 0; e < nadjedge[v]; ++e)
1875  {
1876  for (int i = 0; i < nummodesmax - 2; ++i)
1877  {
1878  // Note this is using wrong shape but gives
1879  // answer that seems to have correct error!
1880  val = (*maxRmat[eHexahedron])(
1881  vertMapMaxR[eHexahedron][VEHexVert[v][e]],
1882  edgeMapMaxR[eHexahedron][VEHexEdge[v][e]][i]);
1883  newmat->SetValue(vertMapMaxR[ePyramid][v],
1884  edgeMapMaxR[ePyramid][VEPyrEdge[v][e]][i],
1885  val);
1886  }
1887  }
1888  }
1889 
1890  int nfacemodes;
1891  nfacemodes = (nummodesmax - 2) * (nummodesmax - 2);
1892  // First four verties are all adjacent to base face
1893  for (int v = 0; v < 4; ++v)
1894  {
1895  for (int i = 0; i < nfacemodes; ++i)
1896  {
1897  val = (*maxRmat[eHexahedron])(vertMapMaxR[eHexahedron][v],
1898  faceMapMaxR[eHexahedron][0][i]);
1899  newmat->SetValue(vertMapMaxR[ePyramid][v],
1900  faceMapMaxR[ePyramid][0][i], val);
1901  }
1902  }
1903 
1904  const int nadjface[] = {2, 2, 2, 2, 4};
1905  const int VFTetVert[][4] = {{0, 0, -1, -1},
1906  {1, 1, -1, -1},
1907  {2, 2, -1, -1},
1908  {0, 2, -1, -1},
1909  {3, 3, 3, 3}};
1910  const int VFTetFace[][4] = {{1, 3, -1, -1},
1911  {1, 2, -1, -1},
1912  {2, 3, -1, -1},
1913  {1, 3, -1, -1},
1914  {1, 2, 1, 2}};
1915  const int VFPyrFace[][4] = {{1, 4, -1, -1},
1916  {1, 2, -1, -1},
1917  {2, 3, -1, -1},
1918  {3, 4, -1, -1},
1919  {1, 2, 3, 4}};
1920 
1921  // next handle all triangular faces from tetrahedron
1922  nfacemodes = (nummodesmax - 3) * (nummodesmax - 2) / 2;
1923  for (int v = 0; v < 5; ++v)
1924  {
1925  for (int f = 0; f < nadjface[v]; ++f)
1926  {
1927  for (int i = 0; i < nfacemodes; ++i)
1928  {
1929  val = (*maxRmat[eTetrahedron])(
1930  vertMapMaxR[eTetrahedron][VFTetVert[v][f]],
1931  faceMapMaxR[eTetrahedron][VFTetFace[v][f]][i]);
1932  newmat->SetValue(vertMapMaxR[ePyramid][v],
1933  faceMapMaxR[ePyramid][VFPyrFace[v][f]][i],
1934  val);
1935  }
1936  }
1937  }
1938 
1939  // Edge to face coupling
1940  // all base edges are coupled to face 0
1941  nfacemodes = (nummodesmax - 2) * (nummodesmax - 2);
1942  for (int e = 0; e < 4; ++e)
1943  {
1944  for (int i = 0; i < nummodesmax - 2; ++i)
1945  {
1946  for (int j = 0; j < nfacemodes; ++j)
1947  {
1948  int edgemapid = edgeMapMaxR[eHexahedron][e][i];
1949  int facemapid = faceMapMaxR[eHexahedron][0][j];
1950 
1951  val = (*maxRmat[eHexahedron])(edgemapid, facemapid);
1952  newmat->SetValue(edgeMapMaxR[ePyramid][e][i],
1953  faceMapMaxR[ePyramid][0][j], val);
1954  }
1955  }
1956  }
1957 
1958  const int nadjface1[] = {1, 1, 1, 1, 2, 2, 2, 2};
1959  const int EFTetEdge[][2] = {{0, -1}, {1, -1}, {0, -1}, {2, -1},
1960  {3, 3}, {4, 4}, {5, 5}, {3, 5}};
1961  const int EFTetFace[][2] = {{1, -1}, {2, -1}, {1, -1}, {3, -1},
1962  {1, 3}, {1, 2}, {2, 3}, {1, 3}};
1963  const int EFPyrFace[][2] = {{1, -1}, {2, -1}, {3, -1}, {4, -1},
1964  {1, 4}, {1, 2}, {2, 3}, {3, 4}};
1965 
1966  // next handle all triangular faces from tetrahedron
1967  nfacemodes = (nummodesmax - 3) * (nummodesmax - 2) / 2;
1968  for (int e = 0; e < 8; ++e)
1969  {
1970  for (int f = 0; f < nadjface1[e]; ++f)
1971  {
1972  for (int i = 0; i < nummodesmax - 2; ++i)
1973  {
1974  for (int j = 0; j < nfacemodes; ++j)
1975  {
1976  int edgemapid =
1977  edgeMapMaxR[eTetrahedron][EFTetEdge[e][f]][i];
1978  int facemapid =
1979  faceMapMaxR[eTetrahedron][EFTetFace[e][f]][j];
1980 
1981  val = (*maxRmat[eTetrahedron])(edgemapid, facemapid);
1982  newmat->SetValue(edgeMapMaxR[ePyramid][e][i],
1983  faceMapMaxR[ePyramid][EFPyrFace[e][f]][j],
1984  val);
1985  }
1986  }
1987  }
1988  }
1989 
1990  DNekScalMatSharedPtr PyrR;
1992  maxRmat[ePyramid] = PyrR;
1993 }

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 1622 of file PreconditionerLowEnergy.cpp.

1627 {
1628 
1629  std::shared_ptr<MultiRegions::ExpList> expList =
1630  ((m_linsys.lock())->GetLocMat()).lock();
1631  GlobalLinSysKey linSysKey = (m_linsys.lock())->GetKey();
1632 
1634 
1635  // face maps for pyramid and hybrid meshes - not need to return.
1636  map<ShapeType, Array<OneD, Array<OneD, unsigned int>>> faceMapMaxR;
1637 
1638  /* Determine the maximum expansion order for all elements */
1639  int nummodesmax = 0;
1640  Array<OneD, int> Shapes(LibUtilities::SIZE_ShapeType, 0);
1641 
1642  for (int n = 0; n < expList->GetNumElmts(); ++n)
1643  {
1644  locExp = expList->GetExp(n);
1645 
1646  nummodesmax = max(nummodesmax, locExp->GetBasisNumModes(0));
1647  nummodesmax = max(nummodesmax, locExp->GetBasisNumModes(1));
1648  nummodesmax = max(nummodesmax, locExp->GetBasisNumModes(2));
1649 
1650  Shapes[locExp->DetShapeType()] = 1;
1651  }
1652 
1653  m_comm->AllReduce(nummodesmax, ReduceMax);
1654  m_comm->AllReduce(Shapes, ReduceMax);
1655 
1656  if (Shapes[ePyramid] || Shapes[ePrism]) // if Pyramids or Prisms used then
1657  // need Tet and Hex expansion
1658  {
1659  Shapes[eTetrahedron] = 1;
1660  Shapes[eHexahedron] = 1;
1661  }
1662 
1663  StdRegions::MatrixType PreconR;
1664  if (linSysKey.GetMatrixType() == StdRegions::eMass)
1665  {
1666  PreconR = StdRegions::ePreconRMass;
1667  }
1668  else
1669  {
1670  PreconR = StdRegions::ePreconR;
1671  }
1672 
1673  Array<OneD, unsigned int> vmap;
1674  Array<OneD, Array<OneD, unsigned int>> emap;
1675  Array<OneD, Array<OneD, unsigned int>> fmap;
1676 
1677  /*
1678  * Set up a transformation matrices for equal max order
1679  * polynomial meshes
1680  */
1681 
1682  if (Shapes[eHexahedron])
1683  {
1685  // Bases for Hex element
1686  const BasisKey HexBa(eModified_A, nummodesmax,
1687  PointsKey(nummodesmax + 1, eGaussLobattoLegendre));
1688  const BasisKey HexBb(eModified_A, nummodesmax,
1689  PointsKey(nummodesmax + 1, eGaussLobattoLegendre));
1690  const BasisKey HexBc(eModified_A, nummodesmax,
1691  PointsKey(nummodesmax + 1, eGaussLobattoLegendre));
1692 
1693  // Create reference Hexahdedral expansion
1695 
1697  HexBa, HexBb, HexBc, hexgeom);
1698 
1699  maxElmt[eHexahedron] = HexExp;
1700 
1701  // Hex:
1702  HexExp->GetInverseBoundaryMaps(vmap, emap, fmap);
1703  vertMapMaxR[eHexahedron] = vmap;
1704  edgeMapMaxR[eHexahedron] = emap;
1705  faceMapMaxR[eHexahedron] = fmap;
1706 
1707  // Get hexahedral transformation matrix
1708  LocalRegions::MatrixKey HexR(PreconR, eHexahedron, *HexExp,
1709  linSysKey.GetConstFactors());
1710  maxRmat[eHexahedron] = HexExp->GetLocMatrix(HexR);
1711  }
1712 
1713  if (Shapes[eTetrahedron])
1714  {
1716  // Bases for Tetrahedral element
1717  const BasisKey TetBa(eModified_A, nummodesmax,
1718  PointsKey(nummodesmax + 1, eGaussLobattoLegendre));
1719  const BasisKey TetBb(eModified_B, nummodesmax,
1720  PointsKey(nummodesmax, eGaussRadauMAlpha1Beta0));
1721  const BasisKey TetBc(eModified_C, nummodesmax,
1722  PointsKey(nummodesmax, eGaussRadauMAlpha2Beta0));
1723 
1724  // Create reference tetrahedral expansion
1726 
1728  TetBa, TetBb, TetBc, tetgeom);
1729 
1730  maxElmt[eTetrahedron] = TetExp;
1731 
1732  TetExp->GetInverseBoundaryMaps(vmap, emap, fmap);
1733  vertMapMaxR[eTetrahedron] = vmap;
1734  edgeMapMaxR[eTetrahedron] = emap;
1735  faceMapMaxR[eTetrahedron] = fmap;
1736 
1737  // Get tetrahedral transformation matrix
1738  LocalRegions::MatrixKey TetR(PreconR, eTetrahedron, *TetExp,
1739  linSysKey.GetConstFactors());
1740  maxRmat[eTetrahedron] = TetExp->GetLocMatrix(TetR);
1741 
1742  if ((Shapes[ePyramid]) || (Shapes[eHexahedron]))
1743  {
1744  ReSetTetMaxRMat(nummodesmax, TetExp, maxRmat, vertMapMaxR,
1745  edgeMapMaxR, faceMapMaxR);
1746  }
1747  }
1748 
1749  if (Shapes[ePyramid])
1750  {
1752 
1753  // Bases for Pyramid element
1754  const BasisKey PyrBa(eModified_A, nummodesmax,
1755  PointsKey(nummodesmax + 1, eGaussLobattoLegendre));
1756  const BasisKey PyrBb(eModified_A, nummodesmax,
1757  PointsKey(nummodesmax + 1, eGaussLobattoLegendre));
1758  const BasisKey PyrBc(eModifiedPyr_C, nummodesmax,
1759  PointsKey(nummodesmax, eGaussRadauMAlpha2Beta0));
1760 
1761  // Create reference pyramid expansion
1763 
1765  PyrBa, PyrBb, PyrBc, pyrgeom);
1766 
1767  maxElmt[ePyramid] = PyrExp;
1768 
1769  // Pyramid:
1770  PyrExp->GetInverseBoundaryMaps(vmap, emap, fmap);
1771  vertMapMaxR[ePyramid] = vmap;
1772  edgeMapMaxR[ePyramid] = emap;
1773  faceMapMaxR[ePyramid] = fmap;
1774 
1775  // Set up Pyramid Transformation Matrix based on Tet
1776  // and Hex expansion
1777  SetUpPyrMaxRMat(nummodesmax, PyrExp, maxRmat, vertMapMaxR, edgeMapMaxR,
1778  faceMapMaxR);
1779  }
1780 
1781  if (Shapes[ePrism])
1782  {
1784  // Bases for Prism element
1785  const BasisKey PrismBa(
1786  eModified_A, nummodesmax,
1787  PointsKey(nummodesmax + 1, eGaussLobattoLegendre));
1788  const BasisKey PrismBb(
1789  eModified_A, nummodesmax,
1790  PointsKey(nummodesmax + 1, eGaussLobattoLegendre));
1791  const BasisKey PrismBc(eModified_B, nummodesmax,
1792  PointsKey(nummodesmax, eGaussRadauMAlpha1Beta0));
1793 
1794  // Create reference prismatic expansion
1796 
1798  PrismBa, PrismBb, PrismBc, prismgeom);
1799  maxElmt[ePrism] = PrismExp;
1800 
1801  // Prism:
1802  PrismExp->GetInverseBoundaryMaps(vmap, emap, fmap);
1803  vertMapMaxR[ePrism] = vmap;
1804  edgeMapMaxR[ePrism] = emap;
1805 
1806  faceMapMaxR[ePrism] = fmap;
1807 
1808  if ((Shapes[ePyramid]) || (Shapes[eHexahedron]))
1809  {
1810  ReSetPrismMaxRMat(nummodesmax, PrismExp, maxRmat, vertMapMaxR,
1811  edgeMapMaxR, faceMapMaxR, false);
1812  }
1813  else
1814  {
1815 
1816  // Get prismatic transformation matrix
1817  LocalRegions::MatrixKey PrismR(PreconR, ePrism, *PrismExp,
1818  linSysKey.GetConstFactors());
1819  maxRmat[ePrism] = PrismExp->GetLocMatrix(PrismR);
1820 
1821  if (Shapes[eTetrahedron]) // reset triangular faces from Tet
1822  {
1823  ReSetPrismMaxRMat(nummodesmax, PrismExp, maxRmat, vertMapMaxR,
1824  edgeMapMaxR, faceMapMaxR, true);
1825  }
1826  }
1827  }
1828 }
LibUtilities::CommSharedPtr m_comm
SpatialDomains::HexGeomSharedPtr CreateRefHexGeom(void)
Sets up the reference hexahedral element needed to construct a low energy basis.
void ReSetPrismMaxRMat(int nummodesmax, LocalRegions::PrismExpSharedPtr &PirsmExp, ShapeToDNekMap &maxRmat, ShapeToIntArrayMap &vertMapMaxR, ShapeToIntArrayArrayMap &edgeMapMaxR, ShapeToIntArrayArrayMap &faceMapMaxR, bool UseTetOnly)
void ReSetTetMaxRMat(int nummodesmax, LocalRegions::TetExpSharedPtr &TetExp, ShapeToDNekMap &maxRmat, ShapeToIntArrayMap &vertMapMaxR, ShapeToIntArrayArrayMap &edgeMapMaxR, ShapeToIntArrayArrayMap &faceMapMaxR)
SpatialDomains::TetGeomSharedPtr CreateRefTetGeom(void)
Sets up the reference tretrahedral element needed to construct a low energy basis.
SpatialDomains::PrismGeomSharedPtr CreateRefPrismGeom(void)
Sets up the reference prismatic element needed to construct a low energy basis.
void SetUpPyrMaxRMat(int nummodesmax, LocalRegions::PyrExpSharedPtr &PyrExp, ShapeToDNekMap &maxRmat, ShapeToIntArrayMap &vertMapMaxR, ShapeToIntArrayArrayMap &edgeMapMaxR, ShapeToIntArrayArrayMap &faceMapMaxR)
SpatialDomains::PyrGeomSharedPtr CreateRefPyrGeom(void)
Sets up the reference prismatic element needed to construct a low energy basis mapping arrays.
@ eGaussLobattoLegendre
1D Gauss-Lobatto-Legendre quadrature points
Definition: PointsType.h:53
@ eModified_B
Principle Modified Functions .
Definition: BasisType.h:51
@ eModified_C
Principle Modified Functions .
Definition: BasisType.h:52
@ eModifiedPyr_C
Principle Modified Functions.
Definition: BasisType.h:55
@ eModified_A
Principle Modified Functions .
Definition: BasisType.h:50
std::shared_ptr< PrismExp > PrismExpSharedPtr
Definition: PrismExp.h:209
std::shared_ptr< Expansion > ExpansionSharedPtr
Definition: Expansion.h:68
std::shared_ptr< HexExp > HexExpSharedPtr
Definition: HexExp.h:260
std::shared_ptr< PyrExp > PyrExpSharedPtr
Definition: PyrExp.h:185
std::shared_ptr< TetExp > TetExpSharedPtr
Definition: TetExp.h:214

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::MultiRegions::Preconditioner::m_comm, Nektar::MultiRegions::Preconditioner::m_linsys, 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 118 of file PreconditionerLowEnergy.cpp.

119 {
120  std::shared_ptr<MultiRegions::ExpList> expList =
121  ((m_linsys.lock())->GetLocMat()).lock();
123  GlobalLinSysKey linSysKey = (m_linsys.lock())->GetKey();
124 
125  int i, j, k;
126  int nVerts, nEdges, nFaces;
127  int eid, fid, n, cnt, nmodes, nedgemodes, nfacemodes;
128  int nedgemodesloc;
129  NekDouble zero = 0.0;
130 
131  int vMap1, vMap2, sign1, sign2;
132  int m, v, eMap1, eMap2, fMap1, fMap2;
133  int offset, globalrow, globalcol, nCoeffs;
134 
135  // Periodic information
136  PeriodicMap periodicVerts;
137  PeriodicMap periodicEdges;
138  PeriodicMap periodicFaces;
139  expList->GetPeriodicEntities(periodicVerts, periodicEdges, periodicFaces);
140 
141  // matrix storage
142  MatrixStorage storage = eFULL;
143  MatrixStorage vertstorage = eDIAGONAL;
144  MatrixStorage blkmatStorage = eDIAGONAL;
145 
146  // local element static condensed matrices
147  DNekScalBlkMatSharedPtr loc_mat;
148  DNekScalMatSharedPtr bnd_mat;
149 
150  DNekMatSharedPtr pRSRT;
151 
152  DNekMat RS;
153  DNekMat RSRT;
154 
155  auto asmMap = m_locToGloMap.lock();
156 
157  int nDirBnd = asmMap->GetNumGlobalDirBndCoeffs();
158  int nNonDirVerts = asmMap->GetNumNonDirVertexModes();
159 
160  // Vertex, edge and face preconditioner matrices
162  nNonDirVerts, nNonDirVerts, zero, vertstorage);
163 
164  Array<OneD, NekDouble> vertArray(nNonDirVerts, 0.0);
165  Array<OneD, long> VertBlockToUniversalMap(nNonDirVerts, -1);
166 
167  // maps for different element types
168  int n_exp = expList->GetNumElmts();
169  int nNonDirEdgeIDs = asmMap->GetNumNonDirEdges();
170  int nNonDirFaceIDs = asmMap->GetNumNonDirFaces();
171 
172  set<int> edgeDirMap;
173  set<int> faceDirMap;
174  map<int, int> uniqueEdgeMap;
175  map<int, int> uniqueFaceMap;
176 
177  // this should be of size total number of local edges + faces
178  Array<OneD, int> modeoffset(1 + nNonDirEdgeIDs + nNonDirFaceIDs, 0);
179  Array<OneD, int> globaloffset(1 + nNonDirEdgeIDs + nNonDirFaceIDs, 0);
180 
181  const Array<OneD, const ExpListSharedPtr> &bndCondExp =
182  expList->GetBndCondExpansions();
183  LocalRegions::Expansion2DSharedPtr bndCondFaceExp;
184  const Array<OneD, const SpatialDomains::BoundaryConditionShPtr>
185  &bndConditions = expList->GetBndConditions();
186 
187  int meshVertId;
188  int meshEdgeId;
189  int meshFaceId;
190 
191  const Array<OneD, const int> &extradiredges = asmMap->GetExtraDirEdges();
192  for (i = 0; i < extradiredges.size(); ++i)
193  {
194  meshEdgeId = extradiredges[i];
195  edgeDirMap.insert(meshEdgeId);
196  }
197 
198  // Determine which boundary edges and faces have dirichlet values
199  for (i = 0; i < bndCondExp.size(); i++)
200  {
201  cnt = 0;
202  for (j = 0; j < bndCondExp[i]->GetNumElmts(); j++)
203  {
204  bndCondFaceExp =
205  std::dynamic_pointer_cast<LocalRegions::Expansion2D>(
206  bndCondExp[i]->GetExp(j));
207  if (bndConditions[i]->GetBoundaryConditionType() ==
209  {
210  for (k = 0; k < bndCondFaceExp->GetNtraces(); k++)
211  {
212  meshEdgeId = bndCondFaceExp->GetGeom()->GetEid(k);
213  if (edgeDirMap.count(meshEdgeId) == 0)
214  {
215  edgeDirMap.insert(meshEdgeId);
216  }
217  }
218  meshFaceId = bndCondFaceExp->GetGeom()->GetGlobalID();
219  faceDirMap.insert(meshFaceId);
220  }
221  }
222  }
223 
224  int dof = 0;
225  int maxFaceDof = 0;
226  int maxEdgeDof = 0;
227  int nlocalNonDirEdges = 0;
228  int nlocalNonDirFaces = 0;
229  int ntotalentries = 0;
230 
231  map<int, int> EdgeSize;
232  map<int, int> FaceSize;
233  map<int, pair<int, int>> FaceModes;
234 
235  /// - Count edges, face and add up min edges and min face sizes
236  for (n = 0; n < n_exp; ++n)
237  {
238  locExpansion = expList->GetExp(n)->as<LocalRegions::Expansion3D>();
239 
240  nEdges = locExpansion->GetNedges();
241  for (j = 0; j < nEdges; ++j)
242  {
243  int nEdgeInteriorCoeffs = locExpansion->GetEdgeNcoeffs(j) - 2;
244  meshEdgeId = locExpansion->as<LocalRegions::Expansion3D>()
245  ->GetGeom3D()
246  ->GetEid(j);
247  if (EdgeSize.count(meshEdgeId) == 0)
248  {
249  EdgeSize[meshEdgeId] = nEdgeInteriorCoeffs;
250  }
251  else
252  {
253  EdgeSize[meshEdgeId] =
254  min(EdgeSize[meshEdgeId], nEdgeInteriorCoeffs);
255  }
256  }
257 
258  nFaces = locExpansion->GetNtraces();
259  for (j = 0; j < nFaces; ++j)
260  {
261  int nFaceInteriorCoeffs = locExpansion->GetTraceIntNcoeffs(j);
262  meshFaceId = locExpansion->GetGeom3D()->GetFid(j);
263 
264  if (FaceSize.count(meshFaceId) == 0)
265  {
266  FaceSize[meshFaceId] = nFaceInteriorCoeffs;
267 
268  int m0, m1;
269  locExpansion->GetTraceNumModes(j, m0, m1,
270  locExpansion->GetTraceOrient(j));
271  FaceModes[meshFaceId] = pair<int, int>(m0, m1);
272  }
273  else
274  {
275  if (nFaceInteriorCoeffs < FaceSize[meshFaceId])
276  {
277  FaceSize[meshFaceId] = nFaceInteriorCoeffs;
278  int m0, m1;
279  locExpansion->GetTraceNumModes(
280  j, m0, m1, locExpansion->GetTraceOrient(j));
281  FaceModes[meshFaceId] = pair<int, int>(m0, m1);
282  }
283  }
284  }
285  }
286 
287  bool verbose = expList->GetSession()->DefinesCmdLineArgument("verbose");
288 
289  // For parallel runs need to check have minimum of edges and faces over
290  // partition boundaries
291  if (m_comm->GetSize() > 1)
292  {
293  int EdgeSizeLen = EdgeSize.size();
294  int FaceSizeLen = FaceSize.size();
295  Array<OneD, long> FacetMap(EdgeSizeLen + FaceSizeLen, -1);
296  Array<OneD, NekDouble> FacetLen(EdgeSizeLen + FaceSizeLen, -1);
297 
298  map<int, int>::iterator it;
299 
300  cnt = 0;
301  int maxid = 0;
302  for (it = EdgeSize.begin(); it != EdgeSize.end(); ++it, ++cnt)
303  {
304  FacetMap[cnt] = it->first;
305  maxid = max(it->first, maxid);
306  FacetLen[cnt] = it->second;
307  }
308  maxid++;
309 
310  m_comm->AllReduce(maxid, ReduceMax);
311 
312  for (it = FaceSize.begin(); it != FaceSize.end(); ++it, ++cnt)
313  {
314  FacetMap[cnt] = it->first + maxid;
315  FacetLen[cnt] = it->second;
316  }
317 
318  // Exchange vertex data over different processes
319  Gs::gs_data *tmp = Gs::Init(FacetMap, m_comm, verbose);
320  Gs::Gather(FacetLen, Gs::gs_min, tmp);
321 
322  cnt = 0;
323  for (it = EdgeSize.begin(); it != EdgeSize.end(); ++it, ++cnt)
324  {
325  it->second = (int)FacetLen[cnt];
326  }
327 
328  for (it = FaceSize.begin(); it != FaceSize.end(); ++it, ++cnt)
329  {
330  it->second = (int)FacetLen[cnt];
331  }
332  }
333 
334  // Loop over all the elements in the domain and compute total edge
335  // DOF and set up unique ordering.
336  map<int, int> nblks;
337  int matrixlocation = 0;
338 
339  // First do periodic edges
340  for (auto &pIt : periodicEdges)
341  {
342  meshEdgeId = pIt.first;
343 
344  if (edgeDirMap.count(meshEdgeId) == 0)
345  {
346  dof = EdgeSize[meshEdgeId];
347  if (uniqueEdgeMap.count(meshEdgeId) == 0 && dof > 0)
348  {
349  bool SetUpNewEdge = true;
350 
351  for (i = 0; i < pIt.second.size(); ++i)
352  {
353  if (!pIt.second[i].isLocal)
354  {
355  continue;
356  }
357 
358  int meshEdgeId2 = pIt.second[i].id;
359  if (edgeDirMap.count(meshEdgeId2) == 0)
360  {
361  if (uniqueEdgeMap.count(meshEdgeId2) != 0)
362  {
363  // set unique map to same location
364  uniqueEdgeMap[meshEdgeId] =
365  uniqueEdgeMap[meshEdgeId2];
366  SetUpNewEdge = false;
367  }
368  }
369  else
370  {
371  edgeDirMap.insert(meshEdgeId);
372  SetUpNewEdge = false;
373  }
374  }
375 
376  if (SetUpNewEdge)
377  {
378  uniqueEdgeMap[meshEdgeId] = matrixlocation;
379  globaloffset[matrixlocation] += ntotalentries;
380  modeoffset[matrixlocation] = dof * dof;
381  ntotalentries += dof * dof;
382  nblks[matrixlocation++] = dof;
383  }
384  }
385  }
386  }
387 
388  for (cnt = n = 0; n < n_exp; ++n)
389  {
390  locExpansion = expList->GetExp(n)->as<LocalRegions::Expansion3D>();
391 
392  for (j = 0; j < locExpansion->GetNedges(); ++j)
393  {
394  meshEdgeId = locExpansion->GetGeom()->GetEid(j);
395  dof = EdgeSize[meshEdgeId];
396  maxEdgeDof = (dof > maxEdgeDof ? dof : maxEdgeDof);
397 
398  if (edgeDirMap.count(meshEdgeId) == 0)
399  {
400  if (uniqueEdgeMap.count(meshEdgeId) == 0 && dof > 0)
401 
402  {
403  uniqueEdgeMap[meshEdgeId] = matrixlocation;
404 
405  globaloffset[matrixlocation] += ntotalentries;
406  modeoffset[matrixlocation] = dof * dof;
407  ntotalentries += dof * dof;
408  nblks[matrixlocation++] = dof;
409  }
410  nlocalNonDirEdges += dof * dof;
411  }
412  }
413  }
414 
415  // Loop over all the elements in the domain and compute max face
416  // DOF. Reduce across all processes to get universal maximum.
417  // - Periodic faces
418  for (auto &pIt : periodicFaces)
419  {
420  meshFaceId = pIt.first;
421 
422  if (faceDirMap.count(meshFaceId) == 0)
423  {
424  dof = FaceSize[meshFaceId];
425 
426  if (uniqueFaceMap.count(meshFaceId) == 0 && dof > 0)
427  {
428  bool SetUpNewFace = true;
429 
430  if (pIt.second[0].isLocal)
431  {
432  int meshFaceId2 = pIt.second[0].id;
433 
434  if (faceDirMap.count(meshFaceId2) == 0)
435  {
436  if (uniqueFaceMap.count(meshFaceId2) != 0)
437  {
438  // set unique map to same location
439  uniqueFaceMap[meshFaceId] =
440  uniqueFaceMap[meshFaceId2];
441  SetUpNewFace = false;
442  }
443  }
444  else // set face to be a Dirichlet face
445  {
446  faceDirMap.insert(meshFaceId);
447  SetUpNewFace = false;
448  }
449  }
450 
451  if (SetUpNewFace)
452  {
453  uniqueFaceMap[meshFaceId] = matrixlocation;
454 
455  modeoffset[matrixlocation] = dof * dof;
456  globaloffset[matrixlocation] += ntotalentries;
457  ntotalentries += dof * dof;
458  nblks[matrixlocation++] = dof;
459  }
460  }
461  }
462  }
463 
464  for (cnt = n = 0; n < n_exp; ++n)
465  {
466  locExpansion = expList->GetExp(n)->as<LocalRegions::Expansion3D>();
467 
468  for (j = 0; j < locExpansion->GetNtraces(); ++j)
469  {
470  meshFaceId = locExpansion->GetGeom()->GetFid(j);
471 
472  dof = FaceSize[meshFaceId];
473  maxFaceDof = (dof > maxFaceDof ? dof : maxFaceDof);
474 
475  if (faceDirMap.count(meshFaceId) == 0)
476  {
477  if (uniqueFaceMap.count(meshFaceId) == 0 && dof > 0)
478  {
479  uniqueFaceMap[meshFaceId] = matrixlocation;
480  modeoffset[matrixlocation] = dof * dof;
481  globaloffset[matrixlocation] += ntotalentries;
482  ntotalentries += dof * dof;
483  nblks[matrixlocation++] = dof;
484  }
485  nlocalNonDirFaces += dof * dof;
486  }
487  }
488  }
489 
490  m_comm->AllReduce(maxEdgeDof, ReduceMax);
491  m_comm->AllReduce(maxFaceDof, ReduceMax);
492 
493  // Allocate arrays for block to universal map (number of expansions * p^2)
494  Array<OneD, long> BlockToUniversalMap(ntotalentries, -1);
495  Array<OneD, int> localToGlobalMatrixMap(
496  nlocalNonDirEdges + nlocalNonDirFaces, -1);
497 
498  // Allocate arrays to store matrices (number of expansions * p^2)
499  Array<OneD, NekDouble> BlockArray(nlocalNonDirEdges + nlocalNonDirFaces,
500  0.0);
501 
502  int matrixoffset = 0;
503  int vGlobal;
504  int uniEdgeOffset = 0;
505 
506  // Need to obtain a fixed offset for the universal number
507  // of the faces which come after the edge numbering
508  for (n = 0; n < n_exp; ++n)
509  {
510  for (j = 0; j < locExpansion->GetNedges(); ++j)
511  {
512  meshEdgeId = locExpansion->as<LocalRegions::Expansion3D>()
513  ->GetGeom3D()
514  ->GetEid(j);
515 
516  uniEdgeOffset = max(meshEdgeId, uniEdgeOffset);
517  }
518  }
519  uniEdgeOffset++;
520 
521  m_comm->AllReduce(uniEdgeOffset, ReduceMax);
522  uniEdgeOffset = uniEdgeOffset * maxEdgeDof * maxEdgeDof;
523 
524  for (n = 0; n < n_exp; ++n)
525  {
526  locExpansion = expList->GetExp(n)->as<LocalRegions::Expansion3D>();
527 
528  // loop over the edges of the expansion
529  for (j = 0; j < locExpansion->GetNedges(); ++j)
530  {
531  // get mesh edge id
532  meshEdgeId = locExpansion->GetGeom()->GetEid(j);
533 
534  nedgemodes = EdgeSize[meshEdgeId];
535 
536  if (edgeDirMap.count(meshEdgeId) == 0 && nedgemodes > 0)
537  {
538  // Determine the Global edge offset
539  int edgeOffset = globaloffset[uniqueEdgeMap[meshEdgeId]];
540 
541  // Determine a universal map offset
542  int uniOffset = meshEdgeId;
543  auto pIt = periodicEdges.find(meshEdgeId);
544  if (pIt != periodicEdges.end())
545  {
546  for (int l = 0; l < pIt->second.size(); ++l)
547  {
548  uniOffset = min(uniOffset, pIt->second[l].id);
549  }
550  }
551  uniOffset = uniOffset * maxEdgeDof * maxEdgeDof;
552 
553  for (k = 0; k < nedgemodes * nedgemodes; ++k)
554  {
555  vGlobal = edgeOffset + k;
556  localToGlobalMatrixMap[matrixoffset + k] = vGlobal;
557  BlockToUniversalMap[vGlobal] = uniOffset + k + 1;
558  }
559  matrixoffset += nedgemodes * nedgemodes;
560  }
561  }
562 
563  Array<OneD, unsigned int> faceInteriorMap;
564  Array<OneD, int> faceInteriorSign;
565  // loop over the faces of the expansion
566  for (j = 0; j < locExpansion->GetNtraces(); ++j)
567  {
568  // get mesh face id
569  meshFaceId = locExpansion->GetGeom()->GetFid(j);
570 
571  nfacemodes = FaceSize[meshFaceId];
572 
573  // Check if face has dirichlet values
574  if (faceDirMap.count(meshFaceId) == 0 && nfacemodes > 0)
575  {
576  // Determine the Global edge offset
577  int faceOffset = globaloffset[uniqueFaceMap[meshFaceId]];
578  // Determine a universal map offset
579  int uniOffset = meshFaceId;
580  // use minimum face edge when periodic
581  auto pIt = periodicFaces.find(meshFaceId);
582  if (pIt != periodicFaces.end())
583  {
584  uniOffset = min(uniOffset, pIt->second[0].id);
585  }
586  uniOffset = uniOffset * maxFaceDof * maxFaceDof;
587 
588  for (k = 0; k < nfacemodes * nfacemodes; ++k)
589  {
590  vGlobal = faceOffset + k;
591 
592  localToGlobalMatrixMap[matrixoffset + k] = vGlobal;
593 
594  BlockToUniversalMap[vGlobal] =
595  uniOffset + uniEdgeOffset + k + 1;
596  }
597  matrixoffset += nfacemodes * nfacemodes;
598  }
599  }
600  }
601 
602  matrixoffset = 0;
603 
604  map<int, int>::iterator it;
605  Array<OneD, unsigned int> n_blks(nblks.size() + 1);
606  n_blks[0] = nNonDirVerts;
607  for (i = 1, it = nblks.begin(); it != nblks.end(); ++it)
608  {
609  n_blks[i++] = it->second;
610  }
611 
613  blkmatStorage);
614 
615  // Here we loop over the expansion and build the block low energy
616  // preconditioner as well as the block versions of the transformation
617  // matrices.
618  for (cnt = n = 0; n < n_exp; ++n)
619  {
620  locExpansion = expList->GetExp(n)->as<LocalRegions::Expansion3D>();
621  nCoeffs = locExpansion->NumBndryCoeffs();
622 
623  // Get correct transformation matrix for element type
624  DNekMat &R = (*m_RBlk->GetBlock(n, n));
625 
626  pRSRT = MemoryManager<DNekMat>::AllocateSharedPtr(nCoeffs, nCoeffs,
627  zero, storage);
628  RSRT = (*pRSRT);
629 
630  nVerts = locExpansion->GetGeom()->GetNumVerts();
631  nEdges = locExpansion->GetGeom()->GetNumEdges();
632  nFaces = locExpansion->GetGeom()->GetNumFaces();
633 
634  // Get statically condensed matrix
635  loc_mat = (m_linsys.lock())->GetStaticCondBlock(n);
636 
637  // Extract boundary block (elemental S1)
638  bnd_mat = loc_mat->GetBlock(0, 0);
639 
640  // offset by number of rows
641  offset = bnd_mat->GetRows();
642 
643  DNekScalMat &S = (*bnd_mat);
644 
645  DNekMat Sloc(nCoeffs, nCoeffs);
646 
647  // For variable p we need to just use the active modes
648  NekDouble val;
649 
650  for (int i = 0; i < nCoeffs; ++i)
651  {
652  for (int j = 0; j < nCoeffs; ++j)
653  {
654  val = S(i, j) * m_variablePmask[cnt + i] *
655  m_variablePmask[cnt + j];
656  Sloc.SetValue(i, j, val);
657  }
658  }
659 
660  // Calculate R*S*trans(R)
661  RSRT = R * Sloc * Transpose(R);
662 
663  // loop over vertices of the element and return the vertex map
664  // for each vertex
665  for (v = 0; v < nVerts; ++v)
666  {
667  vMap1 = locExpansion->GetVertexMap(v);
668 
669  // Get vertex map
670  globalrow = asmMap->GetLocalToGlobalBndMap(cnt + vMap1) - nDirBnd;
671 
672  if (globalrow >= 0)
673  {
674  for (m = 0; m < nVerts; ++m)
675  {
676  vMap2 = locExpansion->GetVertexMap(m);
677 
678  // global matrix location (without offset due to
679  // dirichlet values)
680  globalcol =
681  asmMap->GetLocalToGlobalBndMap(cnt + vMap2) - nDirBnd;
682 
683  // offset for dirichlet conditions
684  if (globalcol == globalrow)
685  {
686  // modal connectivity between elements
687  sign1 = asmMap->GetLocalToGlobalBndSign(cnt + vMap1);
688  sign2 = asmMap->GetLocalToGlobalBndSign(cnt + vMap2);
689 
690  vertArray[globalrow] +=
691  sign1 * sign2 * RSRT(vMap1, vMap2);
692 
693  meshVertId = locExpansion->GetGeom()->GetVid(v);
694 
695  auto pIt = periodicVerts.find(meshVertId);
696  if (pIt != periodicVerts.end())
697  {
698  for (k = 0; k < pIt->second.size(); ++k)
699  {
700  meshVertId = min(meshVertId, pIt->second[k].id);
701  }
702  }
703 
704  VertBlockToUniversalMap[globalrow] = meshVertId + 1;
705  }
706  }
707  }
708  }
709 
710  // loop over edges of the element and return the edge map
711  for (eid = 0; eid < nEdges; ++eid)
712  {
713 
714  meshEdgeId = locExpansion->as<LocalRegions::Expansion3D>()
715  ->GetGeom3D()
716  ->GetEid(eid);
717 
718  nedgemodes = EdgeSize[meshEdgeId];
719  if (nedgemodes)
720  {
721  nedgemodesloc = locExpansion->GetEdgeNcoeffs(eid) - 2;
722  DNekMatSharedPtr m_locMat =
724  nedgemodes, nedgemodes, zero, storage);
725 
726  Array<OneD, unsigned int> edgemodearray =
727  locExpansion->GetEdgeInverseBoundaryMap(eid);
728 
729  if (edgeDirMap.count(meshEdgeId) == 0)
730  {
731  for (v = 0; v < nedgemodesloc; ++v)
732  {
733  eMap1 = edgemodearray[v];
734  sign1 = asmMap->GetLocalToGlobalBndSign(cnt + eMap1);
735 
736  if (sign1 == 0)
737  {
738  continue;
739  }
740 
741  for (m = 0; m < nedgemodesloc; ++m)
742  {
743  eMap2 = edgemodearray[m];
744 
745  // modal connectivity between elements
746  sign2 =
747  asmMap->GetLocalToGlobalBndSign(cnt + eMap2);
748 
749  NekDouble globalEdgeValue =
750  sign1 * sign2 * RSRT(eMap1, eMap2);
751 
752  if (sign2 != 0)
753  {
754  // if(eMap1 == eMap2)
755  BlockArray[matrixoffset + v * nedgemodes + m] =
756  globalEdgeValue;
757  }
758  }
759  }
760  matrixoffset += nedgemodes * nedgemodes;
761  }
762  }
763  }
764 
765  // loop over faces of the element and return the face map
766  for (fid = 0; fid < nFaces; ++fid)
767  {
768  meshFaceId = locExpansion->as<LocalRegions::Expansion3D>()
769  ->GetGeom3D()
770  ->GetFid(fid);
771 
772  nfacemodes = FaceSize[meshFaceId];
773  if (nfacemodes > 0)
774  {
775  DNekMatSharedPtr m_locMat =
777  nfacemodes, nfacemodes, zero, storage);
778 
779  if (faceDirMap.count(meshFaceId) == 0)
780  {
781  Array<OneD, unsigned int> facemodearray;
782  StdRegions::Orientation faceOrient =
783  locExpansion->GetTraceOrient(fid);
784 
785  auto pIt = periodicFaces.find(meshFaceId);
786  if (pIt != periodicFaces.end())
787  {
788  if (meshFaceId == min(meshFaceId, pIt->second[0].id))
789  {
790  faceOrient = DeterminePeriodicFaceOrient(
791  faceOrient, pIt->second[0].orient);
792  }
793  }
794 
795  facemodearray = locExpansion->GetTraceInverseBoundaryMap(
796  fid, faceOrient, FaceModes[meshFaceId].first,
797  FaceModes[meshFaceId].second);
798 
799  for (v = 0; v < nfacemodes; ++v)
800  {
801  fMap1 = facemodearray[v];
802 
803  sign1 = asmMap->GetLocalToGlobalBndSign(cnt + fMap1);
804 
805  ASSERTL1(sign1 != 0,
806  "Something is wrong since we "
807  "shoudl only be extracting modes for "
808  "lowest order expansion");
809 
810  for (m = 0; m < nfacemodes; ++m)
811  {
812  fMap2 = facemodearray[m];
813 
814  // modal connectivity between elements
815  sign2 =
816  asmMap->GetLocalToGlobalBndSign(cnt + fMap2);
817 
818  ASSERTL1(sign2 != 0,
819  "Something is wrong since "
820  "we shoudl only be extracting modes for "
821  "lowest order expansion");
822 
823  // Get the face-face value from the
824  // low energy matrix (S2)
825  NekDouble globalFaceValue =
826  sign1 * sign2 * RSRT(fMap1, fMap2);
827 
828  // local face value to global face value
829  // if(fMap1 == fMap2)
830  BlockArray[matrixoffset + v * nfacemodes + m] =
831  globalFaceValue;
832  }
833  }
834  matrixoffset += nfacemodes * nfacemodes;
835  }
836  }
837  }
838 
839  // offset for the expansion
840  cnt += nCoeffs;
841  }
842 
843  if (nNonDirVerts != 0)
844  {
845  // Exchange vertex data over different processes
846  Gs::gs_data *tmp = Gs::Init(VertBlockToUniversalMap, m_comm, verbose);
847  Gs::Gather(vertArray, Gs::gs_add, tmp);
848  }
849 
850  Array<OneD, NekDouble> GlobalBlock(ntotalentries, 0.0);
851  if (ntotalentries)
852  {
853  // Assemble edge matrices of each process
854  Vmath::Assmb(BlockArray.size(), BlockArray, localToGlobalMatrixMap,
855  GlobalBlock);
856  }
857 
858  // Exchange edge & face data over different processes
859  Gs::gs_data *tmp1 = Gs::Init(BlockToUniversalMap, m_comm, verbose);
860  Gs::Gather(GlobalBlock, Gs::gs_add, tmp1);
861 
862  // Populate vertex block
863  for (int i = 0; i < nNonDirVerts; ++i)
864  {
865  VertBlk->SetValue(i, i, 1.0 / vertArray[i]);
866  }
867 
868  // Set the first block to be the diagonal of the vertex space
869  m_BlkMat->SetBlock(0, 0, VertBlk);
870 
871  // Build the edge and face matrices from the vector
872  DNekMatSharedPtr gmat;
873 
874  offset = 0;
875  // -1 since we ignore vert block
876  for (int loc = 0; loc < n_blks.size() - 1; ++loc)
877  {
878  nmodes = n_blks[1 + loc];
879  gmat = MemoryManager<DNekMat>::AllocateSharedPtr(nmodes, nmodes, zero,
880  storage);
881 
882  for (v = 0; v < nmodes; ++v)
883  {
884  for (m = 0; m < nmodes; ++m)
885  {
886  NekDouble Value = GlobalBlock[offset + v * nmodes + m];
887  gmat->SetValue(v, m, Value);
888  }
889  }
890  m_BlkMat->SetBlock(1 + loc, 1 + loc, gmat);
891  offset += modeoffset[loc];
892  }
893 
894  // invert blocks.
895  int totblks = m_BlkMat->GetNumberOfBlockRows();
896  for (i = 1; i < totblks; ++i)
897  {
898  unsigned int nmodes = m_BlkMat->GetNumberOfRowsInBlockRow(i);
899  if (nmodes)
900  {
901  DNekMatSharedPtr tmp_mat =
902  MemoryManager<DNekMat>::AllocateSharedPtr(nmodes, nmodes, zero,
903  storage);
904 
905  tmp_mat = m_BlkMat->GetBlock(i, i);
906  tmp_mat->Invert();
907 
908  m_BlkMat->SetBlock(i, i, tmp_mat);
909  }
910  }
911 }
#define ASSERTL1(condition, msg)
Assert Level 1 – Debugging which is used whether in FULLDEBUG or DEBUG compilation mode....
Definition: ErrorUtil.hpp:249
static void Gather(Nektar::Array< OneD, NekDouble > pU, gs_op pOp, gs_data *pGsh, Nektar::Array< OneD, NekDouble > pBuffer=NullNekDouble1DArray)
Performs a gather-scatter operation of the provided values.
Definition: GsLib.hpp:270
@ gs_add
Definition: GsLib.hpp:62
@ gs_min
Definition: GsLib.hpp:64
static gs_data * Init(const Nektar::Array< OneD, long > pId, const LibUtilities::CommSharedPtr &pComm, bool verbose=true)
Initialise Gather-Scatter map.
Definition: GsLib.hpp:192
std::shared_ptr< Expansion2D > Expansion2DSharedPtr
Definition: Expansion1D.h:47
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
Definition: NekTypeDefs.hpp:50
NekMatrix< InnerMatrixType, BlockMatrixTag > Transpose(NekMatrix< InnerMatrixType, BlockMatrixTag > &rhs)
std::shared_ptr< DNekScalBlkMat > DNekScalBlkMatSharedPtr
Definition: NekTypeDefs.hpp:79
void Assmb(int n, const T *x, const int *y, T *z)
Assemble z[y[i]] += x[i]; z should be zero'd first.
Definition: Vmath.cpp:862

References Nektar::MemoryManager< DataType >::AllocateSharedPtr(), ASSERTL1, Vmath::Assmb(), Nektar::MultiRegions::DeterminePeriodicFaceOrient(), Nektar::eDIAGONAL, Nektar::SpatialDomains::eDirichlet, Nektar::eFULL, Gs::Gather(), Nektar::StdRegions::StdExpansion3D::GetEdgeNcoeffs(), Nektar::LocalRegions::Expansion::GetGeom(), Nektar::StdRegions::StdExpansion3D::GetNedges(), Gs::gs_add, Gs::gs_min, Gs::Init(), CG_Iterations::loc, m_BlkMat, Nektar::MultiRegions::Preconditioner::m_comm, Nektar::MultiRegions::Preconditioner::m_linsys, Nektar::MultiRegions::Preconditioner::m_locToGloMap, m_RBlk, m_variablePmask, 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 
)
overrideprotectedvirtual

Apply the low energy preconditioner during the conjugate gradient routine

Reimplemented from Nektar::MultiRegions::Preconditioner.

Definition at line 917 of file PreconditionerLowEnergy.cpp.

919 {
920  int nDir = m_locToGloMap.lock()->GetNumGlobalDirBndCoeffs();
921  int nGlobal = m_locToGloMap.lock()->GetNumGlobalBndCoeffs();
922  int nNonDir = nGlobal - nDir;
923  DNekBlkMat &M = (*m_BlkMat);
924 
925  NekVector<NekDouble> r(nNonDir, pInput, eWrapper);
926  NekVector<NekDouble> z(nNonDir, pOutput, eWrapper);
927 
928  z = M * r;
929 }
NekMatrix< NekMatrix< NekDouble, StandardMatrixTag >, BlockMatrixTag > DNekBlkMat
Definition: NekTypeDefs.hpp:58

References 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 1127 of file PreconditionerLowEnergy.cpp.

1129 {
1130  int nLocBndDofs = m_locToGloMap.lock()->GetNumLocalBndCoeffs();
1131 
1132  ASSERTL1(pInput.size() >= nLocBndDofs,
1133  "Input array is smaller than nLocBndDofs");
1134  ASSERTL1(pOutput.size() >= nLocBndDofs,
1135  "Output array is smaller than nLocBndDofs");
1136 
1137  // Block inverse transformation matrix
1138  DNekBlkMat &invR = *m_InvRBlk;
1139 
1140  Array<OneD, NekDouble> pLocalIn(nLocBndDofs, pInput.get());
1141 
1142  // Multiply by the inverse transformation matrix
1143  int cnt = 0;
1144  int cnt1 = 0;
1145  for (int i = 0; i < m_sameBlock.size(); ++i)
1146  {
1147  int nexp = m_sameBlock[i].first;
1148  int nbndcoeffs = m_sameBlock[i].second;
1149  Blas::Dgemm('N', 'N', nbndcoeffs, nexp, nbndcoeffs, 1.0,
1150  &(invR.GetBlock(cnt1, cnt1)->GetPtr()[0]), nbndcoeffs,
1151  pLocalIn.get() + cnt, nbndcoeffs, 0.0, pOutput.get() + cnt,
1152  nbndcoeffs);
1153  cnt += nbndcoeffs * nexp;
1154  cnt1 += nexp;
1155  }
1156 }
static void Dgemm(const char &transa, const char &transb, const int &m, const int &n, const int &k, const double &alpha, const double *a, const int &lda, const double *b, const int &ldb, const double &beta, double *c, const int &ldc)
BLAS level 3: Matrix-matrix multiply C = A x B where op(A)[m x k], op(B)[k x n], C[m x n] DGEMM perfo...
Definition: Blas.hpp:368

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 1051 of file PreconditionerLowEnergy.cpp.

1053 {
1054  int nLocBndDofs = m_locToGloMap.lock()->GetNumLocalBndCoeffs();
1055 
1056  // Block transformation matrix
1057  DNekBlkMat &R = *m_RBlk;
1058 
1059  Array<OneD, NekDouble> pLocalIn(nLocBndDofs, pInOut.get());
1060 
1061  // Apply mask in case of variable P
1062  Vmath::Vmul(nLocBndDofs, pLocalIn, 1, m_variablePmask, 1, pLocalIn, 1);
1063 
1064  // Multiply by the block transformation matrix
1065  int cnt = 0;
1066  int cnt1 = 0;
1067  for (int i = 0; i < m_sameBlock.size(); ++i)
1068  {
1069  int nexp = m_sameBlock[i].first;
1070  int nbndcoeffs = m_sameBlock[i].second;
1071  Blas::Dgemm('N', 'N', nbndcoeffs, nexp, nbndcoeffs, 1.0,
1072  &(R.GetBlock(cnt1, cnt1)->GetPtr()[0]), nbndcoeffs,
1073  pLocalIn.get() + cnt, nbndcoeffs, 0.0, pInOut.get() + cnt,
1074  nbndcoeffs);
1075  cnt += nbndcoeffs * nexp;
1076  cnt1 += nexp;
1077  }
1078 }
void Vmul(int n, const T *x, const int incx, const T *y, const int incy, T *z, const int incz)
Multiply vector z = x*y.
Definition: Vmath.cpp:209

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 1089 of file PreconditionerLowEnergy.cpp.

1091 {
1092  int nLocBndDofs = m_locToGloMap.lock()->GetNumLocalBndCoeffs();
1093 
1094  ASSERTL1(pInOut.size() >= nLocBndDofs,
1095  "Output array is not greater than the nLocBndDofs");
1096 
1097  // Block transposed transformation matrix
1098  DNekBlkMat &R = *m_RBlk;
1099 
1100  Array<OneD, NekDouble> pLocalIn(nLocBndDofs, pInOut.get());
1101 
1102  // Multiply by the transpose of block transformation matrix
1103  int cnt = 0;
1104  int cnt1 = 0;
1105  for (int i = 0; i < m_sameBlock.size(); ++i)
1106  {
1107  int nexp = m_sameBlock[i].first;
1108  int nbndcoeffs = m_sameBlock[i].second;
1109  Blas::Dgemm('T', 'N', nbndcoeffs, nexp, nbndcoeffs, 1.0,
1110  &(R.GetBlock(cnt1, cnt1)->GetPtr()[0]), nbndcoeffs,
1111  pLocalIn.get() + cnt, nbndcoeffs, 0.0, pInOut.get() + cnt,
1112  nbndcoeffs);
1113  cnt += nbndcoeffs * nexp;
1114  cnt1 += nexp;
1115  }
1116 
1117  Vmath::Vmul(nLocBndDofs, pInOut, 1, m_variablePmask, 1, pInOut, 1);
1118 }

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 1165 of file PreconditionerLowEnergy.cpp.

1167 {
1168  int nLocBndDofs = m_locToGloMap.lock()->GetNumLocalBndCoeffs();
1169 
1170  ASSERTL1(pInput.size() >= nLocBndDofs,
1171  "Input array is less than nLocBndDofs");
1172  ASSERTL1(pOutput.size() >= nLocBndDofs,
1173  "Output array is less than nLocBndDofs");
1174 
1175  // Block inverse transformation matrix
1176  DNekBlkMat &invR = *m_InvRBlk;
1177 
1178  Array<OneD, NekDouble> pLocalIn(nLocBndDofs, pInput.get());
1179 
1180  // Multiply by the transpose of block transformation matrix
1181  int cnt = 0;
1182  int cnt1 = 0;
1183  for (int i = 0; i < m_sameBlock.size(); ++i)
1184  {
1185  int nexp = m_sameBlock[i].first;
1186  int nbndcoeffs = m_sameBlock[i].second;
1187  Blas::Dgemm('T', 'N', nbndcoeffs, nexp, nbndcoeffs, 1.0,
1188  &(invR.GetBlock(cnt1, cnt1)->GetPtr()[0]), nbndcoeffs,
1189  pLocalIn.get() + cnt, nbndcoeffs, 0.0, pOutput.get() + cnt,
1190  nbndcoeffs);
1191  cnt += nbndcoeffs * nexp;
1192  cnt1 += nexp;
1193  }
1194 }

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 73 of file PreconditionerLowEnergy.cpp.

74 {
75  GlobalSysSolnType solvertype = m_locToGloMap.lock()->GetGlobalSysSolnType();
76 
77  ASSERTL0(solvertype == eIterativeStaticCond ||
78  solvertype == ePETScStaticCond,
79  "Solver type not valid");
80 
81  std::shared_ptr<MultiRegions::ExpList> expList =
82  ((m_linsys.lock())->GetLocMat()).lock();
83 
84  m_comm = expList->GetComm();
85 
87 
88  locExpansion = expList->GetExp(0);
89 
90  int nDim = locExpansion->GetShapeDimension();
91 
92  ASSERTL0(nDim == 3, "Preconditioner type only valid in 3D");
93 
94  // Set up block transformation matrix
96 
97  // Sets up variable p mask
99 }
#define ASSERTL0(condition, msg)
Definition: ErrorUtil.hpp:215

References ASSERTL0, CreateVariablePMask(), Nektar::MultiRegions::eIterativeStaticCond, Nektar::MultiRegions::ePETScStaticCond, Nektar::MultiRegions::Preconditioner::m_comm, 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 1203 of file PreconditionerLowEnergy.cpp.

1205 {
1206  std::shared_ptr<MultiRegions::ExpList> expList =
1207  ((m_linsys.lock())->GetLocMat()).lock();
1208 
1209  LocalRegions::ExpansionSharedPtr locExpansion;
1210  locExpansion = expList->GetExp(n);
1211  unsigned int nbnd = locExpansion->NumBndryCoeffs();
1212 
1213  MatrixStorage storage = eFULL;
1214  DNekMatSharedPtr pS2 =
1215  MemoryManager<DNekMat>::AllocateSharedPtr(nbnd, nbnd, 0.0, storage);
1216 
1217  // transformation matrices
1218  DNekMat &R = (*m_RBlk->GetBlock(n, n));
1219 
1220  // Original Schur Complement
1221  DNekScalMat &S1 = (*loc_mat);
1222 
1223  DNekMat Sloc(nbnd, nbnd);
1224 
1225  // For variable p we need to just use the active modes
1226  NekDouble val;
1227 
1228  for (int i = 0; i < nbnd; ++i)
1229  {
1230  for (int j = 0; j < nbnd; ++j)
1231  {
1232  val = S1(i, j) * m_variablePmask[bndoffset + i] *
1233  m_variablePmask[bndoffset + j];
1234  Sloc.SetValue(i, j, val);
1235  }
1236  }
1237 
1238  // create low energy matrix
1239  DNekMat &S2 = (*pS2);
1240 
1241  S2 = R * Sloc * Transpose(R);
1242 
1243  DNekScalMatSharedPtr return_val;
1244  return_val = MemoryManager<DNekScalMat>::AllocateSharedPtr(1.0, pS2);
1245 
1246  return return_val;
1247 }

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.
Definition: NekFactory.hpp:198
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 69 of file PreconditionerLowEnergy.h.

◆ m_BlkMat

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

Definition at line 81 of file PreconditionerLowEnergy.h.

Referenced by v_BuildPreconditioner().

◆ 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 87 of file PreconditionerLowEnergy.h.

Referenced by CreateVariablePMask().

◆ m_variablePmask

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