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

Constructs mappings for the C0 scalar continuous Galerkin formulation. More...

#include <AssemblyMapCG.h>

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

Public Member Functions

 AssemblyMapCG (const LibUtilities::SessionReaderSharedPtr &pSession, const LibUtilities::CommSharedPtr &comm, const std::string variable="DefaultVar")
 Default constructor.
 
 AssemblyMapCG (const LibUtilities::SessionReaderSharedPtr &pSession, const int numLocalCoeffs, const ExpList &locExp, const BndCondExp &bndCondExp=NullExpListSharedPtrArray, const BndCond &bndConditions=SpatialDomains::NullBoundaryConditionShPtrArray, const bool checkIfSingular=false, const std::string variable="defaultVar", const PeriodicMap &periodicVerts=NullPeriodicMap, const PeriodicMap &periodicEdges=NullPeriodicMap, const PeriodicMap &periodicFaces=NullPeriodicMap)
 General constructor for expansions of all dimensions without boundary conditions.
 
 ~AssemblyMapCG () override
 Destructor.
 
std::set< ExtraDirDof > & GetCopyLocalDirDofs ()
 
std::set< int > & GetParallelDirBndSign ()
 
- Public Member Functions inherited from Nektar::MultiRegions::AssemblyMap
 AssemblyMap ()
 Default constructor.
 
 AssemblyMap (const LibUtilities::SessionReaderSharedPtr &pSession, const LibUtilities::CommSharedPtr &comm, const std::string variable="DefaultVar")
 Constructor with a communicator.
 
 AssemblyMap (AssemblyMap *oldLevelMap, const BottomUpSubStructuredGraphSharedPtr &multiLevelGraph)
 Constructor for next level in multi-level static condensation.
 
virtual ~AssemblyMap ()
 Destructor.
 
LibUtilities::CommSharedPtr GetComm ()
 Retrieves the communicator.
 
std::string GetVariable ()
 Retrieves the variable string.
 
size_t GetHash () const
 Retrieves the hash of this map.
 
int GetLocalToGlobalMap (const int i) const
 
int GetGlobalToUniversalMap (const int i) const
 
int GetGlobalToUniversalMapUnique (const int i) const
 
const Array< OneD, const int > & GetLocalToGlobalMap ()
 
const Array< OneD, const int > & GetGlobalToUniversalMap ()
 
const Array< OneD, const int > & GetGlobalToUniversalMapUnique ()
 
NekDouble GetLocalToGlobalSign (const int i) const
 
const Array< OneD, NekDouble > & GetLocalToGlobalSign () const
 
void LocalToGlobal (const Array< OneD, const NekDouble > &loc, Array< OneD, NekDouble > &global, bool useComm=true) const
 
void LocalToGlobal (const NekVector< NekDouble > &loc, NekVector< NekDouble > &global, bool useComm=true) const
 
void GlobalToLocal (const Array< OneD, const NekDouble > &global, Array< OneD, NekDouble > &loc) const
 
void GlobalToLocal (const NekVector< NekDouble > &global, NekVector< NekDouble > &loc) const
 
void Assemble (const Array< OneD, const NekDouble > &loc, Array< OneD, NekDouble > &global) const
 
void Assemble (const NekVector< NekDouble > &loc, NekVector< NekDouble > &global) const
 
void UniversalAssemble (Array< OneD, NekDouble > &pGlobal) const
 
void UniversalAssemble (NekVector< NekDouble > &pGlobal) const
 
void UniversalAssemble (Array< OneD, NekDouble > &pGlobal, int offset) const
 
void UniversalAbsMaxBnd (Array< OneD, NekDouble > &bndvals)
 
int GetLocalToGlobalBndMap (const int i) const
 Retrieve the global index of a given local boundary mode.
 
const Array< OneD, const int > & GetLocalToGlobalBndMap ()
 Retrieve the global indices of the local boundary modes.
 
const Array< OneD, const int > & GetGlobalToUniversalBndMap ()
 
const Array< OneD, const int > & GetGlobalToUniversalBndMapUnique ()
 
bool GetSignChange ()
 Returns true if using a modal expansion requiring a change of sign of some modes.
 
NekDouble GetLocalToGlobalBndSign (const int i) const
 Retrieve the sign change of a given local boundary mode.
 
Array< OneD, const NekDoubleGetLocalToGlobalBndSign () const
 Retrieve the sign change for all local boundary modes.
 
const Array< OneD, const int > & GetBndCondCoeffsToLocalCoeffsMap ()
 Retrieves the local indices corresponding to the boundary expansion modes.
 
const Array< OneD, NekDouble > & GetBndCondCoeffsToLocalCoeffsSign ()
 Returns the modal sign associated with a given boundary expansion mode.
 
const Array< OneD, const int > & GetBndCondCoeffsToLocalTraceMap ()
 Retrieves the local indices corresponding to the boundary expansion modes to global trace.
 
int GetBndCondIDToGlobalTraceID (const int i)
 Returns the global index of the boundary trace giving the index on the boundary expansion.
 
const Array< OneD, const int > & GetBndCondIDToGlobalTraceID ()
 
int GetPerBndCondIDToGlobalTraceID (const int i)
 Returns the global index of the rotational periodic boundary trace giving the index on the rotational periodic boundary condition.
 
const Array< OneD, const int > & GetPerBndCondIDToGlobalTraceID ()
 
int GetNumGlobalDirBndCoeffs () const
 Returns the number of global Dirichlet boundary coefficients.
 
int GetNumLocalDirBndCoeffs () const
 Returns the number of local Dirichlet boundary coefficients.
 
int GetNumGlobalBndCoeffs () const
 Returns the total number of global boundary coefficients.
 
int GetNumLocalBndCoeffs () const
 Returns the total number of local boundary coefficients.
 
int GetNumLocalCoeffs () const
 Returns the total number of local coefficients.
 
int GetNumGlobalCoeffs () const
 Returns the total number of global coefficients.
 
bool GetSingularSystem () const
 Retrieves if the system is singular (true) or not (false)
 
void GlobalToLocalBnd (const NekVector< NekDouble > &global, NekVector< NekDouble > &loc, int offset) const
 
void GlobalToLocalBnd (const NekVector< NekDouble > &global, NekVector< NekDouble > &loc) const
 
void GlobalToLocalBnd (const Array< OneD, const NekDouble > &global, Array< OneD, NekDouble > &loc, int offset) const
 
void GlobalToLocalBnd (const Array< OneD, const NekDouble > &global, Array< OneD, NekDouble > &loc) const
 
void LocalBndToGlobal (const Array< OneD, const NekDouble > &loc, Array< OneD, NekDouble > &global, int offset, bool UseComm=true) const
 
void LocalBndToGlobal (const Array< OneD, const NekDouble > &loc, Array< OneD, NekDouble > &global, bool UseComm=true) const
 
void LocalToLocalBnd (const Array< OneD, const NekDouble > &local, Array< OneD, NekDouble > &locbnd) const
 
void LocalToLocalInt (const Array< OneD, const NekDouble > &local, Array< OneD, NekDouble > &locint) const
 
void LocalBndToLocal (const Array< OneD, const NekDouble > &locbnd, Array< OneD, NekDouble > &local) const
 
void LocalIntToLocal (const Array< OneD, const NekDouble > &locbnd, Array< OneD, NekDouble > &local) const
 
void AssembleBnd (const NekVector< NekDouble > &loc, NekVector< NekDouble > &global, int offset) const
 
void AssembleBnd (const NekVector< NekDouble > &loc, NekVector< NekDouble > &global) const
 
void AssembleBnd (const Array< OneD, const NekDouble > &loc, Array< OneD, NekDouble > &global, int offset) const
 
void AssembleBnd (const Array< OneD, const NekDouble > &loc, Array< OneD, NekDouble > &global) const
 
void UniversalAssembleBnd (Array< OneD, NekDouble > &pGlobal) const
 
void UniversalAssembleBnd (NekVector< NekDouble > &pGlobal) const
 
void UniversalAssembleBnd (Array< OneD, NekDouble > &pGlobal, int offset) const
 
int GetFullSystemBandWidth () const
 
int GetNumNonDirVertexModes () const
 
int GetNumNonDirEdgeModes () const
 
int GetNumNonDirFaceModes () const
 
int GetNumDirEdges () const
 
int GetNumDirFaces () const
 
int GetNumNonDirEdges () const
 
int GetNumNonDirFaces () const
 
void PrintStats (std::ostream &out, std::string variable, bool printHeader=true) const
 
const Array< OneD, const int > & GetExtraDirEdges ()
 
std::shared_ptr< AssemblyMapLinearSpaceMap (const ExpList &locexp, GlobalSysSolnType solnType)
 
int GetBndSystemBandWidth () const
 Returns the bandwidth of the boundary system.
 
int GetStaticCondLevel () const
 Returns the level of static condensation for this map.
 
int GetNumPatches () const
 Returns the number of patches in this static condensation level.
 
const Array< OneD, const unsigned int > & GetNumLocalBndCoeffsPerPatch ()
 Returns the number of local boundary coefficients in each patch.
 
const Array< OneD, const unsigned int > & GetNumLocalIntCoeffsPerPatch ()
 Returns the number of local interior coefficients in each patch.
 
const AssemblyMapSharedPtr GetNextLevelLocalToGlobalMap () const
 Returns the local to global mapping for the next level in the multi-level static condensation.
 
void SetNextLevelLocalToGlobalMap (AssemblyMapSharedPtr pNextLevelLocalToGlobalMap)
 
const PatchMapSharedPtrGetPatchMapFromPrevLevel (void) const
 Returns the patch map from the previous level of the multi-level static condensation.
 
bool AtLastLevel () const
 Returns true if this is the last level in the multi-level static condensation.
 
GlobalSysSolnType GetGlobalSysSolnType () const
 Returns the method of solving global systems.
 
std::string GetPreconType () const
 
bool IsAbsoluteTolerance () const
 
int GetSuccessiveRHS () const
 
std::string GetLinSysIterSolver () const
 
int GetLowestStaticCondLevel () const
 
void PatchLocalToGlobal (const Array< OneD, const NekDouble > &loc, Array< OneD, NekDouble > &global) const
 
void PatchGlobalToLocal (const Array< OneD, const NekDouble > &global, Array< OneD, NekDouble > &loc) const
 
void PatchAssemble (const Array< OneD, const NekDouble > &loc, Array< OneD, NekDouble > &global) const
 

Protected Member Functions

int CreateGraph (const ExpList &locExp, const BndCondExp &bndCondExp, const Array< OneD, const BndCond > &bndConditions, const bool checkIfSystemSingular, const PeriodicMap &periodicVerts, const PeriodicMap &periodicEdges, const PeriodicMap &periodicFaces, DofGraph &graph, BottomUpSubStructuredGraphSharedPtr &bottomUpGraph, std::set< int > &extraDirVerts, std::set< int > &extraDirEdges, int &firstNonDirGraphVertId, int &nExtraDirichlet, int mdswitch=1)
 
void SetUpUniversalC0ContMap (const ExpList &locExp, const PeriodicMap &perVerts=NullPeriodicMap, const PeriodicMap &perEdges=NullPeriodicMap, const PeriodicMap &perFaces=NullPeriodicMap)
 
void CalculateFullSystemBandWidth ()
 Calculate the bandwith of the full matrix system.
 
int v_GetLocalToGlobalMap (const int i) const override
 
int v_GetGlobalToUniversalMap (const int i) const override
 
int v_GetGlobalToUniversalMapUnique (const int i) const override
 
const Array< OneD, const int > & v_GetLocalToGlobalMap () override
 
const Array< OneD, const int > & v_GetGlobalToUniversalMap () override
 
const Array< OneD, const int > & v_GetGlobalToUniversalMapUnique () override
 
NekDouble v_GetLocalToGlobalSign (const int i) const override
 
const Array< OneD, NekDouble > & v_GetLocalToGlobalSign () const override
 
void v_LocalToGlobal (const Array< OneD, const NekDouble > &loc, Array< OneD, NekDouble > &global, bool useComm) const override
 
void v_GlobalToLocal (const Array< OneD, const NekDouble > &global, Array< OneD, NekDouble > &loc) const override
 
void v_GlobalToLocal (const NekVector< NekDouble > &global, NekVector< NekDouble > &loc) const override
 
void v_Assemble (const Array< OneD, const NekDouble > &loc, Array< OneD, NekDouble > &global) const override
 
void v_Assemble (const NekVector< NekDouble > &loc, NekVector< NekDouble > &global) const override
 
void v_UniversalAssemble (Array< OneD, NekDouble > &pGlobal) const override
 
void v_UniversalAssemble (Array< OneD, NekDouble > &pGlobal, int offset) const override
 
int v_GetFullSystemBandWidth () const override
 
int v_GetNumNonDirVertexModes () const override
 
int v_GetNumNonDirEdgeModes () const override
 
int v_GetNumNonDirFaceModes () const override
 
int v_GetNumDirEdges () const override
 
int v_GetNumDirFaces () const override
 
int v_GetNumNonDirEdges () const override
 
int v_GetNumNonDirFaces () const override
 
const Array< OneD, const int > & v_GetExtraDirEdges () override
 
AssemblyMapSharedPtr v_LinearSpaceMap (const ExpList &locexp, GlobalSysSolnType solnType) override
 Construct an AssemblyMapCG object which corresponds to the linear space of the current object.
 
- Protected Member Functions inherited from Nektar::MultiRegions::AssemblyMap
void CalculateBndSystemBandWidth ()
 Calculates the bandwidth of the boundary system.
 
void GlobalToLocalBndWithoutSign (const Array< OneD, const NekDouble > &global, Array< OneD, NekDouble > &loc)
 

Protected Attributes

Array< OneD, int > m_localToGlobalMap
 Integer map of local coeffs to global space.
 
Array< OneD, NekDoublem_localToGlobalSign
 Integer sign of local coeffs to global space.
 
int m_fullSystemBandWidth
 Bandwith of the full matrix system (no static condensation).
 
Array< OneD, int > m_globalToUniversalMap
 Integer map of process coeffs to universal space.
 
Array< OneD, int > m_globalToUniversalMapUnique
 Integer map of unique process coeffs to universal space (signed)
 
int m_numNonDirVertexModes
 Number of non Dirichlet vertex modes.
 
int m_numNonDirEdgeModes
 Number of non Dirichlet edge modes.
 
int m_numNonDirFaceModes
 Number of non Dirichlet face modes.
 
int m_numDirEdges
 Number of Dirichlet edges.
 
int m_numDirFaces
 Number of Dirichlet faces.
 
int m_numNonDirEdges
 Number of Dirichlet edges.
 
int m_numNonDirFaces
 Number of Dirichlet faces.
 
int m_numLocalBndCondCoeffs
 Number of local boundary condition coefficients.
 
Array< OneD, int > m_extraDirEdges
 Extra dirichlet edges in parallel.
 
int m_numLocDirBndCondDofs
 Number of local boundary condition degrees of freedom.
 
int m_maxStaticCondLevel
 Maximum static condensation level.
 
std::set< ExtraDirDofm_copyLocalDirDofs
 Set indicating degrees of freedom which are Dirichlet but whose value is stored on another processor.
 
std::set< int > m_parallelDirBndSign
 Set indicating the local coeffs just touching parallel dirichlet boundary that have a sign change.
 
- Protected Attributes inherited from Nektar::MultiRegions::AssemblyMap
LibUtilities::SessionReaderSharedPtr m_session
 Session object.
 
LibUtilities::CommSharedPtr m_comm
 Communicator.
 
std::string m_variable
 Variable string identifier.
 
size_t m_hash
 Hash for map.
 
int m_numLocalBndCoeffs
 Number of local boundary coefficients.
 
int m_numGlobalBndCoeffs
 Total number of global boundary coefficients.
 
int m_numLocalDirBndCoeffs
 Number of Local Dirichlet Boundary Coefficients.
 
int m_numGlobalDirBndCoeffs
 Number of Global Dirichlet Boundary Coefficients.
 
bool m_systemSingular
 Flag indicating if the system is singular or not.
 
int m_numLocalCoeffs
 Total number of local coefficients.
 
int m_numGlobalCoeffs
 Total number of global coefficients.
 
bool m_signChange
 Flag indicating if modes require sign reversal.
 
Array< OneD, int > m_localToGlobalBndMap
 Integer map of local coeffs to global Boundary Dofs.
 
Array< OneD, NekDoublem_localToGlobalBndSign
 Integer sign of local boundary coeffs to global space.
 
Array< OneD, int > m_localToLocalBndMap
 Integer map of local boundary coeffs to local boundary system numbering.
 
Array< OneD, int > m_localToLocalIntMap
 Integer map of local boundary coeffs to local interior system numbering.
 
Array< OneD, int > m_bndCondCoeffsToLocalCoeffsMap
 Integer map of bnd cond coeffs to local coefficients.
 
Array< OneD, NekDoublem_bndCondCoeffsToLocalCoeffsSign
 Integer map of sign of bnd cond coeffs to local coefficients.
 
Array< OneD, int > m_bndCondCoeffsToLocalTraceMap
 Integer map of bnd cond coeff to local trace coeff.
 
Array< OneD, int > m_bndCondIDToGlobalTraceID
 Integer map of bnd cond trace number to global trace number.
 
Array< OneD, int > m_perbndCondIDToGlobalTraceID
 Integer map of rotational periodic bnd cond trace number to global trace number.
 
Array< OneD, int > m_globalToUniversalBndMap
 Integer map of process coeffs to universal space.
 
Array< OneD, int > m_globalToUniversalBndMapUnique
 Integer map of unique process coeffs to universal space (signed)
 
GlobalSysSolnType m_solnType
 The solution type of the global system.
 
int m_bndSystemBandWidth
 The bandwith of the global bnd system.
 
std::string m_preconType
 Type type of preconditioner to use in iterative solver.
 
NekDouble m_iterativeTolerance
 Tolerance for iterative solver.
 
bool m_isAbsoluteTolerance
 
int m_successiveRHS
 sucessive RHS for iterative solver
 
std::string m_linSysIterSolver
 Iterative solver: Conjugate Gradient, GMRES.
 
Gs::gs_datam_gsh
 
Gs::gs_datam_bndGsh
 
Gs::gs_datam_dirBndGsh
 gs gather communication to impose Dirhichlet BCs.
 
int m_staticCondLevel
 The level of recursion in the case of multi-level static condensation.
 
int m_numPatches
 The number of patches (~elements) in the current level.
 
Array< OneD, unsigned int > m_numLocalBndCoeffsPerPatch
 The number of bnd dofs per patch.
 
Array< OneD, unsigned int > m_numLocalIntCoeffsPerPatch
 The number of int dofs per patch.
 
AssemblyMapSharedPtr m_nextLevelLocalToGlobalMap
 Map from the patches of the previous level to the patches of the current level.
 
int m_lowestStaticCondLevel
 Lowest static condensation level.
 

Private Types

typedef Array< OneD, const ExpListSharedPtrBndCondExp
 
typedef Array< OneD, const SpatialDomains::BoundaryConditionShPtrBndCond
 

Detailed Description

Constructs mappings for the C0 scalar continuous Galerkin formulation.

Mappings are created for three possible global solution types:

These mappings are used by GlobalLinSys to generate the global system.

Definition at line 65 of file AssemblyMapCG.h.

Member Typedef Documentation

◆ BndCond

Definition at line 68 of file AssemblyMapCG.h.

◆ BndCondExp

Definition at line 67 of file AssemblyMapCG.h.

Constructor & Destructor Documentation

◆ AssemblyMapCG() [1/2]

Nektar::MultiRegions::AssemblyMapCG::AssemblyMapCG ( const LibUtilities::SessionReaderSharedPtr pSession,
const LibUtilities::CommSharedPtr comm,
const std::string  variable = "DefaultVar" 
)

Default constructor.

Definition at line 69 of file AssemblyMapCG.cpp.

72 : AssemblyMap(pSession, comm, variable)
73{
74 pSession->LoadParameter("MaxStaticCondLevel", m_maxStaticCondLevel, 100);
75}
int m_maxStaticCondLevel
Maximum static condensation level.
AssemblyMap()
Default constructor.

References m_maxStaticCondLevel.

◆ AssemblyMapCG() [2/2]

Nektar::MultiRegions::AssemblyMapCG::AssemblyMapCG ( const LibUtilities::SessionReaderSharedPtr pSession,
const int  numLocalCoeffs,
const ExpList locExp,
const BndCondExp bndCondExp = NullExpListSharedPtrArray,
const BndCond bndConditions = SpatialDomains::NullBoundaryConditionShPtrArray,
const bool  checkIfSingular = false,
const std::string  variable = "defaultVar",
const PeriodicMap periodicVerts = NullPeriodicMap,
const PeriodicMap periodicEdges = NullPeriodicMap,
const PeriodicMap periodicFaces = NullPeriodicMap 
)

General constructor for expansions of all dimensions without boundary conditions.

STEP 6: Now, all ingredients are ready to set up the actual local to global mapping.

The remainder of the map consists of the element-interior degrees of freedom. This leads to the block-diagonal submatrix as each element-interior mode is globally orthogonal to modes in all other elements.

Definition at line 1312 of file AssemblyMapCG.cpp.

1319 : AssemblyMap(pSession, locExp.GetComm(), variable)
1320{
1321 int i, j, k;
1322 int p, q, numModes0, numModes1;
1323 int cnt = 0;
1324 int meshVertId, meshEdgeId, meshEdgeId2, meshFaceId, meshFaceId2;
1325 int globalId;
1326 int nEdgeInteriorCoeffs;
1327 int firstNonDirGraphVertId;
1328 LibUtilities::CommSharedPtr vRowComm = m_comm->GetRowComm();
1330 StdRegions::Orientation edgeOrient;
1331 StdRegions::Orientation faceOrient;
1332 Array<OneD, unsigned int> edgeInteriorMap;
1333 Array<OneD, int> edgeInteriorSign;
1334 Array<OneD, unsigned int> faceInteriorMap;
1335 Array<OneD, int> faceInteriorSign;
1336
1337 const LocalRegions::ExpansionVector &locExpVector = *(locExp.GetExp());
1338
1339 bool verbose = m_session->DefinesCmdLineArgument("verbose");
1340
1341 m_signChange = false;
1342
1343 // Stores vertex, edge and face reordered vertices.
1344 DofGraph graph(3);
1345 DofGraph dofs(3);
1346 vector<map<int, int>> faceModes(2);
1347 map<int, LibUtilities::ShapeType> faceType;
1348
1349 set<int> extraDirVerts, extraDirEdges;
1351
1352 // Construct list of number of degrees of freedom for each vertex,
1353 // edge and face.
1354 for (i = 0; i < locExpVector.size(); ++i)
1355 {
1356 exp = locExpVector[i];
1357
1358 for (j = 0; j < exp->GetNverts(); ++j)
1359 {
1360 dofs[0][exp->GetGeom()->GetVid(j)] = 1;
1361 }
1362
1363 for (j = 0; j < exp->GetGeom()->GetNumEdges(); ++j)
1364 {
1365 int nEdgeInt;
1366 if (exp->GetGeom()->GetNumFaces())
1367 {
1368 nEdgeInt =
1369 exp->as<LocalRegions::Expansion3D>()->GetEdgeNcoeffs(j) - 2;
1370 }
1371 else
1372 {
1373 nEdgeInt = exp->GetTraceNcoeffs(j) - 2;
1374 }
1375
1376 if (dofs[1].count(exp->GetGeom()->GetEid(j)) > 0)
1377 {
1378 if (dofs[1][exp->GetGeom()->GetEid(j)] != nEdgeInt)
1379 {
1380 ASSERTL0(
1381 (exp->GetBasisType(0) == LibUtilities::eModified_A) ||
1382 (exp->GetBasisType(1) ==
1384 (exp->GetBasisType(2) ==
1386 (exp->GetBasisType(2) ==
1388 "CG with variable order only available with "
1389 "modal expansion");
1390 }
1391 dofs[1][exp->GetGeom()->GetEid(j)] =
1392 min(dofs[1][exp->GetGeom()->GetEid(j)], nEdgeInt);
1393 }
1394 else
1395 {
1396 dofs[1][exp->GetGeom()->GetEid(j)] = nEdgeInt;
1397 }
1398 }
1399
1400 for (j = 0; j < exp->GetGeom()->GetNumFaces(); ++j)
1401 {
1402 faceOrient = exp->GetGeom()->GetForient(j);
1403 meshFaceId = exp->GetGeom()->GetFid(j);
1404 exp->GetTraceNumModes(j, numModes0, numModes1, faceOrient);
1405
1406 if (faceModes[0].count(meshFaceId) > 0)
1407 {
1408 faceModes[0][meshFaceId] =
1409 min(faceModes[0][meshFaceId], numModes0);
1410
1411 faceModes[1][meshFaceId] =
1412 min(faceModes[1][meshFaceId], numModes1);
1413 }
1414 else
1415 {
1416 faceModes[0][meshFaceId] = numModes0;
1417 faceModes[1][meshFaceId] = numModes1;
1418
1419 // Get shape of this face
1420 faceType[meshFaceId] =
1421 exp->GetGeom()->GetFace(j)->GetShapeType();
1422 }
1423 }
1424 }
1425
1426 // Add non-local periodic dofs to the map
1427 for (auto &pIt : periodicEdges)
1428 {
1429 for (i = 0; i < pIt.second.size(); ++i)
1430 {
1431 meshEdgeId2 = pIt.second[i].id;
1432 if (dofs[1].count(meshEdgeId2) == 0)
1433 {
1434 dofs[1][meshEdgeId2] = 1e6;
1435 }
1436 }
1437 }
1438 for (auto &pIt : periodicFaces)
1439 {
1440 for (i = 0; i < pIt.second.size(); ++i)
1441 {
1442 meshFaceId2 = pIt.second[i].id;
1443 if (faceModes[0].count(meshFaceId2) == 0)
1444 {
1445 faceModes[0][meshFaceId2] = 1e6;
1446 faceModes[1][meshFaceId2] = 1e6;
1447 }
1448 }
1449 }
1450
1451 // Now use information from all partitions to determine the correct
1452 // size
1453
1454 // edges
1455 Array<OneD, long> edgeId(dofs[1].size());
1456 Array<OneD, NekDouble> edgeDof(dofs[1].size());
1457 i = 0;
1458 for (auto &dofIt : dofs[1])
1459 {
1460 edgeId[i] = dofIt.first + 1;
1461 edgeDof[i++] = (NekDouble)dofIt.second;
1462 }
1463 Gs::gs_data *tmp = Gs::Init(edgeId, vRowComm, verbose);
1464 Gs::Gather(edgeDof, Gs::gs_min, tmp);
1465 Gs::Finalise(tmp);
1466 for (i = 0; i < dofs[1].size(); i++)
1467 {
1468 dofs[1][edgeId[i] - 1] = (int)(edgeDof[i] + 0.5);
1469 }
1470 // Periodic edges
1471 for (auto &pIt : periodicEdges)
1472 {
1473 meshEdgeId = pIt.first;
1474 for (i = 0; i < pIt.second.size(); ++i)
1475 {
1476 meshEdgeId2 = pIt.second[i].id;
1477 if (dofs[1][meshEdgeId2] < dofs[1][meshEdgeId])
1478 {
1479 dofs[1][meshEdgeId] = dofs[1][meshEdgeId2];
1480 }
1481 }
1482 }
1483 // faces
1484 Array<OneD, long> faceId(faceModes[0].size());
1485 Array<OneD, NekDouble> faceP(faceModes[0].size());
1486 Array<OneD, NekDouble> faceQ(faceModes[0].size());
1487
1488 i = 0;
1489 for (auto dofIt = faceModes[0].begin(), dofIt2 = faceModes[1].begin();
1490 dofIt != faceModes[0].end(); dofIt++, dofIt2++, i++)
1491 {
1492 faceId[i] = dofIt->first + 1;
1493 faceP[i] = (NekDouble)dofIt->second;
1494 faceQ[i] = (NekDouble)dofIt2->second;
1495 }
1496 Gs::gs_data *tmp2 = Gs::Init(faceId, vRowComm, verbose);
1497 Gs::Gather(faceP, Gs::gs_min, tmp2);
1498 Gs::Gather(faceQ, Gs::gs_min, tmp2);
1499 Gs::Finalise(tmp2);
1500 for (i = 0; i < faceModes[0].size(); i++)
1501 {
1502 faceModes[0][faceId[i] - 1] = (int)(faceP[i] + 0.5);
1503 faceModes[1][faceId[i] - 1] = (int)(faceQ[i] + 0.5);
1504 }
1505 // Periodic faces
1506 for (auto &pIt : periodicFaces)
1507 {
1508 meshFaceId = pIt.first;
1509 for (i = 0; i < pIt.second.size(); ++i)
1510 {
1511 meshFaceId2 = pIt.second[i].id;
1512 if (faceModes[0][meshFaceId2] < faceModes[0][meshFaceId])
1513 {
1514 faceModes[0][meshFaceId] = faceModes[0][meshFaceId2];
1515 }
1516 if (faceModes[1][meshFaceId2] < faceModes[1][meshFaceId])
1517 {
1518 faceModes[1][meshFaceId] = faceModes[1][meshFaceId2];
1519 }
1520 }
1521 }
1522 // Calculate number of dof in each face
1523 int P, Q;
1524 for (i = 0; i < faceModes[0].size(); i++)
1525 {
1526 P = faceModes[0][faceId[i] - 1];
1527 Q = faceModes[1][faceId[i] - 1];
1528 if (faceType[faceId[i] - 1] == LibUtilities::eQuadrilateral)
1529 {
1530 // Quad face
1531 dofs[2][faceId[i] - 1] =
1534 }
1535 else
1536 {
1537 // Tri face
1538 dofs[2][faceId[i] - 1] =
1541 }
1542 }
1543
1544 Array<OneD, const BndCond> bndCondVec(1, bndConditions);
1545
1546 // Note that nExtraDirichlet is not used in the logic below; it just
1547 // needs to be set so that the coupled solver in
1548 // IncNavierStokesSolver can work.
1549 int nExtraDirichlet;
1550 int mdswitch;
1551 m_session->LoadParameter("MDSwitch", mdswitch, 10);
1552
1553 int nGraphVerts = CreateGraph(
1554 locExp, bndCondExp, bndCondVec, checkIfSystemSingular, periodicVerts,
1555 periodicEdges, periodicFaces, graph, bottomUpGraph, extraDirVerts,
1556 extraDirEdges, firstNonDirGraphVertId, nExtraDirichlet, mdswitch);
1557
1558 /*
1559 * Set up an array which contains the offset information of the
1560 * different graph vertices.
1561 *
1562 * This basically means to identify to how many global degrees of
1563 * freedom the individual graph vertices correspond. Obviously,
1564 * the graph vertices corresponding to the mesh-vertices account
1565 * for a single global DOF. However, the graph vertices
1566 * corresponding to the element edges correspond to N-2 global DOF
1567 * where N is equal to the number of boundary modes on this edge.
1568 */
1569 Array<OneD, int> graphVertOffset(
1570 graph[0].size() + graph[1].size() + graph[2].size() + 1, 0);
1571
1572 graphVertOffset[0] = 0;
1573
1574 for (i = 0; i < locExpVector.size(); ++i)
1575 {
1576 exp = locExpVector[i];
1577
1578 for (j = 0; j < exp->GetNverts(); ++j)
1579 {
1580 meshVertId = exp->GetGeom()->GetVid(j);
1581 graphVertOffset[graph[0][meshVertId] + 1] = 1;
1582 }
1583
1584 for (j = 0; j < exp->GetGeom()->GetNumEdges(); ++j)
1585 {
1586 if (exp->GetGeom()->GetNumFaces()) // 3D version
1587 {
1588 nEdgeInteriorCoeffs =
1589 exp->as<LocalRegions::Expansion3D>()->GetEdgeNcoeffs(j) - 2;
1590 }
1591 else
1592 {
1593 nEdgeInteriorCoeffs = exp->GetTraceNcoeffs(j) - 2;
1594 }
1595 meshEdgeId = exp->GetGeom()->GetEid(j);
1596 graphVertOffset[graph[1][meshEdgeId] + 1] = dofs[1][meshEdgeId];
1597
1598 // Need a sign vector for modal expansions if nEdgeCoeffs
1599 // >=3 (not 4 because of variable order case)
1600 if (nEdgeInteriorCoeffs &&
1601 (exp->GetBasisType(0) == LibUtilities::eModified_A))
1602 {
1603 m_signChange = true;
1604 }
1605 }
1606
1607 for (j = 0; j < exp->GetGeom()->GetNumFaces(); ++j)
1608 {
1609 meshFaceId = exp->GetGeom()->GetFid(j);
1610 graphVertOffset[graph[2][meshFaceId] + 1] = dofs[2][meshFaceId];
1611 }
1612 }
1613
1614 for (i = 1; i < graphVertOffset.size(); i++)
1615 {
1616 graphVertOffset[i] += graphVertOffset[i - 1];
1617 }
1618
1619 // Allocate the proper amount of space for the class-data
1620 m_numLocalCoeffs = numLocalCoeffs;
1621 m_numGlobalDirBndCoeffs = graphVertOffset[firstNonDirGraphVertId];
1622 m_localToGlobalMap = Array<OneD, int>(m_numLocalCoeffs, -1);
1623 m_localToGlobalBndMap = Array<OneD, int>(m_numLocalBndCoeffs, -1);
1624 m_localToLocalBndMap = Array<OneD, int>(m_numLocalBndCoeffs, -1);
1626 Array<OneD, int>(m_numLocalCoeffs - m_numLocalBndCoeffs, -1);
1628 Array<OneD, int>(m_numLocalBndCondCoeffs, -1);
1629
1630 // If required, set up the sign-vector
1631 if (m_signChange)
1632 {
1633 m_localToGlobalSign = Array<OneD, NekDouble>(m_numLocalCoeffs, 1.0);
1635 Array<OneD, NekDouble>(m_numLocalBndCoeffs, 1.0);
1637 Array<OneD, NekDouble>(m_numLocalBndCondCoeffs, 1.0);
1638 }
1639
1641 m_numPatches = locExpVector.size();
1642 m_numLocalBndCoeffsPerPatch = Array<OneD, unsigned int>(m_numPatches);
1643 m_numLocalIntCoeffsPerPatch = Array<OneD, unsigned int>(m_numPatches);
1644 for (i = 0; i < m_numPatches; ++i)
1645 {
1647 (unsigned int)locExpVector[i]->NumBndryCoeffs();
1649 (unsigned int)locExpVector[i]->GetNcoeffs() -
1650 locExpVector[i]->NumBndryCoeffs();
1651 }
1652
1653 /**
1654 * STEP 6: Now, all ingredients are ready to set up the actual
1655 * local to global mapping.
1656 *
1657 * The remainder of the map consists of the element-interior
1658 * degrees of freedom. This leads to the block-diagonal submatrix
1659 * as each element-interior mode is globally orthogonal to modes
1660 * in all other elements.
1661 */
1662 cnt = 0;
1663
1664 // Loop over all the elements in the domain
1665 int cntbdry = 0;
1666 int cntint = 0;
1667 for (i = 0; i < locExpVector.size(); ++i)
1668 {
1669 exp = locExpVector[i];
1670 cnt = locExp.GetCoeff_Offset(i);
1671
1672 int nbdry = exp->NumBndryCoeffs();
1673 int nint = exp->GetNcoeffs() - nbdry;
1674
1675 Array<OneD, unsigned int> bmap(nbdry);
1676 Array<OneD, unsigned int> imap(nint);
1677
1678 exp->GetBoundaryMap(bmap);
1679 exp->GetInteriorMap(imap);
1680
1681 for (j = 0; j < nbdry; ++j)
1682 {
1683 m_localToLocalBndMap[cntbdry++] = cnt + bmap[j];
1684 }
1685
1686 for (j = 0; j < nint; ++j)
1687 {
1688 m_localToLocalIntMap[cntint++] = cnt + imap[j];
1689 }
1690
1691 for (j = 0; j < exp->GetNverts(); ++j)
1692 {
1693 meshVertId = exp->GetGeom()->GetVid(j);
1694
1695 // Set the global DOF for vertex j of element i
1696 m_localToGlobalMap[cnt + exp->GetVertexMap(j)] =
1697 graphVertOffset[graph[0][meshVertId]];
1698 }
1699
1700 for (j = 0; j < exp->GetGeom()->GetNumEdges(); ++j)
1701 {
1702 if (exp->GetGeom()->GetNumFaces())
1703 {
1704 nEdgeInteriorCoeffs =
1705 exp->as<LocalRegions::Expansion3D>()->GetEdgeNcoeffs(j) - 2;
1706 }
1707 else
1708 {
1709 nEdgeInteriorCoeffs = exp->GetTraceNcoeffs(j) - 2;
1710 }
1711 edgeOrient = exp->GetGeom()->GetEorient(j);
1712 meshEdgeId = exp->GetGeom()->GetEid(j);
1713
1714 auto pIt = periodicEdges.find(meshEdgeId);
1715
1716 // See if this edge is periodic. If it is, then we map all
1717 // edges to the one with lowest ID, and align all
1718 // coefficients to this edge orientation.
1719 if (pIt != periodicEdges.end())
1720 {
1721 pair<int, StdRegions::Orientation> idOrient =
1722 DeterminePeriodicEdgeOrientId(meshEdgeId, edgeOrient,
1723 pIt->second);
1724 edgeOrient = idOrient.second;
1725 }
1726
1727 if (exp->GetGeom()->GetNumFaces())
1728 {
1729 exp->as<LocalRegions::Expansion3D>()
1730 ->GetEdgeInteriorToElementMap(j, edgeInteriorMap,
1731 edgeInteriorSign, edgeOrient);
1732 }
1733 else
1734 {
1735 exp->GetTraceInteriorToElementMap(j, edgeInteriorMap,
1736 edgeInteriorSign, edgeOrient);
1737 }
1738
1739 // Set the global DOF's for the interior modes of edge j
1740 for (k = 0; k < dofs[1][meshEdgeId]; ++k)
1741 {
1742 m_localToGlobalMap[cnt + edgeInteriorMap[k]] =
1743 graphVertOffset[graph[1][meshEdgeId]] + k;
1744 }
1745 for (k = dofs[1][meshEdgeId]; k < nEdgeInteriorCoeffs; ++k)
1746 {
1747 m_localToGlobalMap[cnt + edgeInteriorMap[k]] = 0;
1748 }
1749
1750 // Fill the sign vector if required
1751 if (m_signChange)
1752 {
1753 for (k = 0; k < dofs[1][meshEdgeId]; ++k)
1754 {
1755 m_localToGlobalSign[cnt + edgeInteriorMap[k]] =
1756 (NekDouble)edgeInteriorSign[k];
1757 }
1758 for (k = dofs[1][meshEdgeId]; k < nEdgeInteriorCoeffs; ++k)
1759 {
1760 m_localToGlobalSign[cnt + edgeInteriorMap[k]] = 0.0;
1761 }
1762 }
1763 }
1764
1765 for (j = 0; j < exp->GetGeom()->GetNumFaces(); ++j)
1766 {
1767 faceOrient = exp->GetGeom()->GetForient(j);
1768 meshFaceId = exp->GetGeom()->GetFid(j);
1769
1770 auto pIt = periodicFaces.find(meshFaceId);
1771
1772 if (pIt != periodicFaces.end() &&
1773 meshFaceId == min(meshFaceId, pIt->second[0].id))
1774 {
1775 faceOrient = DeterminePeriodicFaceOrient(faceOrient,
1776 pIt->second[0].orient);
1777 }
1778
1779 exp->GetTraceInteriorToElementMap(j, faceInteriorMap,
1780 faceInteriorSign, faceOrient);
1781
1782 // Set the global DOF's for the interior modes of face j
1783 exp->GetTraceNumModes(j, numModes0, numModes1, faceOrient);
1784 switch (faceType[meshFaceId])
1785 {
1787 {
1788 int kLoc = 0;
1789 k = 0;
1790 for (q = 2; q < numModes1; q++)
1791 {
1792 for (p = 2; p < numModes0; p++)
1793 {
1794 if ((p < faceModes[0][meshFaceId]) &&
1795 (q < faceModes[1][meshFaceId]))
1796 {
1797 m_localToGlobalMap[cnt +
1798 faceInteriorMap[kLoc]] =
1799 graphVertOffset[graph[2][meshFaceId]] + k;
1800 if (m_signChange)
1801 {
1803 faceInteriorMap[kLoc]] =
1804 (NekDouble)faceInteriorSign[kLoc];
1805 }
1806 k++;
1807 }
1808 else
1809 {
1810 m_localToGlobalMap[cnt +
1811 faceInteriorMap[kLoc]] = 0;
1812 if (m_signChange)
1813 {
1815 faceInteriorMap[kLoc]] =
1816 0.0;
1817 }
1818 }
1819 kLoc++;
1820 }
1821 }
1822 }
1823 break;
1825 {
1826 int kLoc = 0;
1827 k = 0;
1828 for (p = 2; p < numModes0; p++)
1829 {
1830 for (q = 1; q < numModes1 - p; q++)
1831 {
1832 if ((p < faceModes[0][meshFaceId]) &&
1833 (p + q < faceModes[1][meshFaceId]))
1834 {
1835 m_localToGlobalMap[cnt +
1836 faceInteriorMap[kLoc]] =
1837 graphVertOffset[graph[2][meshFaceId]] + k;
1838 if (m_signChange)
1839 {
1841 faceInteriorMap[kLoc]] =
1842 (NekDouble)faceInteriorSign[kLoc];
1843 }
1844 k++;
1845 }
1846 else
1847 {
1848 m_localToGlobalMap[cnt +
1849 faceInteriorMap[kLoc]] = 0;
1850 if (m_signChange)
1851 {
1853 faceInteriorMap[kLoc]] =
1854 0.0;
1855 }
1856 }
1857 kLoc++;
1858 }
1859 }
1860 }
1861 break;
1862 default:
1863 ASSERTL0(false, "Shape not recognised");
1864 break;
1865 }
1866 }
1867 }
1868
1869 // Set up the mapping for the boundary conditions
1870 // Set up boundary mapping
1871 map<int, pair<int, int>> traceToElmtTraceMap;
1872 int id;
1873
1874 for (cnt = i = 0; i < locExpVector.size(); ++i)
1875 {
1876 exp = locExpVector[i];
1877
1878 for (j = 0; j < exp->GetNtraces(); ++j)
1879 {
1880 id = exp->GetGeom()->GetTid(j);
1881
1882 traceToElmtTraceMap[id] = pair<int, int>(i, j);
1883 }
1884 }
1885
1886 Array<OneD, unsigned int> maparray;
1887 Array<OneD, int> signarray;
1888 map<int, pair<int, NekDouble>> GloDirBndCoeffToLocalCoeff;
1889 set<int> CoeffOnDirTrace;
1890
1891 cnt = 0;
1892 int offset = 0;
1893 for (i = 0; i < bndCondExp.size(); i++)
1894 {
1895 set<int> foundExtraVerts, foundExtraEdges;
1896 for (j = 0; j < bndCondExp[i]->GetNumElmts(); j++)
1897 {
1898 bndExp = bndCondExp[i]->GetExp(j);
1899 cnt = offset + bndCondExp[i]->GetCoeff_Offset(j);
1900
1901 int id = bndExp->GetGeom()->GetGlobalID();
1902
1903 ASSERTL1(traceToElmtTraceMap.count(id) > 0,
1904 "Failed to find trace id");
1905
1906 int eid = traceToElmtTraceMap[id].first;
1907 int tid = traceToElmtTraceMap[id].second;
1908
1909 exp = locExpVector[eid];
1910 int dim = exp->GetShapeDimension();
1911
1912 if (dim == 1)
1913 {
1915 locExp.GetCoeff_Offset(eid) + exp->GetVertexMap(tid);
1916 }
1917 else
1918 {
1919 if (dim == 2)
1920 {
1921 exp->GetTraceToElementMap(tid, maparray, signarray,
1922 exp->GetGeom()->GetEorient(tid),
1923 bndExp->GetBasisNumModes(0));
1924 }
1925 else if (dim == 3)
1926 {
1927 exp->GetTraceToElementMap(tid, maparray, signarray,
1928 exp->GetGeom()->GetForient(tid),
1929 bndExp->GetBasisNumModes(0),
1930 bndExp->GetBasisNumModes(1));
1931 }
1932
1933 for (k = 0; k < bndExp->GetNcoeffs(); k++)
1934 {
1936 locExp.GetCoeff_Offset(eid) + maparray[k];
1937 if (m_signChange)
1938 {
1940 signarray[k];
1941 }
1942 }
1943 }
1944
1945 // we now need some information to work out how to
1946 // handle vertices and edges that are only just
1947 // touching a dirichlet boundary (and not the
1948 // whole edge/face)
1949
1950 for (k = 0; k < bndExp->GetNcoeffs(); k++)
1951 {
1952 int locid = m_bndCondCoeffsToLocalCoeffsMap[cnt + k];
1953 int gloid = m_localToGlobalMap[locid];
1954 NekDouble sign = 1.0;
1955
1956 if (m_signChange)
1957 {
1959 }
1960
1961 if (bndConditions[i]->GetBoundaryConditionType() ==
1963 {
1964 bool addid =
1965 (m_signChange && m_localToGlobalSign[locid] == 0)
1966 ? false
1967 : true;
1968
1969 // only add point if sign is +/- 1 since if zero it
1970 // belongs to a mode that is not used in variable p
1971 // expansion
1972 if (addid)
1973 {
1974 CoeffOnDirTrace.insert(locid);
1975
1976 // store the local id and sign from global id
1977 // back to local space;
1978 GloDirBndCoeffToLocalCoeff[gloid] =
1979 pair<int, NekDouble>(locid, sign);
1980 }
1981 }
1982 }
1983 }
1984 offset += bndCondExp[i]->GetNcoeffs();
1985 }
1986
1987 globalId = Vmath::Vmax(m_numLocalCoeffs, &m_localToGlobalMap[0], 1) + 1;
1988 m_numGlobalBndCoeffs = globalId;
1989
1990 // Set up a mapping list of Dirichlet Local Dofs that
1991 // arise due to one vertex or edge just touching a
1992 // Dirichlet boundary and need the value from another
1993 // local coeff that has been filled by the boundary
1994 // coeffs.
1995
1996 Array<OneD, NekDouble> gloParaDirBnd(m_numGlobalBndCoeffs, -1.0);
1997
1998 Array<OneD, unsigned int> bndmap;
1999 cnt = 0;
2000 for (i = 0; i < locExpVector.size(); ++i)
2001 {
2002 int gloid;
2003
2004 exp = locExpVector[i];
2005
2006 exp->GetBoundaryMap(bndmap);
2007
2008 for (j = 0; j < bndmap.size(); ++j)
2009 {
2010 k = cnt + bndmap[j];
2011
2012 // exclude if Dirichlet boundary already included in partition
2013 if (CoeffOnDirTrace.count(k) == 0)
2014 {
2015 gloid = m_localToGlobalMap[k];
2016
2017 if (gloid < m_numGlobalDirBndCoeffs) // point on Dir BC
2018 {
2019 if (GloDirBndCoeffToLocalCoeff.count(gloid))
2020 {
2021 int locid = GloDirBndCoeffToLocalCoeff[gloid].first;
2022 NekDouble sign = 1.0;
2023
2024 if (m_signChange)
2025 {
2026 sign = m_localToGlobalSign[locid] *
2028 }
2029
2030 ExtraDirDof DirDofs(k, locid, sign);
2031 // could make same `structure as extraDirDof
2032 m_copyLocalDirDofs.insert(DirDofs);
2033 }
2034 else // else could be on another parallel partition.
2035 {
2036 gloParaDirBnd[gloid] = gloid;
2037 }
2038 }
2039 }
2040 }
2041
2042 cnt += exp->GetNcoeffs();
2043 }
2044
2045 /*
2046 * The boundary condition mapping is generated from the same vertex
2047 * renumbering.
2048 */
2049 cnt = 0;
2050 for (i = 0; i < m_numLocalCoeffs; ++i)
2051 {
2052 if (m_localToGlobalMap[i] == -1)
2053 {
2054 m_localToGlobalMap[i] = globalId++;
2055 }
2056 else
2057 {
2058 if (m_signChange)
2059 {
2061 }
2063 }
2064 }
2065
2066 m_numGlobalCoeffs = globalId;
2067
2068 SetUpUniversalC0ContMap(locExp, periodicVerts, periodicEdges,
2069 periodicFaces);
2070
2071 // Now that universal map is setup reset gloParaDirBnd to
2072 // 0 if no point communicated or universal value of not
2073 // equal to -1.0
2074 for (i = 0; i < m_numGlobalBndCoeffs; ++i)
2075 {
2076 int gloid = gloParaDirBnd[i];
2077 if (gloid == -1)
2078 {
2079 gloParaDirBnd[i] = 0.0;
2080 }
2081 else
2082 {
2083 gloParaDirBnd[i] = m_globalToUniversalMap[gloid];
2084 }
2085 }
2086
2087 // Use parallel boundary communication to set parallel
2088 // dirichlet values on all processors Needs to be after
2089 // SetupUuniversialC0ContMap
2090 Gs::Gather(gloParaDirBnd, Gs::gs_max, m_bndGsh);
2091
2092 // copy global ids back to local values in partition to
2093 // initialise gs communicator.
2094 Array<OneD, long> paraDirBnd(m_numLocalCoeffs);
2095 for (i = 0; i < numLocalCoeffs; ++i)
2096 {
2097 paraDirBnd[i] = 0.0;
2098
2099 int id = m_localToGlobalMap[i];
2100
2101 if (id >= m_numGlobalDirBndCoeffs)
2102 {
2103 continue;
2104 }
2105
2106 paraDirBnd[i] = gloParaDirBnd[id];
2107
2108 if (gloParaDirBnd[id] > 0.0)
2109 {
2110 // gather any sign changes due to edge modes
2111 if (m_signChange)
2112 {
2113 if (m_localToGlobalSign[i] < 0)
2114 {
2115 m_parallelDirBndSign.insert(i);
2116 }
2117 }
2118 }
2119 }
2120
2121 m_dirBndGsh = Gs::Init(paraDirBnd, vRowComm, verbose);
2122
2123 // Set up the local to global map for the next level when using
2124 // multi-level static condensation
2129 nGraphVerts)
2130 {
2131 if (m_staticCondLevel < (bottomUpGraph->GetNlevels() - 1))
2132 {
2133 Array<OneD, int> vwgts_perm(graph[0].size() + graph[1].size() +
2134 graph[2].size() -
2135 firstNonDirGraphVertId);
2136
2137 for (i = 0; i < locExpVector.size(); ++i)
2138 {
2139 exp = locExpVector[i];
2140
2141 for (j = 0; j < exp->GetNverts(); ++j)
2142 {
2143 meshVertId = exp->GetGeom()->GetVid(j);
2144
2145 if (graph[0][meshVertId] >= firstNonDirGraphVertId)
2146 {
2147 vwgts_perm[graph[0][meshVertId] -
2148 firstNonDirGraphVertId] =
2149 dofs[0][meshVertId];
2150 }
2151 }
2152
2153 for (j = 0; j < exp->GetGeom()->GetNumEdges(); ++j)
2154 {
2155 meshEdgeId = exp->GetGeom()->GetEid(j);
2156
2157 if (graph[1][meshEdgeId] >= firstNonDirGraphVertId)
2158 {
2159 vwgts_perm[graph[1][meshEdgeId] -
2160 firstNonDirGraphVertId] =
2161 dofs[1][meshEdgeId];
2162 }
2163 }
2164
2165 for (j = 0; j < exp->GetGeom()->GetNumFaces(); ++j)
2166 {
2167 meshFaceId = exp->GetGeom()->GetFid(j);
2168
2169 if (graph[2][meshFaceId] >= firstNonDirGraphVertId)
2170 {
2171 vwgts_perm[graph[2][meshFaceId] -
2172 firstNonDirGraphVertId] =
2173 dofs[2][meshFaceId];
2174 }
2175 }
2176 }
2177
2178 bottomUpGraph->ExpandGraphWithVertexWeights(vwgts_perm);
2181 bottomUpGraph);
2182 }
2183 }
2184
2186
2187 // Add up hash values if parallel
2188 int hash = m_hash;
2189 vRowComm->AllReduce(hash, LibUtilities::ReduceSum);
2190 m_hash = hash;
2191
2194}
#define ASSERTL0(condition, msg)
#define ASSERTL1(condition, msg)
Assert Level 1 – Debugging which is used whether in FULLDEBUG or DEBUG compilation mode....
#define sign(a, b)
return the sign(b)*a
Definition Polylib.cpp:47
static std::shared_ptr< DataType > AllocateSharedPtr(const Args &...args)
Allocate a shared pointer from the memory pool.
int CreateGraph(const ExpList &locExp, const BndCondExp &bndCondExp, const Array< OneD, const BndCond > &bndConditions, const bool checkIfSystemSingular, const PeriodicMap &periodicVerts, const PeriodicMap &periodicEdges, const PeriodicMap &periodicFaces, DofGraph &graph, BottomUpSubStructuredGraphSharedPtr &bottomUpGraph, std::set< int > &extraDirVerts, std::set< int > &extraDirEdges, int &firstNonDirGraphVertId, int &nExtraDirichlet, int mdswitch=1)
std::set< int > m_parallelDirBndSign
Set indicating the local coeffs just touching parallel dirichlet boundary that have a sign change.
Array< OneD, int > m_localToGlobalMap
Integer map of local coeffs to global space.
void SetUpUniversalC0ContMap(const ExpList &locExp, const PeriodicMap &perVerts=NullPeriodicMap, const PeriodicMap &perEdges=NullPeriodicMap, const PeriodicMap &perFaces=NullPeriodicMap)
Array< OneD, NekDouble > m_localToGlobalSign
Integer sign of local coeffs to global space.
void CalculateFullSystemBandWidth()
Calculate the bandwith of the full matrix system.
std::set< ExtraDirDof > m_copyLocalDirDofs
Set indicating degrees of freedom which are Dirichlet but whose value is stored on another processor.
Array< OneD, int > m_globalToUniversalMap
Integer map of process coeffs to universal space.
int m_numLocalBndCondCoeffs
Number of local boundary condition coefficients.
GlobalSysSolnType m_solnType
The solution type of the global system.
int m_numLocalCoeffs
Total number of local coefficients.
Array< OneD, int > m_bndCondCoeffsToLocalCoeffsMap
Integer map of bnd cond coeffs to local coefficients.
bool m_signChange
Flag indicating if modes require sign reversal.
Array< OneD, int > m_localToLocalIntMap
Integer map of local boundary coeffs to local interior system numbering.
int m_numGlobalCoeffs
Total number of global coefficients.
void CalculateBndSystemBandWidth()
Calculates the bandwidth of the boundary system.
Array< OneD, NekDouble > m_localToGlobalBndSign
Integer sign of local boundary coeffs to global space.
Array< OneD, unsigned int > m_numLocalBndCoeffsPerPatch
The number of bnd dofs per patch.
LibUtilities::SessionReaderSharedPtr m_session
Session object.
int m_numLocalBndCoeffs
Number of local boundary coefficients.
AssemblyMapSharedPtr m_nextLevelLocalToGlobalMap
Map from the patches of the previous level to the patches of the current level.
int m_staticCondLevel
The level of recursion in the case of multi-level static condensation.
int m_numGlobalDirBndCoeffs
Number of Global Dirichlet Boundary Coefficients.
Array< OneD, unsigned int > m_numLocalIntCoeffsPerPatch
The number of int dofs per patch.
Array< OneD, int > m_localToGlobalBndMap
Integer map of local coeffs to global Boundary Dofs.
Gs::gs_data * m_dirBndGsh
gs gather communication to impose Dirhichlet BCs.
LibUtilities::CommSharedPtr m_comm
Communicator.
Array< OneD, int > m_localToLocalBndMap
Integer map of local boundary coeffs to local boundary system numbering.
Array< OneD, NekDouble > m_bndCondCoeffsToLocalCoeffsSign
Integer map of sign of bnd cond coeffs to local coefficients.
int m_numPatches
The number of patches (~elements) in the current level.
int m_numGlobalBndCoeffs
Total number of global boundary coefficients.
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_max
Definition GsLib.hpp:63
@ gs_min
Definition GsLib.hpp:62
static void Finalise(gs_data *pGsh)
Deallocates the GSLib mapping data.
Definition GsLib.hpp:248
int getNumberOfCoefficients(int Na, int Nb)
int getNumberOfBndCoefficients(int Na, int Nb)
int getNumberOfCoefficients(int Na, int Nb)
int getNumberOfBndCoefficients(int Na, int Nb)
std::shared_ptr< Comm > CommSharedPtr
Pointer to a Communicator object.
Definition Comm.h:55
@ eModified_B
Principle Modified Functions .
Definition BasisType.h:49
@ P
Monomial polynomials .
Definition BasisType.h:62
@ 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< Expansion > ExpansionSharedPtr
Definition Expansion.h:66
std::vector< ExpansionSharedPtr > ExpansionVector
Definition Expansion.h:68
std::shared_ptr< BottomUpSubStructuredGraph > BottomUpSubStructuredGraphSharedPtr
std::tuple< int, int, NekDouble > ExtraDirDof
std::vector< std::map< int, int > > DofGraph
pair< int, StdRegions::Orientation > DeterminePeriodicEdgeOrientId(int meshEdgeId, StdRegions::Orientation edgeOrient, const vector< PeriodicEntity > &periodicEdges)
Determine orientation of an edge to its periodic equivalents, as well as the ID of the representative...
StdRegions::Orientation DeterminePeriodicFaceOrient(StdRegions::Orientation faceOrient, StdRegions::Orientation perFaceOrient)
Determine relative orientation between two faces.
std::vector< double > p(NPUPPER)
std::vector< double > q(NPUPPER *NPUPPER)
std::size_t hash_range(Iter first, Iter last)
Definition HashUtils.hpp:64
T Vmax(int n, const T *x, const int incx)
Return the maximum element in x – called vmax to avoid conflict with max.
Definition Vmath.hpp:644
scalarT< T > min(scalarT< T > lhs, scalarT< T > rhs)
Definition scalar.hpp:300

References Nektar::MemoryManager< DataType >::AllocateSharedPtr(), ASSERTL0, ASSERTL1, Nektar::MultiRegions::AssemblyMap::CalculateBndSystemBandWidth(), CalculateFullSystemBandWidth(), CreateGraph(), Nektar::MultiRegions::DeterminePeriodicEdgeOrientId(), Nektar::MultiRegions::DeterminePeriodicFaceOrient(), Nektar::MultiRegions::eDirectMultiLevelStaticCond, Nektar::SpatialDomains::eDirichlet, Nektar::MultiRegions::eIterativeMultiLevelStaticCond, Nektar::LibUtilities::eModified_A, Nektar::LibUtilities::eModified_B, Nektar::LibUtilities::eModified_C, Nektar::LibUtilities::eModifiedPyr_C, Nektar::MultiRegions::ePETScMultiLevelStaticCond, Nektar::LibUtilities::eQuadrilateral, Nektar::LibUtilities::eTriangle, Nektar::MultiRegions::eXxtMultiLevelStaticCond, Gs::Finalise(), Gs::Gather(), Nektar::MultiRegions::ExpList::GetCoeff_Offset(), Nektar::MultiRegions::ExpList::GetExp(), Nektar::LibUtilities::StdTriData::getNumberOfBndCoefficients(), Nektar::LibUtilities::StdQuadData::getNumberOfBndCoefficients(), Nektar::LibUtilities::StdTriData::getNumberOfCoefficients(), Nektar::LibUtilities::StdQuadData::getNumberOfCoefficients(), Nektar::StdRegions::StdExpansion::GetTraceNcoeffs(), Gs::gs_max, Gs::gs_min, Nektar::hash_range(), Gs::Init(), Nektar::MultiRegions::AssemblyMap::m_bndCondCoeffsToLocalCoeffsMap, Nektar::MultiRegions::AssemblyMap::m_bndCondCoeffsToLocalCoeffsSign, Nektar::MultiRegions::AssemblyMap::m_bndGsh, Nektar::MultiRegions::AssemblyMap::m_comm, m_copyLocalDirDofs, Nektar::MultiRegions::AssemblyMap::m_dirBndGsh, m_globalToUniversalMap, Nektar::MultiRegions::AssemblyMap::m_hash, Nektar::MultiRegions::AssemblyMap::m_localToGlobalBndMap, Nektar::MultiRegions::AssemblyMap::m_localToGlobalBndSign, m_localToGlobalMap, m_localToGlobalSign, Nektar::MultiRegions::AssemblyMap::m_localToLocalBndMap, Nektar::MultiRegions::AssemblyMap::m_localToLocalIntMap, Nektar::MultiRegions::AssemblyMap::m_nextLevelLocalToGlobalMap, Nektar::MultiRegions::AssemblyMap::m_numGlobalBndCoeffs, Nektar::MultiRegions::AssemblyMap::m_numGlobalCoeffs, Nektar::MultiRegions::AssemblyMap::m_numGlobalDirBndCoeffs, Nektar::MultiRegions::AssemblyMap::m_numLocalBndCoeffs, Nektar::MultiRegions::AssemblyMap::m_numLocalBndCoeffsPerPatch, m_numLocalBndCondCoeffs, Nektar::MultiRegions::AssemblyMap::m_numLocalCoeffs, Nektar::MultiRegions::AssemblyMap::m_numLocalIntCoeffsPerPatch, Nektar::MultiRegions::AssemblyMap::m_numPatches, m_parallelDirBndSign, Nektar::MultiRegions::AssemblyMap::m_session, Nektar::MultiRegions::AssemblyMap::m_signChange, Nektar::MultiRegions::AssemblyMap::m_solnType, Nektar::MultiRegions::AssemblyMap::m_staticCondLevel, tinysimd::min(), Nektar::LibUtilities::P, Nektar::LibUtilities::ReduceSum, SetUpUniversalC0ContMap(), sign, and Vmath::Vmax().

◆ ~AssemblyMapCG()

Nektar::MultiRegions::AssemblyMapCG::~AssemblyMapCG ( )
override

Member Function Documentation

◆ CalculateFullSystemBandWidth()

void Nektar::MultiRegions::AssemblyMapCG::CalculateFullSystemBandWidth ( )
protected

Calculate the bandwith of the full matrix system.

The bandwidth calculated here corresponds to what is referred to as half-bandwidth. If the elements of the matrix are designated as a_ij, it corresponds to the maximum value of |i-j| for non-zero a_ij. As a result, the value also corresponds to the number of sub- or super-diagonals.

The bandwith can be calculated elementally as it corresponds to the maximal elemental bandwith (i.e. the maximal difference in global DOF index for every element).

We caluclate here the bandwith of the full global system.

Definition at line 2708 of file AssemblyMapCG.cpp.

2709{
2710 int i, j;
2711 int cnt = 0;
2712 int locSize;
2713 int maxId;
2714 int minId;
2715 int bwidth = -1;
2716 for (i = 0; i < m_numPatches; ++i)
2717 {
2718 locSize =
2720 maxId = -1;
2721 minId = m_numLocalCoeffs + 1;
2722 for (j = 0; j < locSize; j++)
2723 {
2725 {
2726 if (m_localToGlobalMap[cnt + j] > maxId)
2727 {
2728 maxId = m_localToGlobalMap[cnt + j];
2729 }
2730
2731 if (m_localToGlobalMap[cnt + j] < minId)
2732 {
2733 minId = m_localToGlobalMap[cnt + j];
2734 }
2735 }
2736 }
2737 bwidth = (bwidth > (maxId - minId)) ? bwidth : (maxId - minId);
2738
2739 cnt += locSize;
2740 }
2741
2742 m_fullSystemBandWidth = bwidth;
2743}
int m_fullSystemBandWidth
Bandwith of the full matrix system (no static condensation).

References m_fullSystemBandWidth, m_localToGlobalMap, Nektar::MultiRegions::AssemblyMap::m_numGlobalDirBndCoeffs, Nektar::MultiRegions::AssemblyMap::m_numLocalBndCoeffsPerPatch, Nektar::MultiRegions::AssemblyMap::m_numLocalCoeffs, Nektar::MultiRegions::AssemblyMap::m_numLocalIntCoeffsPerPatch, and Nektar::MultiRegions::AssemblyMap::m_numPatches.

Referenced by AssemblyMapCG().

◆ CreateGraph()

int Nektar::MultiRegions::AssemblyMapCG::CreateGraph ( const ExpList locExp,
const BndCondExp bndCondExp,
const Array< OneD, const BndCond > &  bndConditions,
const bool  checkIfSystemSingular,
const PeriodicMap periodicVerts,
const PeriodicMap periodicEdges,
const PeriodicMap periodicFaces,
DofGraph graph,
BottomUpSubStructuredGraphSharedPtr bottomUpGraph,
std::set< int > &  extraDirVerts,
std::set< int > &  extraDirEdges,
int &  firstNonDirGraphVertId,
int &  nExtraDirichlet,
int  mdswitch = 1 
)
protected
  • Count verts, edges, face and add up edges and face sizes
  • Periodic vertices
  • Periodic edges
  • Periodic faces

STEP 4: Fill the #graph[0] and #graph[1] with the optimal ordering from boost.

Definition at line 77 of file AssemblyMapCG.cpp.

85{
86 int graphVertId = 0;
87 int vMaxVertId = -1;
88 int i, j, k, l, cnt;
89 int meshVertId, meshEdgeId, meshFaceId;
90 int meshVertId2, meshEdgeId2;
91
93 const LocalRegions::ExpansionVector &locExpVector = *(locExp.GetExp());
94 LibUtilities::CommSharedPtr vRowComm = m_comm->GetRowComm();
95
97 m_systemSingular = checkIfSystemSingular;
98
99 for (i = 0; i < bndCondExp.size(); i++)
100 {
101 m_numLocalBndCondCoeffs += bndCondExp[i]->GetNcoeffs();
102
103 if (bndConditions[0][i]->GetBoundaryConditionType() ==
105 {
106 continue;
107 }
108
109 // Check to see if any value on boundary has Dirichlet
110 // value. note this is a vector to manage coupled
111 // solver but for scalar will just be a vector of size 11
112 cnt = 0;
113 for (k = 0; k < bndConditions.size(); ++k)
114 {
115 if (bndConditions[k][i]->GetBoundaryConditionType() ==
117 {
118 cnt++;
119 }
120 if (bndConditions[k][i]->GetBoundaryConditionType() !=
122 {
123 m_systemSingular = false;
124 }
125 }
126
127 // Find the maximum boundary vertex ID on this process. This is
128 // used later to pin a vertex if the system is singular.
129 for (j = 0; j < bndCondExp[i]->GetNumElmts(); ++j)
130 {
131 bndExp = bndCondExp[i]->GetExp(j)->as<LocalRegions::Expansion>();
132 for (k = 0; k < bndExp->GetNverts(); ++k)
133 {
134 if (vMaxVertId < bndExp->GetGeom()->GetVid(k))
135 {
136 vMaxVertId = bndExp->GetGeom()->GetVid(k);
137 }
138 }
139 }
140
141 // If all boundaries are Dirichlet fill in graph
142 if (cnt == bndConditions.size())
143 {
144 for (j = 0; j < bndCondExp[i]->GetNumElmts(); j++)
145 {
146 bndExp = bndCondExp[i]->GetExp(j);
147
148 for (k = 0; k < bndExp->GetNverts(); k++)
149 {
150 meshVertId = bndExp->GetGeom()->GetVid(k);
151 if (graph[0].count(meshVertId) == 0)
152 {
153 graph[0][meshVertId] = graphVertId++;
154 }
155 }
156
157 const int bndDim = bndExp->GetNumBases();
158 if (bndDim > 1)
159 {
160 for (k = 0; k < bndExp->GetNtraces(); k++)
161 {
162 meshEdgeId = bndExp->GetGeom()->GetEid(k);
163 if (graph[1].count(meshEdgeId) == 0)
164 {
165 graph[1][meshEdgeId] = graphVertId++;
166 }
167 }
168 }
169
170 // Possibility of a face in 3D or edge in 2D
171 meshFaceId = bndExp->GetGeom()->GetGlobalID();
172 if (graph[bndDim].count(meshFaceId) == 0)
173 {
174 graph[bndDim][meshFaceId] = graphVertId++;
175 }
176 m_numLocalDirBndCoeffs += bndExp->GetNcoeffs();
177 }
178 }
179 }
180
181 // Number of dirichlet edges and faces (not considering periodic
182 // BCs)
183 m_numDirEdges = graph[1].size();
184 m_numDirFaces = graph[2].size();
185
186 /*
187 * The purpose of this routine is to deal with those degrees of
188 * freedom that are Dirichlet, but do not have a local Dirichlet
189 * boundary condition expansion set.
190 *
191 * For example, in 2D, consider a triangulation of a square into two
192 * triangles. Now imagine one edge of the square is Dirichlet and
193 * the problem is run on two processors. On one processor, one
194 * triangle vertex is Dirichlet, but doesn't know this since the
195 * Dirichlet composite lives on the other processor.
196 *
197 * When the global linear system is solved therefore, there is an
198 * inconsistency that at best leads to an inaccurate answer or a
199 * divergence of the system.
200 *
201 * This routine identifies such cases for 2D, and also for 3D where
202 * e.g. edges may have the same problem (consider an extrusion of
203 * the case above, for example).
204 */
205
206 // Collate information on Dirichlet vertices from all processes
207 int n = vRowComm->GetSize();
208 int p = vRowComm->GetRank();
209
210 if (vRowComm->IsSerial())
211 {
212 // for FieldConvert Comm this is true and it resets
213 // parallel processing back to serial case
214 n = 1;
215 p = 0;
216 }
217 // At this point, graph only contains information from Dirichlet
218 // boundaries. Therefore make a global list of the vert and edge
219 // information on all processors.
220 Array<OneD, int> vertcounts(n, 0);
221 Array<OneD, int> vertoffsets(n, 0);
222 Array<OneD, int> edgecounts(n, 0);
223 Array<OneD, int> edgeoffsets(n, 0);
224 vertcounts[p] = graph[0].size();
225 edgecounts[p] = graph[1].size();
226 vRowComm->AllReduce(vertcounts, LibUtilities::ReduceSum);
227 vRowComm->AllReduce(edgecounts, LibUtilities::ReduceSum);
228
229 for (i = 1; i < n; ++i)
230 {
231 vertoffsets[i] = vertoffsets[i - 1] + vertcounts[i - 1];
232 edgeoffsets[i] = edgeoffsets[i - 1] + edgecounts[i - 1];
233 }
234
235 int nTotVerts = Vmath::Vsum(n, vertcounts, 1);
236 int nTotEdges = Vmath::Vsum(n, edgecounts, 1);
237
238 Array<OneD, int> vertlist(nTotVerts, 0);
239 Array<OneD, int> edgelist(nTotEdges, 0);
240
241 // construct list of global ids of global vertices
242 i = 0;
243 for (auto &it : graph[0])
244 {
245 vertlist[vertoffsets[p] + i++] = it.first;
246 }
247
248 // construct list of global ids of global edges
249 i = 0;
250 for (auto &it : graph[1])
251 {
252 edgelist[edgeoffsets[p] + i++] = it.first;
253 }
254 vRowComm->AllReduce(vertlist, LibUtilities::ReduceSum);
255 vRowComm->AllReduce(edgelist, LibUtilities::ReduceSum);
256
257 // Now we have a list of all Dirichlet vertices and edges on all
258 // processors.
259 nExtraDirichlet = 0;
260 map<int, int> extraDirVertIds, extraDirEdgeIds;
261
262 // Ensure Dirchlet vertices are consistently recorded between
263 // processes (e.g. Dirichlet region meets Neumann region across a
264 // partition boundary requires vertex on partition to be Dirichlet).
265 //
266 // To do this we look over all elements and vertices in local
267 // partition and see if they match the values stored in the vertlist
268 // from other processors and if so record the meshVertId/meshEdgeId
269 // and the processor it comes from.
270 for (i = 0; i < n; ++i)
271 {
272 if (i == p)
273 {
274 continue;
275 }
276
277 for (j = 0; j < locExpVector.size(); j++)
278 {
279 exp = locExpVector[j];
280
281 for (k = 0; k < exp->GetNverts(); k++)
282 {
283 meshVertId = exp->GetGeom()->GetVid(k);
284 if (graph[0].count(meshVertId) == 0)
285 {
286 for (l = 0; l < vertcounts[i]; ++l)
287 {
288 if (vertlist[vertoffsets[i] + l] == meshVertId)
289 {
290 extraDirVertIds[meshVertId] = i;
291 graph[0][meshVertId] = graphVertId++;
292 nExtraDirichlet++;
293 }
294 }
295 }
296 }
297
298 for (k = 0; k < exp->GetGeom()->GetNumEdges(); k++)
299 {
300 meshEdgeId = exp->GetGeom()->GetEid(k);
301 if (graph[1].count(meshEdgeId) == 0)
302 {
303 for (l = 0; l < edgecounts[i]; ++l)
304 {
305 if (edgelist[edgeoffsets[i] + l] == meshEdgeId)
306 {
307 extraDirEdgeIds[meshEdgeId] = i;
308 graph[1][meshEdgeId] = graphVertId++;
309 if (exp->GetGeom()->GetNumFaces())
310 {
311 nExtraDirichlet +=
312 exp->as<LocalRegions::Expansion3D>()
313 ->GetEdgeNcoeffs(k) -
314 2;
315 }
316 else
317 {
318 nExtraDirichlet += exp->GetTraceNcoeffs(k) - 2;
319 }
320 }
321 }
322 }
323 }
324 }
325 }
326
327 // Low Energy preconditioner needs to know how many extra Dirichlet
328 // edges are on this process so store map in array.
329 m_extraDirEdges = Array<OneD, int>(extraDirEdgeIds.size(), -1);
330 i = 0;
331 for (auto &it : extraDirEdgeIds)
332 {
333 meshEdgeId = it.first;
334 m_extraDirEdges[i++] = meshEdgeId;
335 }
336
337 // Now we have a list of all vertices and edges that are Dirichlet
338 // and not defined on the local partition as well as which processor
339 // they are stored on.
340 //
341 // Make a full list of all such entities on all processors and which
342 // processor they belong to.
343 for (i = 0; i < n; ++i)
344 {
345 vertcounts[i] = 0;
346 vertoffsets[i] = 0;
347 edgecounts[i] = 0;
348 edgeoffsets[i] = 0;
349 }
350
351 vertcounts[p] = extraDirVertIds.size();
352 edgecounts[p] = extraDirEdgeIds.size();
353 vRowComm->AllReduce(vertcounts, LibUtilities::ReduceSum);
354 vRowComm->AllReduce(edgecounts, LibUtilities::ReduceSum);
355 nTotVerts = Vmath::Vsum(n, vertcounts, 1);
356 nTotEdges = Vmath::Vsum(n, edgecounts, 1);
357
358 vertoffsets[0] = edgeoffsets[0] = 0;
359
360 for (i = 1; i < n; ++i)
361 {
362 vertoffsets[i] = vertoffsets[i - 1] + vertcounts[i - 1];
363 edgeoffsets[i] = edgeoffsets[i - 1] + edgecounts[i - 1];
364 }
365
366 Array<OneD, int> vertids(nTotVerts, 0);
367 Array<OneD, int> edgeids(nTotEdges, 0);
368 Array<OneD, int> vertprocs(nTotVerts, 0);
369 Array<OneD, int> edgeprocs(nTotEdges, 0);
370
371 i = 0;
372 for (auto &it : extraDirVertIds)
373 {
374 vertids[vertoffsets[p] + i] = it.first;
375 vertprocs[vertoffsets[p] + i] = it.second;
376 ++i;
377 }
378
379 i = 0;
380 for (auto &it : extraDirEdgeIds)
381 {
382 edgeids[edgeoffsets[p] + i] = it.first;
383 edgeprocs[edgeoffsets[p] + i] = it.second;
384 ++i;
385 }
386
387 vRowComm->AllReduce(vertids, LibUtilities::ReduceSum);
388 vRowComm->AllReduce(vertprocs, LibUtilities::ReduceSum);
389 vRowComm->AllReduce(edgeids, LibUtilities::ReduceSum);
390 vRowComm->AllReduce(edgeprocs, LibUtilities::ReduceSum);
391
392 // Set up list of vertices that need to be shared to other
393 // partitions
394 for (i = 0; i < nTotVerts; ++i)
395 {
396 if (p == vertprocs[i]) // rank = vertproc[i]
397 {
398 extraDirVerts.insert(vertids[i]);
399 }
400 }
401
402 // Set up list of edges that need to be shared to other partitions
403 for (i = 0; i < nTotEdges; ++i)
404 {
405 if (p == edgeprocs[i]) // rank = vertproc[i]
406 {
407 extraDirEdges.insert(edgeids[i]);
408 }
409 }
410
411 // Check between processes if the whole system is singular
412 int s = m_systemSingular ? 1 : 0;
413 vRowComm->AllReduce(s, LibUtilities::ReduceMin);
414 m_systemSingular = s == 1 ? true : false;
415
416 // Find the minimum boundary vertex ID on each process
417 Array<OneD, int> bcminvertid(n, 0);
418 bcminvertid[p] = vMaxVertId;
419 vRowComm->AllReduce(bcminvertid, LibUtilities::ReduceMax);
420
421 // Find the process rank with the minimum boundary vertex ID
422 int maxIdx = Vmath::Imax(n, bcminvertid, 1);
423
424 // If the system is singular, the process with the maximum
425 // number of BCs will set a Dirichlet vertex to make
426 // system non-singular. Note: we find the process with
427 // maximum boundary regions to ensure we do not try to set
428 // a Dirichlet vertex on a partition with no intersection
429 // with the boundary.
430 meshVertId = 0;
431
432 if (m_systemSingular && checkIfSystemSingular && maxIdx == p)
433 {
434 if (m_session->DefinesParameter("SingularVertex"))
435 {
436 m_session->LoadParameter("SingularVertex", meshVertId);
437 }
438 else if (vMaxVertId == -1)
439 {
440 // All boundaries are periodic.
441 meshVertId = locExpVector[0]->GetGeom()->GetVid(0);
442 }
443 else
444 {
445 // Set pinned vertex to that with minimum vertex ID to
446 // ensure consistency in parallel.
447 meshVertId = bcminvertid[p];
448 }
449
450 if (graph[0].count(meshVertId) == 0)
451 {
452 graph[0][meshVertId] = graphVertId++;
453 }
454 }
455
456 vRowComm->AllReduce(meshVertId, LibUtilities::ReduceSum);
457
458 // When running in parallel, we need to ensure that the singular
459 // mesh vertex is communicated to any periodic vertices, otherwise
460 // the system may diverge.
461 if (m_systemSingular && checkIfSystemSingular)
462 {
463 // Firstly, we check that no other processors have this
464 // vertex. If they do, then we mark the vertex as also being
465 // Dirichlet.
466 if (maxIdx != p)
467 {
468 for (i = 0; i < locExpVector.size(); ++i)
469 {
470 for (j = 0; j < locExpVector[i]->GetNverts(); ++j)
471 {
472 if (locExpVector[i]->GetGeom()->GetVid(j) != meshVertId)
473 {
474 continue;
475 }
476
477 if (graph[0].count(meshVertId) == 0)
478 {
479 graph[0][meshVertId] = graphVertId++;
480 }
481 }
482 }
483 }
484
485 // In the case that meshVertId is periodic with other vertices,
486 // this process and all other processes need to make sure that
487 // the periodic vertices are also marked as Dirichlet.
488 int gId;
489
490 // At least one process (maxBCidx) will have already associated
491 // a graphVertId with meshVertId. Others won't even have any of
492 // the vertices. The logic below is designed to handle both
493 // cases.
494 if (graph[0].count(meshVertId) == 0)
495 {
496 gId = -1;
497 }
498 else
499 {
500 gId = graph[0][meshVertId];
501 }
502
503 for (auto &pIt : periodicVerts)
504 {
505 // Either the vertex is local to this processor (in which
506 // case it will be in the pIt.first position) or else
507 // meshVertId might be contained within another processor's
508 // vertex list. The if statement below covers both cases. If
509 // we find it, set as Dirichlet with the vertex id gId.
510 if (pIt.first == meshVertId)
511 {
512 gId = gId < 0 ? graphVertId++ : gId;
513 graph[0][meshVertId] = gId;
514
515 for (i = 0; i < pIt.second.size(); ++i)
516 {
517 if (pIt.second[i].isLocal)
518 {
519 graph[0][pIt.second[i].id] = graph[0][meshVertId];
520 }
521 }
522 }
523 else
524 {
525 bool found = false;
526 for (i = 0; i < pIt.second.size(); ++i)
527 {
528 if (pIt.second[i].id == meshVertId)
529 {
530 found = true;
531 break;
532 }
533 }
534
535 if (found)
536 {
537 gId = gId < 0 ? graphVertId++ : gId;
538 graph[0][pIt.first] = gId;
539
540 for (i = 0; i < pIt.second.size(); ++i)
541 {
542 if (pIt.second[i].isLocal)
543 {
544 graph[0][pIt.second[i].id] = graph[0][pIt.first];
545 }
546 }
547 }
548 }
549 }
550 }
551
552 // Add extra dirichlet boundary conditions to count.
553 m_numLocalDirBndCoeffs += nExtraDirichlet;
554 firstNonDirGraphVertId = graphVertId;
555
556 typedef boost::adjacency_list<boost::setS, boost::vecS, boost::undirectedS>
557 BoostGraph;
558 BoostGraph boostGraphObj;
559
560 vector<map<int, int>> tempGraph(3);
561 map<int, int> vwgts_map;
562 Array<OneD, int> localVerts;
563 Array<OneD, int> localEdges;
564 Array<OneD, int> localFaces;
565
566 int tempGraphVertId = 0;
567 int localVertOffset = 0;
568 int localEdgeOffset = 0;
569 int localFaceOffset = 0;
570 int nTotalVerts = 0;
571 int nTotalEdges = 0;
572 int nTotalFaces = 0;
573 int nVerts;
574 int nEdges;
575 int nFaces;
576 int vertCnt;
577 int edgeCnt;
578 int faceCnt;
579
586
587 map<int, int> EdgeSize;
588 map<int, int> FaceSize;
589
590 /// - Count verts, edges, face and add up edges and face sizes
591 for (i = 0; i < locExpVector.size(); ++i)
592 {
593 exp = locExpVector[i];
594 nEdges = exp->GetGeom()->GetNumEdges();
595 nFaces = exp->GetGeom()->GetNumFaces();
596
597 nTotalVerts += exp->GetNverts();
598 nTotalEdges += nEdges;
599 nTotalFaces += nFaces;
600
601 for (j = 0; j < nEdges; ++j)
602 {
603 meshEdgeId = exp->GetGeom()->GetEid(j);
604 int nEdgeInt;
605
606 if (nFaces)
607 {
608 nEdgeInt =
609 exp->as<LocalRegions::Expansion3D>()->GetEdgeNcoeffs(j) - 2;
610 }
611 else
612 {
613 nEdgeInt = exp->GetTraceNcoeffs(j) - 2;
614 }
615
616 if (EdgeSize.count(meshEdgeId) > 0)
617 {
618 EdgeSize[meshEdgeId] = min(EdgeSize[meshEdgeId], nEdgeInt);
619 }
620 else
621 {
622 EdgeSize[meshEdgeId] = nEdgeInt;
623 }
624 }
625
626 faceCnt = 0;
627 for (j = 0; j < nFaces; ++j)
628 {
629 meshFaceId = exp->GetGeom()->GetFid(j);
630 if (FaceSize.count(meshFaceId) > 0)
631 {
632 FaceSize[meshFaceId] =
633 min(FaceSize[meshFaceId], exp->GetTraceIntNcoeffs(j));
634 }
635 else
636 {
637 FaceSize[meshFaceId] = exp->GetTraceIntNcoeffs(j);
638 }
639 FaceSize[meshFaceId] = exp->GetTraceIntNcoeffs(j);
640 }
641 }
642
643 /// - Periodic vertices
644 for (auto &pIt : periodicVerts)
645 {
646 meshVertId = pIt.first;
647
648 // This periodic vertex is joined to a Dirichlet condition.
649 if (graph[0].count(pIt.first) != 0)
650 {
651 for (i = 0; i < pIt.second.size(); ++i)
652 {
653 meshVertId2 = pIt.second[i].id;
654 if (graph[0].count(meshVertId2) == 0 && pIt.second[i].isLocal)
655 {
656 graph[0][meshVertId2] = graph[0][meshVertId];
657 }
658 }
659 continue;
660 }
661
662 // One of the attached vertices is Dirichlet.
663 bool isDirichlet = false;
664 for (i = 0; i < pIt.second.size(); ++i)
665 {
666 if (!pIt.second[i].isLocal)
667 {
668 continue;
669 }
670
671 meshVertId2 = pIt.second[i].id;
672 if (graph[0].count(meshVertId2) > 0)
673 {
674 isDirichlet = true;
675 break;
676 }
677 }
678
679 if (isDirichlet)
680 {
681 graph[0][meshVertId] = graph[0][pIt.second[i].id];
682
683 for (j = 0; j < pIt.second.size(); ++j)
684 {
685 meshVertId2 = pIt.second[i].id;
686 if (j == i || !pIt.second[j].isLocal ||
687 graph[0].count(meshVertId2) > 0)
688 {
689 continue;
690 }
691
692 graph[0][meshVertId2] = graph[0][pIt.second[i].id];
693 }
694
695 continue;
696 }
697
698 // Otherwise, see if a vertex ID has already been set.
699 for (i = 0; i < pIt.second.size(); ++i)
700 {
701 if (!pIt.second[i].isLocal)
702 {
703 continue;
704 }
705
706 if (tempGraph[0].count(pIt.second[i].id) > 0)
707 {
708 break;
709 }
710 }
711
712 if (i == pIt.second.size())
713 {
714 boost::add_vertex(boostGraphObj);
715 tempGraph[0][meshVertId] = tempGraphVertId++;
717 }
718 else
719 {
720 tempGraph[0][meshVertId] = tempGraph[0][pIt.second[i].id];
721 }
722 }
723
724 // Store the temporary graph vertex id's of all element edges and
725 // vertices in these 3 arrays below
726 localVerts = Array<OneD, int>(nTotalVerts, -1);
727 localEdges = Array<OneD, int>(nTotalEdges, -1);
728 localFaces = Array<OneD, int>(nTotalFaces, -1);
729
730 // Set up vertex numbering
731 for (i = 0; i < locExpVector.size(); ++i)
732 {
733 exp = locExpVector[i];
734 vertCnt = 0;
735 nVerts = exp->GetNverts();
736 for (j = 0; j < nVerts; ++j)
737 {
738 meshVertId = exp->GetGeom()->GetVid(j);
739 if (graph[0].count(meshVertId) == 0)
740 {
741 if (tempGraph[0].count(meshVertId) == 0)
742 {
743 boost::add_vertex(boostGraphObj);
744 tempGraph[0][meshVertId] = tempGraphVertId++;
746 }
747 localVerts[localVertOffset + vertCnt++] =
748 tempGraph[0][meshVertId];
749 vwgts_map[tempGraph[0][meshVertId]] = 1;
750 }
751 }
752
753 localVertOffset += nVerts;
754 }
755
756 /// - Periodic edges
757 for (auto &pIt : periodicEdges)
758 {
759 meshEdgeId = pIt.first;
760
761 // This periodic edge is joined to a Dirichlet condition.
762 if (graph[1].count(pIt.first) != 0)
763 {
764 for (i = 0; i < pIt.second.size(); ++i)
765 {
766 meshEdgeId2 = pIt.second[i].id;
767 if (graph[1].count(meshEdgeId2) == 0 && pIt.second[i].isLocal)
768 {
769 graph[1][meshEdgeId2] = graph[1][meshEdgeId];
770 }
771 }
772 continue;
773 }
774
775 // One of the attached edges is Dirichlet.
776 bool isDirichlet = false;
777 for (i = 0; i < pIt.second.size(); ++i)
778 {
779 if (!pIt.second[i].isLocal)
780 {
781 continue;
782 }
783
784 meshEdgeId2 = pIt.second[i].id;
785 if (graph[1].count(meshEdgeId2) > 0)
786 {
787 isDirichlet = true;
788 break;
789 }
790 }
791
792 if (isDirichlet)
793 {
794 graph[1][meshEdgeId] = graph[1][pIt.second[i].id];
795
796 for (j = 0; j < pIt.second.size(); ++j)
797 {
798 meshEdgeId2 = pIt.second[i].id;
799 if (j == i || !pIt.second[j].isLocal ||
800 graph[1].count(meshEdgeId2) > 0)
801 {
802 continue;
803 }
804
805 graph[1][meshEdgeId2] = graph[1][pIt.second[i].id];
806 }
807
808 continue;
809 }
810
811 // Otherwise, see if a edge ID has already been set.
812 for (i = 0; i < pIt.second.size(); ++i)
813 {
814 if (!pIt.second[i].isLocal)
815 {
816 continue;
817 }
818
819 if (tempGraph[1].count(pIt.second[i].id) > 0)
820 {
821 break;
822 }
823 }
824
825 if (i == pIt.second.size())
826 {
827 boost::add_vertex(boostGraphObj);
828 tempGraph[1][meshEdgeId] = tempGraphVertId++;
829 m_numNonDirEdgeModes += EdgeSize[meshEdgeId];
831 }
832 else
833 {
834 tempGraph[1][meshEdgeId] = tempGraph[1][pIt.second[i].id];
835 }
836 }
837
838 int nEdgeIntCoeffs, nFaceIntCoeffs;
839
840 // Set up edge numbering
841 for (i = 0; i < locExpVector.size(); ++i)
842 {
843 exp = locExpVector[i];
844 edgeCnt = 0;
845 nEdges = exp->GetGeom()->GetNumEdges();
846
847 for (j = 0; j < nEdges; ++j)
848 {
849 meshEdgeId = exp->GetGeom()->GetEid(j);
850 nEdgeIntCoeffs = EdgeSize[meshEdgeId];
851 if (graph[1].count(meshEdgeId) == 0)
852 {
853 if (tempGraph[1].count(meshEdgeId) == 0)
854 {
855 boost::add_vertex(boostGraphObj);
856 tempGraph[1][meshEdgeId] = tempGraphVertId++;
857 m_numNonDirEdgeModes += nEdgeIntCoeffs;
858
860 }
861 localEdges[localEdgeOffset + edgeCnt++] =
862 tempGraph[1][meshEdgeId];
863 vwgts_map[tempGraph[1][meshEdgeId]] = nEdgeIntCoeffs;
864 }
865 }
866
867 localEdgeOffset += nEdges;
868 }
869
870 /// - Periodic faces
871 for (auto &pIt : periodicFaces)
872 {
873 if (!pIt.second[0].isLocal)
874 {
875 // The face mapped to is on another process.
876 meshFaceId = pIt.first;
877 ASSERTL0(graph[2].count(meshFaceId) == 0,
878 "This periodic boundary edge has been specified before");
879 boost::add_vertex(boostGraphObj);
880 tempGraph[2][meshFaceId] = tempGraphVertId++;
881 nFaceIntCoeffs = FaceSize[meshFaceId];
882 m_numNonDirFaceModes += nFaceIntCoeffs;
884 }
885 else if (pIt.first < pIt.second[0].id)
886 {
887 ASSERTL0(graph[2].count(pIt.first) == 0,
888 "This periodic boundary face has been specified before");
889 ASSERTL0(graph[2].count(pIt.second[0].id) == 0,
890 "This periodic boundary face has been specified before");
891
892 boost::add_vertex(boostGraphObj);
893 tempGraph[2][pIt.first] = tempGraphVertId;
894 tempGraph[2][pIt.second[0].id] = tempGraphVertId++;
895 nFaceIntCoeffs = FaceSize[pIt.first];
896 m_numNonDirFaceModes += nFaceIntCoeffs;
898 }
899 }
900
901 // setup face numbering
902 for (i = 0; i < locExpVector.size(); ++i)
903 {
904 exp = locExpVector[i];
905 nFaces = exp->GetGeom()->GetNumFaces();
906 faceCnt = 0;
907 for (j = 0; j < nFaces; ++j)
908 {
909 nFaceIntCoeffs = exp->GetTraceIntNcoeffs(j);
910 meshFaceId = exp->GetGeom()->GetFid(j);
911 if (graph[2].count(meshFaceId) == 0)
912 {
913 if (tempGraph[2].count(meshFaceId) == 0)
914 {
915 boost::add_vertex(boostGraphObj);
916 tempGraph[2][meshFaceId] = tempGraphVertId++;
917 m_numNonDirFaceModes += nFaceIntCoeffs;
918
920 }
921 localFaces[localFaceOffset + faceCnt++] =
922 tempGraph[2][meshFaceId];
923 vwgts_map[tempGraph[2][meshFaceId]] = nFaceIntCoeffs;
924 }
925 }
926 m_numLocalBndCoeffs += exp->NumBndryCoeffs();
927
928 localFaceOffset += nFaces;
929 }
930
931 localVertOffset = 0;
932 localEdgeOffset = 0;
933 localFaceOffset = 0;
934 for (i = 0; i < locExpVector.size(); ++i)
935 {
936 exp = locExpVector[i];
937 nVerts = exp->GetNverts();
938 nEdges = exp->GetGeom()->GetNumEdges();
939 nFaces = exp->GetGeom()->GetNumFaces();
940
941 // Now loop over all local faces, edges and vertices of this
942 // element and define that all other faces, edges and verices of
943 // this element are adjacent to them.
944
945 // Vertices
946 for (j = 0; j < nVerts; j++)
947 {
948 if (localVerts[j + localVertOffset] == -1)
949 {
950 break;
951 }
952 // associate to other vertices
953 for (k = 0; k < nVerts; k++)
954 {
955 if (localVerts[k + localVertOffset] == -1)
956 {
957 break;
958 }
959 if (k != j)
960 {
961 boost::add_edge((size_t)localVerts[j + localVertOffset],
962 (size_t)localVerts[k + localVertOffset],
963 boostGraphObj);
964 }
965 }
966 // associate to other edges
967 for (k = 0; k < nEdges; k++)
968 {
969 if (localEdges[k + localEdgeOffset] == -1)
970 {
971 break;
972 }
973 boost::add_edge((size_t)localVerts[j + localVertOffset],
974 (size_t)localEdges[k + localEdgeOffset],
975 boostGraphObj);
976 }
977 // associate to other faces
978 for (k = 0; k < nFaces; k++)
979 {
980 if (localFaces[k + localFaceOffset] == -1)
981 {
982 break;
983 }
984 boost::add_edge((size_t)localVerts[j + localVertOffset],
985 (size_t)localFaces[k + localFaceOffset],
986 boostGraphObj);
987 }
988 }
989
990 // Edges
991 for (j = 0; j < nEdges; j++)
992 {
993 if (localEdges[j + localEdgeOffset] == -1)
994 {
995 break;
996 }
997 // Associate to other edges
998 for (k = 0; k < nEdges; k++)
999 {
1000 if (localEdges[k + localEdgeOffset] == -1)
1001 {
1002 break;
1003 }
1004 if (k != j)
1005 {
1006 boost::add_edge((size_t)localEdges[j + localEdgeOffset],
1007 (size_t)localEdges[k + localEdgeOffset],
1008 boostGraphObj);
1009 }
1010 }
1011 // Associate to vertices
1012 for (k = 0; k < nVerts; k++)
1013 {
1014 if (localVerts[k + localVertOffset] == -1)
1015 {
1016 break;
1017 }
1018 boost::add_edge((size_t)localEdges[j + localEdgeOffset],
1019 (size_t)localVerts[k + localVertOffset],
1020 boostGraphObj);
1021 }
1022 // Associate to faces
1023 for (k = 0; k < nFaces; k++)
1024 {
1025 if (localFaces[k + localFaceOffset] == -1)
1026 {
1027 break;
1028 }
1029 boost::add_edge((size_t)localEdges[j + localEdgeOffset],
1030 (size_t)localFaces[k + localFaceOffset],
1031 boostGraphObj);
1032 }
1033 }
1034
1035 // Faces
1036 for (j = 0; j < nFaces; j++)
1037 {
1038 if (localFaces[j + localFaceOffset] == -1)
1039 {
1040 break;
1041 }
1042 // Associate to other faces
1043 for (k = 0; k < nFaces; k++)
1044 {
1045 if (localFaces[k + localFaceOffset] == -1)
1046 {
1047 break;
1048 }
1049 if (k != j)
1050 {
1051 boost::add_edge((size_t)localFaces[j + localFaceOffset],
1052 (size_t)localFaces[k + localFaceOffset],
1053 boostGraphObj);
1054 }
1055 }
1056 // Associate to vertices
1057 for (k = 0; k < nVerts; k++)
1058 {
1059 if (localVerts[k + localVertOffset] == -1)
1060 {
1061 break;
1062 }
1063 boost::add_edge((size_t)localFaces[j + localFaceOffset],
1064 (size_t)localVerts[k + localVertOffset],
1065 boostGraphObj);
1066 }
1067 // Associate to edges
1068 for (k = 0; k < nEdges; k++)
1069 {
1070 if (localEdges[k + localEdgeOffset] == -1)
1071 {
1072 break;
1073 }
1074 boost::add_edge((size_t)localFaces[j + localFaceOffset],
1075 (size_t)localEdges[k + localEdgeOffset],
1076 boostGraphObj);
1077 }
1078 }
1079
1080 localVertOffset += nVerts;
1081 localEdgeOffset += nEdges;
1082 localFaceOffset += nFaces;
1083 }
1084
1085 // Container to store vertices of the graph which correspond to
1086 // degrees of freedom along the boundary and periodic BCs.
1087 set<int> partVerts;
1088
1091 {
1092 vector<long> procVerts, procEdges, procFaces;
1093 set<int> foundVerts, foundEdges, foundFaces;
1094
1095 // Loop over element and construct the procVerts and procEdges
1096 // vectors, which store the geometry IDs of mesh vertices and
1097 // edges respectively which are local to this process.
1098 for (i = cnt = 0; i < locExpVector.size(); ++i)
1099 {
1100 int elmtid = i;
1101 exp = locExpVector[elmtid];
1102 for (j = 0; j < exp->GetNverts(); ++j)
1103 {
1104 int vid = exp->GetGeom()->GetVid(j) + 1;
1105 if (foundVerts.count(vid) == 0)
1106 {
1107 procVerts.push_back(vid);
1108 foundVerts.insert(vid);
1109 }
1110 }
1111
1112 for (j = 0; j < exp->GetGeom()->GetNumEdges(); ++j)
1113 {
1114 int eid = exp->GetGeom()->GetEid(j) + 1;
1115
1116 if (foundEdges.count(eid) == 0)
1117 {
1118 procEdges.push_back(eid);
1119 foundEdges.insert(eid);
1120 }
1121 }
1122
1123 for (j = 0; j < exp->GetGeom()->GetNumFaces(); ++j)
1124 {
1125 int fid = exp->GetGeom()->GetFid(j) + 1;
1126
1127 if (foundFaces.count(fid) == 0)
1128 {
1129 procFaces.push_back(fid);
1130 foundFaces.insert(fid);
1131 }
1132 }
1133 }
1134
1135 int unique_verts = foundVerts.size();
1136 int unique_edges = foundEdges.size();
1137 int unique_faces = foundFaces.size();
1138
1139 bool verbose = m_session->DefinesCmdLineArgument("verbose");
1140
1141 // Now construct temporary GS objects. These will be used to
1142 // populate the arrays tmp3 and tmp4 with the multiplicity of
1143 // the vertices and edges respectively to identify those
1144 // vertices and edges which are located on partition boundary.
1145 Array<OneD, long> vertArray(unique_verts, &procVerts[0]);
1146 Gs::gs_data *tmp1 = Gs::Init(vertArray, vRowComm, verbose);
1147 Array<OneD, NekDouble> tmp4(unique_verts, 1.0);
1148 Array<OneD, NekDouble> tmp5(unique_edges, 1.0);
1149 Array<OneD, NekDouble> tmp6(unique_faces, 1.0);
1150 Gs::Gather(tmp4, Gs::gs_add, tmp1);
1151 Gs::Finalise(tmp1);
1152
1153 if (unique_edges > 0)
1154 {
1155 Array<OneD, long> edgeArray(unique_edges, &procEdges[0]);
1156 Gs::gs_data *tmp2 = Gs::Init(edgeArray, vRowComm, verbose);
1157 Gs::Gather(tmp5, Gs::gs_add, tmp2);
1158 Gs::Finalise(tmp2);
1159 }
1160
1161 if (unique_faces > 0)
1162 {
1163 Array<OneD, long> faceArray(unique_faces, &procFaces[0]);
1164 Gs::gs_data *tmp3 = Gs::Init(faceArray, vRowComm, verbose);
1165 Gs::Gather(tmp6, Gs::gs_add, tmp3);
1166 Gs::Finalise(tmp3);
1167 }
1168
1169 // Finally, fill the partVerts set with all non-Dirichlet
1170 // vertices which lie on a partition boundary.
1171 for (i = 0; i < unique_verts; ++i)
1172 {
1173 if (tmp4[i] > 1.0)
1174 {
1175 if (graph[0].count(procVerts[i] - 1) == 0)
1176 {
1177 partVerts.insert(tempGraph[0][procVerts[i] - 1]);
1178 }
1179 }
1180 }
1181
1182 for (i = 0; i < unique_edges; ++i)
1183 {
1184 if (tmp5[i] > 1.0)
1185 {
1186 if (graph[1].count(procEdges[i] - 1) == 0)
1187 {
1188 partVerts.insert(tempGraph[1][procEdges[i] - 1]);
1189 }
1190 }
1191 }
1192
1193 for (i = 0; i < unique_faces; ++i)
1194 {
1195 if (tmp6[i] > 1.0)
1196 {
1197 if (graph[2].count(procFaces[i] - 1) == 0)
1198 {
1199 partVerts.insert(tempGraph[2][procFaces[i] - 1]);
1200 }
1201 }
1202 }
1203
1204 // Now fill with all vertices on periodic BCs
1205 for (auto &pIt : periodicVerts)
1206 {
1207 if (graph[0].count(pIt.first) == 0)
1208 {
1209 partVerts.insert(tempGraph[0][pIt.first]);
1210 }
1211 }
1212 for (auto &pIt : periodicEdges)
1213 {
1214 if (graph[1].count(pIt.first) == 0)
1215 {
1216 partVerts.insert(tempGraph[1][pIt.first]);
1217 }
1218 }
1219 for (auto &pIt : periodicFaces)
1220 {
1221 if (graph[2].count(pIt.first) == 0)
1222 {
1223 partVerts.insert(tempGraph[2][pIt.first]);
1224 }
1225 }
1226 }
1227
1228 int nGraphVerts = tempGraphVertId;
1229 Array<OneD, int> perm(nGraphVerts);
1230 Array<OneD, int> iperm(nGraphVerts);
1231
1232 if (nGraphVerts)
1233 {
1234 switch (m_solnType)
1235 {
1236 case eDirectFullMatrix:
1237 case eIterativeFull:
1239 case ePETScStaticCond:
1240 case ePETScFullMatrix:
1241 case eXxtFullMatrix:
1242 case eXxtStaticCond:
1243 {
1244 NoReordering(boostGraphObj, perm, iperm);
1245 break;
1246 }
1247
1248 case eDirectStaticCond:
1249 {
1250 CuthillMckeeReordering(boostGraphObj, perm, iperm);
1251 break;
1252 }
1253
1258 {
1259 MultiLevelBisectionReordering(boostGraphObj, perm, iperm,
1260 bottomUpGraph, partVerts,
1261 mdswitch);
1262 break;
1263 }
1264 default:
1265 {
1266 ASSERTL0(false,
1267 "Unrecognised solution type: " +
1268 std::string(GlobalSysSolnTypeMap[m_solnType]));
1269 }
1270 }
1271 }
1272
1273 // For parallel multi-level static condensation determine the lowest
1274 // static condensation level amongst processors.
1279 bottomUpGraph)
1280 {
1281 m_lowestStaticCondLevel = bottomUpGraph->GetNlevels() - 1;
1283 }
1284 else
1285 {
1287 }
1288
1289 /**
1290 * STEP 4: Fill the #graph[0] and
1291 * #graph[1] with the optimal ordering from boost.
1292 */
1293 for (auto &mapIt : tempGraph[0])
1294 {
1295 graph[0][mapIt.first] = iperm[mapIt.second] + graphVertId;
1296 }
1297 for (auto &mapIt : tempGraph[1])
1298 {
1299 graph[1][mapIt.first] = iperm[mapIt.second] + graphVertId;
1300 }
1301 for (auto &mapIt : tempGraph[2])
1302 {
1303 graph[2][mapIt.first] = iperm[mapIt.second] + graphVertId;
1304 }
1305
1306 return nGraphVerts;
1307}
int m_numNonDirVertexModes
Number of non Dirichlet vertex modes.
int m_numNonDirEdges
Number of Dirichlet edges.
Array< OneD, int > m_extraDirEdges
Extra dirichlet edges in parallel.
int m_numNonDirFaceModes
Number of non Dirichlet face modes.
int m_numNonDirEdgeModes
Number of non Dirichlet edge modes.
int m_numDirEdges
Number of Dirichlet edges.
int m_numDirFaces
Number of Dirichlet faces.
int m_numNonDirFaces
Number of Dirichlet faces.
int m_lowestStaticCondLevel
Lowest static condensation level.
int m_numLocalDirBndCoeffs
Number of Local Dirichlet Boundary Coefficients.
bool m_systemSingular
Flag indicating if the system is singular or not.
@ gs_add
Definition GsLib.hpp:60
void NoReordering(const BoostGraph &graph, Array< OneD, int > &perm, Array< OneD, int > &iperm)
void CuthillMckeeReordering(const BoostGraph &graph, Array< OneD, int > &perm, Array< OneD, int > &iperm)
void MultiLevelBisectionReordering(const BoostGraph &graph, Array< OneD, int > &perm, Array< OneD, int > &iperm, BottomUpSubStructuredGraphSharedPtr &substructgraph, std::set< int > partVerts, int mdswitch)
const char *const GlobalSysSolnTypeMap[]
T Vsum(int n, const T *x, const int incx)
Subtract return sum(x)
Definition Vmath.hpp:608
int Imax(int n, const T *x, const int incx)
Return the index of the maximum element in x.
Definition Vmath.hpp:623

References ASSERTL0, Nektar::MultiRegions::CuthillMckeeReordering(), Nektar::MultiRegions::eDirectFullMatrix, Nektar::MultiRegions::eDirectMultiLevelStaticCond, Nektar::MultiRegions::eDirectStaticCond, Nektar::SpatialDomains::eDirichlet, Nektar::MultiRegions::eIterativeFull, Nektar::MultiRegions::eIterativeMultiLevelStaticCond, Nektar::MultiRegions::eIterativeStaticCond, Nektar::SpatialDomains::eNeumann, Nektar::SpatialDomains::ePeriodic, Nektar::MultiRegions::ePETScFullMatrix, Nektar::MultiRegions::ePETScMultiLevelStaticCond, Nektar::MultiRegions::ePETScStaticCond, Nektar::MultiRegions::eXxtFullMatrix, Nektar::MultiRegions::eXxtMultiLevelStaticCond, Nektar::MultiRegions::eXxtStaticCond, Gs::Finalise(), Gs::Gather(), Nektar::MultiRegions::ExpList::GetExp(), Nektar::LocalRegions::Expansion::GetGeom(), Nektar::StdRegions::StdExpansion::GetTraceNcoeffs(), Nektar::SpatialDomains::Geometry::GetVid(), Nektar::MultiRegions::GlobalSysSolnTypeMap, Gs::gs_add, Vmath::Imax(), Gs::Init(), Nektar::MultiRegions::AssemblyMap::m_comm, m_extraDirEdges, Nektar::MultiRegions::AssemblyMap::m_lowestStaticCondLevel, m_numDirEdges, m_numDirFaces, Nektar::MultiRegions::AssemblyMap::m_numLocalBndCoeffs, m_numLocalBndCondCoeffs, Nektar::MultiRegions::AssemblyMap::m_numLocalDirBndCoeffs, m_numNonDirEdgeModes, m_numNonDirEdges, m_numNonDirFaceModes, m_numNonDirFaces, m_numNonDirVertexModes, Nektar::MultiRegions::AssemblyMap::m_session, Nektar::MultiRegions::AssemblyMap::m_solnType, Nektar::MultiRegions::AssemblyMap::m_systemSingular, tinysimd::min(), Nektar::MultiRegions::MultiLevelBisectionReordering(), Nektar::MultiRegions::NoReordering(), Nektar::LibUtilities::ReduceMax, Nektar::LibUtilities::ReduceMin, Nektar::LibUtilities::ReduceSum, and Vmath::Vsum().

Referenced by AssemblyMapCG(), and Nektar::CoupledLocalToGlobalC0ContMap::CoupledLocalToGlobalC0ContMap().

◆ GetCopyLocalDirDofs()

std::set< ExtraDirDof > & Nektar::MultiRegions::AssemblyMapCG::GetCopyLocalDirDofs ( )
inline

Definition at line 94 of file AssemblyMapCG.h.

95 {
96 return m_copyLocalDirDofs;
97 }

References m_copyLocalDirDofs.

◆ GetParallelDirBndSign()

std::set< int > & Nektar::MultiRegions::AssemblyMapCG::GetParallelDirBndSign ( )
inline

Definition at line 99 of file AssemblyMapCG.h.

100 {
102 }

References m_parallelDirBndSign.

◆ SetUpUniversalC0ContMap()

void Nektar::MultiRegions::AssemblyMapCG::SetUpUniversalC0ContMap ( const ExpList locExp,
const PeriodicMap perVerts = NullPeriodicMap,
const PeriodicMap perEdges = NullPeriodicMap,
const PeriodicMap perFaces = NullPeriodicMap 
)
protected

Sets up the global to universal mapping of degrees of freedom across processors.

Definition at line 2313 of file AssemblyMapCG.cpp.

2317{
2319 int nVert = 0;
2320 int nEdge = 0;
2321 int nFace = 0;
2322 int maxEdgeDof = 0;
2323 int maxFaceDof = 0;
2324 int maxIntDof = 0;
2325 int dof = 0;
2326 int cnt;
2327 int i, j, k, l;
2328 int meshVertId;
2329 int meshEdgeId;
2330 int meshFaceId;
2331 int elementId;
2332 int vGlobalId;
2333 int maxBndGlobalId = 0;
2334 StdRegions::Orientation edgeOrient;
2335 StdRegions::Orientation faceOrient;
2336 Array<OneD, unsigned int> edgeInteriorMap;
2337 Array<OneD, int> edgeInteriorSign;
2338 Array<OneD, unsigned int> faceInteriorMap;
2339 Array<OneD, int> faceInteriorSign;
2340 Array<OneD, unsigned int> interiorMap;
2341
2342 const LocalRegions::ExpansionVector &locExpVector = *(locExp.GetExp());
2343 LibUtilities::CommSharedPtr vRowComm = m_comm->GetRowComm();
2344 const bool verbose = locExp.GetSession()->DefinesCmdLineArgument("verbose");
2345
2353
2354 // Loop over all the elements in the domain to gather mesh data
2355 for (i = 0; i < locExpVector.size(); ++i)
2356 {
2357 exp = locExpVector[i];
2358
2359 int nv = exp->GetNverts();
2360 int ne = exp->GetGeom()->GetNumEdges();
2361 int nf = exp->GetGeom()->GetNumFaces();
2362
2363 nVert += nv;
2364 nEdge += ne;
2365 nFace += nf;
2366
2367 // Loop over all edges (and vertices) of element i
2368 for (j = 0; j < ne; ++j)
2369 {
2370 if (nf)
2371 {
2372 dof =
2373 exp->as<LocalRegions::Expansion3D>()->GetEdgeNcoeffs(j) - 2;
2374 }
2375 else
2376 {
2377 dof = exp->GetTraceNcoeffs(j) - 2;
2378 }
2379
2380 maxEdgeDof = (dof > maxEdgeDof ? dof : maxEdgeDof);
2381 }
2382 for (j = 0; j < nf; ++j)
2383 {
2384 dof = exp->GetTraceIntNcoeffs(j);
2385 maxFaceDof = (dof > maxFaceDof ? dof : maxFaceDof);
2386 }
2387 exp->GetInteriorMap(interiorMap);
2388 dof = interiorMap.size();
2389 maxIntDof = (dof > maxIntDof ? dof : maxIntDof);
2390 }
2391
2392 // Tell other processes about how many dof we have
2393 vRowComm->AllReduce(nVert, LibUtilities::ReduceSum);
2394 vRowComm->AllReduce(nEdge, LibUtilities::ReduceSum);
2395 vRowComm->AllReduce(nFace, LibUtilities::ReduceSum);
2396 vRowComm->AllReduce(maxEdgeDof, LibUtilities::ReduceMax);
2397 vRowComm->AllReduce(maxFaceDof, LibUtilities::ReduceMax);
2398 vRowComm->AllReduce(maxIntDof, LibUtilities::ReduceMax);
2399
2400 // Assemble global to universal mapping for this process
2401 for (i = 0; i < locExpVector.size(); ++i)
2402 {
2403 exp = locExpVector[i];
2404 cnt = locExp.GetCoeff_Offset(i);
2405
2406 int nf = exp->GetGeom()->GetNumFaces();
2407
2408 // Loop over all vertices of element i
2409 for (j = 0; j < exp->GetNverts(); ++j)
2410 {
2411 meshVertId = exp->GetGeom()->GetVid(j);
2412 vGlobalId = m_localToGlobalMap[cnt + exp->GetVertexMap(j)];
2413
2414 auto pIt = perVerts.find(meshVertId);
2415 if (pIt != perVerts.end())
2416 {
2417 for (k = 0; k < pIt->second.size(); ++k)
2418 {
2419 meshVertId = min(meshVertId, pIt->second[k].id);
2420 }
2421 }
2422
2423 m_globalToUniversalMap[vGlobalId] = meshVertId + 1;
2424 m_globalToUniversalBndMap[vGlobalId] =
2425 m_globalToUniversalMap[vGlobalId];
2426 maxBndGlobalId =
2427 (vGlobalId > maxBndGlobalId ? vGlobalId : maxBndGlobalId);
2428 }
2429
2430 // Loop over all edges of element i
2431 for (j = 0; j < exp->GetGeom()->GetNumEdges(); ++j)
2432 {
2433 meshEdgeId = exp->GetGeom()->GetEid(j);
2434 auto pIt = perEdges.find(meshEdgeId);
2435 edgeOrient = exp->GetGeom()->GetEorient(j);
2436
2437 if (pIt != perEdges.end())
2438 {
2439 pair<int, StdRegions::Orientation> idOrient =
2440 DeterminePeriodicEdgeOrientId(meshEdgeId, edgeOrient,
2441 pIt->second);
2442 meshEdgeId = idOrient.first;
2443 edgeOrient = idOrient.second;
2444 }
2445
2446 if (nf) // 3D version
2447 {
2448 exp->as<LocalRegions::Expansion3D>()
2449 ->GetEdgeInteriorToElementMap(j, edgeInteriorMap,
2450 edgeInteriorSign, edgeOrient);
2451 dof =
2452 exp->as<LocalRegions::Expansion3D>()->GetEdgeNcoeffs(j) - 2;
2453 }
2454 else // 2D version
2455 {
2456 exp->GetTraceInteriorToElementMap(j, edgeInteriorMap,
2457 edgeInteriorSign, edgeOrient);
2458 dof = exp->GetTraceNcoeffs(j) - 2;
2459 }
2460
2461 // Set the global DOF's for the interior modes of edge j
2462 // for varP, ignore modes with sign == 0
2463 for (k = 0, l = 0; k < dof; ++k)
2464 {
2465 if (m_signChange)
2466 {
2467 if (m_localToGlobalSign[cnt + edgeInteriorMap[k]] == 0)
2468 {
2469 continue;
2470 }
2471 }
2472 vGlobalId = m_localToGlobalMap[cnt + edgeInteriorMap[k]];
2473 m_globalToUniversalMap[vGlobalId] =
2474 nVert + meshEdgeId * maxEdgeDof + l + 1;
2475 m_globalToUniversalBndMap[vGlobalId] =
2476 m_globalToUniversalMap[vGlobalId];
2477 maxBndGlobalId =
2478 (vGlobalId > maxBndGlobalId ? vGlobalId : maxBndGlobalId);
2479 l++;
2480 }
2481 }
2482
2483 // Loop over all faces of element i
2484 for (j = 0; j < exp->GetGeom()->GetNumFaces(); ++j)
2485 {
2486 faceOrient = exp->GetGeom()->GetForient(j);
2487
2488 meshFaceId = exp->GetGeom()->GetFid(j);
2489
2490 auto pIt = perFaces.find(meshFaceId);
2491 if (pIt != perFaces.end())
2492 {
2493 if (meshFaceId == min(meshFaceId, pIt->second[0].id))
2494 {
2495 faceOrient = DeterminePeriodicFaceOrient(
2496 faceOrient, pIt->second[0].orient);
2497 }
2498 meshFaceId = min(meshFaceId, pIt->second[0].id);
2499 }
2500
2501 exp->GetTraceInteriorToElementMap(j, faceInteriorMap,
2502 faceInteriorSign, faceOrient);
2503 dof = exp->GetTraceIntNcoeffs(j);
2504
2505 for (k = 0, l = 0; k < dof; ++k)
2506 {
2507 if (m_signChange)
2508 {
2509 if (m_localToGlobalSign[cnt + faceInteriorMap[k]] == 0)
2510 {
2511 continue;
2512 }
2513 }
2514 vGlobalId = m_localToGlobalMap[cnt + faceInteriorMap[k]];
2515 m_globalToUniversalMap[vGlobalId] = nVert + nEdge * maxEdgeDof +
2516 meshFaceId * maxFaceDof +
2517 l + 1;
2518 m_globalToUniversalBndMap[vGlobalId] =
2519 m_globalToUniversalMap[vGlobalId];
2520
2521 maxBndGlobalId =
2522 (vGlobalId > maxBndGlobalId ? vGlobalId : maxBndGlobalId);
2523 l++;
2524 }
2525 }
2526
2527 // Add interior DOFs to complete universal numbering
2528 exp->GetInteriorMap(interiorMap);
2529 dof = interiorMap.size();
2530 elementId = (exp->GetGeom())->GetGlobalID();
2531 for (k = 0; k < dof; ++k)
2532 {
2533 vGlobalId = m_localToGlobalMap[cnt + interiorMap[k]];
2534 m_globalToUniversalMap[vGlobalId] = nVert + nEdge * maxEdgeDof +
2535 nFace * maxFaceDof +
2536 elementId * maxIntDof + k + 1;
2537 }
2538 }
2539
2540 // Set up the GSLib universal assemble mapping
2541 // Internal DOF do not participate in any data
2542 // exchange, so we keep these set to the special GSLib id=0 so
2543 // they are ignored.
2547 for (unsigned int i = 0; i < m_numGlobalBndCoeffs; ++i)
2548 {
2549 tmp[i] = m_globalToUniversalMap[i];
2550 }
2551
2552 m_gsh = Gs::Init(tmp, vRowComm, verbose);
2553 m_bndGsh = Gs::Init(tmp2, vRowComm, verbose);
2554 Gs::Unique(tmp, vRowComm);
2555 for (unsigned int i = 0; i < m_numGlobalCoeffs; ++i)
2556 {
2557 m_globalToUniversalMapUnique[i] = (tmp[i] >= 0 ? 1 : 0);
2558 }
2559 for (unsigned int i = 0; i < m_numGlobalBndCoeffs; ++i)
2560 {
2561 m_globalToUniversalBndMapUnique[i] = (tmp2[i] >= 0 ? 1 : 0);
2562 }
2563}
Array< OneD, int > m_globalToUniversalMapUnique
Integer map of unique process coeffs to universal space (signed)
Array< OneD, int > m_globalToUniversalBndMap
Integer map of process coeffs to universal space.
Array< OneD, int > m_globalToUniversalBndMapUnique
Integer map of unique process coeffs to universal space (signed)
static void Unique(const Nektar::Array< OneD, long > &pId, const LibUtilities::CommSharedPtr &pComm)
Updates pId to negate all-but-one references to each universal ID.
Definition GsLib.hpp:225
void Zero(int n, T *x, const int incx)
Zero vector.
Definition Vmath.hpp:273

References Nektar::MultiRegions::DeterminePeriodicEdgeOrientId(), Nektar::MultiRegions::DeterminePeriodicFaceOrient(), Nektar::MultiRegions::ExpList::GetCoeff_Offset(), Nektar::MultiRegions::ExpList::GetExp(), Nektar::MultiRegions::ExpList::GetSession(), Nektar::StdRegions::StdExpansion::GetTraceInteriorToElementMap(), Nektar::StdRegions::StdExpansion::GetTraceNcoeffs(), Gs::Init(), Nektar::MultiRegions::AssemblyMap::m_bndGsh, Nektar::MultiRegions::AssemblyMap::m_comm, Nektar::MultiRegions::AssemblyMap::m_globalToUniversalBndMap, Nektar::MultiRegions::AssemblyMap::m_globalToUniversalBndMapUnique, m_globalToUniversalMap, m_globalToUniversalMapUnique, Nektar::MultiRegions::AssemblyMap::m_gsh, m_localToGlobalMap, m_localToGlobalSign, Nektar::MultiRegions::AssemblyMap::m_numGlobalBndCoeffs, Nektar::MultiRegions::AssemblyMap::m_numGlobalCoeffs, Nektar::MultiRegions::AssemblyMap::m_signChange, tinysimd::min(), Nektar::LibUtilities::ReduceMax, Nektar::LibUtilities::ReduceSum, Gs::Unique(), and Vmath::Zero().

Referenced by AssemblyMapCG().

◆ v_Assemble() [1/2]

void Nektar::MultiRegions::AssemblyMapCG::v_Assemble ( const Array< OneD, const NekDouble > &  loc,
Array< OneD, NekDouble > &  global 
) const
overrideprotectedvirtual

Reimplemented from Nektar::MultiRegions::AssemblyMap.

Definition at line 2856 of file AssemblyMapCG.cpp.

2858{
2859 Array<OneD, const NekDouble> local;
2860 if (global.data() == loc.data())
2861 {
2862 local = Array<OneD, NekDouble>(m_numLocalCoeffs, loc.data());
2863 }
2864 else
2865 {
2866 local = loc; // create reference
2867 }
2868
2869 Vmath::Zero(m_numGlobalCoeffs, global.data(), 1);
2870
2871 if (m_signChange)
2872 {
2874 m_localToGlobalMap.data(), global.data());
2875 }
2876 else
2877 {
2878 Vmath::Assmb(m_numLocalCoeffs, local.data(), m_localToGlobalMap.data(),
2879 global.data());
2880 }
2881 UniversalAssemble(global);
2882}
void UniversalAssemble(Array< OneD, NekDouble > &pGlobal) const
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

References Vmath::Assmb(), m_localToGlobalMap, m_localToGlobalSign, Nektar::MultiRegions::AssemblyMap::m_numGlobalCoeffs, Nektar::MultiRegions::AssemblyMap::m_numLocalCoeffs, Nektar::MultiRegions::AssemblyMap::m_signChange, Nektar::MultiRegions::AssemblyMap::UniversalAssemble(), and Vmath::Zero().

◆ v_Assemble() [2/2]

void Nektar::MultiRegions::AssemblyMapCG::v_Assemble ( const NekVector< NekDouble > &  loc,
NekVector< NekDouble > &  global 
) const
overrideprotectedvirtual

Reimplemented from Nektar::MultiRegions::AssemblyMap.

Definition at line 2884 of file AssemblyMapCG.cpp.

2886{
2887 Assemble(loc.GetPtr(), global.GetPtr());
2888}
void Assemble(const Array< OneD, const NekDouble > &loc, Array< OneD, NekDouble > &global) const
Array< OneD, DataType > & GetPtr()

References Nektar::MultiRegions::AssemblyMap::Assemble(), and Nektar::NekVector< DataType >::GetPtr().

◆ v_GetExtraDirEdges()

const Array< OneD, const int > & Nektar::MultiRegions::AssemblyMapCG::v_GetExtraDirEdges ( )
overrideprotectedvirtual

Reimplemented from Nektar::MultiRegions::AssemblyMap.

Definition at line 2944 of file AssemblyMapCG.cpp.

2945{
2946 return m_extraDirEdges;
2947}

References m_extraDirEdges.

◆ v_GetFullSystemBandWidth()

int Nektar::MultiRegions::AssemblyMapCG::v_GetFullSystemBandWidth ( ) const
overrideprotectedvirtual

Reimplemented from Nektar::MultiRegions::AssemblyMap.

Definition at line 2904 of file AssemblyMapCG.cpp.

2905{
2906 return m_fullSystemBandWidth;
2907}

References m_fullSystemBandWidth.

◆ v_GetGlobalToUniversalMap() [1/2]

const Array< OneD, const int > & Nektar::MultiRegions::AssemblyMapCG::v_GetGlobalToUniversalMap ( void  )
overrideprotectedvirtual

Reimplemented from Nektar::MultiRegions::AssemblyMap.

Definition at line 2765 of file AssemblyMapCG.cpp.

2766{
2768}

References m_globalToUniversalMap.

◆ v_GetGlobalToUniversalMap() [2/2]

int Nektar::MultiRegions::AssemblyMapCG::v_GetGlobalToUniversalMap ( const int  i) const
overrideprotectedvirtual

Reimplemented from Nektar::MultiRegions::AssemblyMap.

Definition at line 2750 of file AssemblyMapCG.cpp.

2751{
2752 return m_globalToUniversalMap[i];
2753}

References m_globalToUniversalMap.

◆ v_GetGlobalToUniversalMapUnique() [1/2]

const Array< OneD, const int > & Nektar::MultiRegions::AssemblyMapCG::v_GetGlobalToUniversalMapUnique ( void  )
overrideprotectedvirtual

Reimplemented from Nektar::MultiRegions::AssemblyMap.

Definition at line 2770 of file AssemblyMapCG.cpp.

2772{
2774}

References m_globalToUniversalMapUnique.

◆ v_GetGlobalToUniversalMapUnique() [2/2]

int Nektar::MultiRegions::AssemblyMapCG::v_GetGlobalToUniversalMapUnique ( const int  i) const
overrideprotectedvirtual

Reimplemented from Nektar::MultiRegions::AssemblyMap.

Definition at line 2755 of file AssemblyMapCG.cpp.

2756{
2758}

References m_globalToUniversalMapUnique.

◆ v_GetLocalToGlobalMap() [1/2]

const Array< OneD, const int > & Nektar::MultiRegions::AssemblyMapCG::v_GetLocalToGlobalMap ( void  )
overrideprotectedvirtual

Reimplemented from Nektar::MultiRegions::AssemblyMap.

Definition at line 2760 of file AssemblyMapCG.cpp.

2761{
2762 return m_localToGlobalMap;
2763}

References m_localToGlobalMap.

◆ v_GetLocalToGlobalMap() [2/2]

int Nektar::MultiRegions::AssemblyMapCG::v_GetLocalToGlobalMap ( const int  i) const
overrideprotectedvirtual

Reimplemented from Nektar::MultiRegions::AssemblyMap.

Definition at line 2745 of file AssemblyMapCG.cpp.

2746{
2747 return m_localToGlobalMap[i];
2748}

References m_localToGlobalMap.

◆ v_GetLocalToGlobalSign() [1/2]

const Array< OneD, NekDouble > & Nektar::MultiRegions::AssemblyMapCG::v_GetLocalToGlobalSign ( ) const
overrideprotectedvirtual

Reimplemented from Nektar::MultiRegions::AssemblyMap.

Definition at line 2788 of file AssemblyMapCG.cpp.

2789{
2790 return m_localToGlobalSign;
2791}

References m_localToGlobalSign.

◆ v_GetLocalToGlobalSign() [2/2]

NekDouble Nektar::MultiRegions::AssemblyMapCG::v_GetLocalToGlobalSign ( const int  i) const
overrideprotectedvirtual

Reimplemented from Nektar::MultiRegions::AssemblyMap.

Definition at line 2776 of file AssemblyMapCG.cpp.

2777{
2778 if (m_signChange)
2779 {
2780 return m_localToGlobalSign[i];
2781 }
2782 else
2783 {
2784 return 1.0;
2785 }
2786}

References m_localToGlobalSign, and Nektar::MultiRegions::AssemblyMap::m_signChange.

◆ v_GetNumDirEdges()

int Nektar::MultiRegions::AssemblyMapCG::v_GetNumDirEdges ( ) const
overrideprotectedvirtual

Reimplemented from Nektar::MultiRegions::AssemblyMap.

Definition at line 2924 of file AssemblyMapCG.cpp.

2925{
2926 return m_numDirEdges;
2927}

References m_numDirEdges.

◆ v_GetNumDirFaces()

int Nektar::MultiRegions::AssemblyMapCG::v_GetNumDirFaces ( ) const
overrideprotectedvirtual

Reimplemented from Nektar::MultiRegions::AssemblyMap.

Definition at line 2929 of file AssemblyMapCG.cpp.

2930{
2931 return m_numDirFaces;
2932}

References m_numDirFaces.

◆ v_GetNumNonDirEdgeModes()

int Nektar::MultiRegions::AssemblyMapCG::v_GetNumNonDirEdgeModes ( ) const
overrideprotectedvirtual

Reimplemented from Nektar::MultiRegions::AssemblyMap.

Definition at line 2914 of file AssemblyMapCG.cpp.

2915{
2916 return m_numNonDirEdgeModes;
2917}

References m_numNonDirEdgeModes.

◆ v_GetNumNonDirEdges()

int Nektar::MultiRegions::AssemblyMapCG::v_GetNumNonDirEdges ( ) const
overrideprotectedvirtual

Reimplemented from Nektar::MultiRegions::AssemblyMap.

Definition at line 2934 of file AssemblyMapCG.cpp.

2935{
2936 return m_numNonDirEdges;
2937}

References m_numNonDirEdges.

◆ v_GetNumNonDirFaceModes()

int Nektar::MultiRegions::AssemblyMapCG::v_GetNumNonDirFaceModes ( ) const
overrideprotectedvirtual

Reimplemented from Nektar::MultiRegions::AssemblyMap.

Definition at line 2919 of file AssemblyMapCG.cpp.

2920{
2921 return m_numNonDirFaceModes;
2922}

References m_numNonDirFaceModes.

◆ v_GetNumNonDirFaces()

int Nektar::MultiRegions::AssemblyMapCG::v_GetNumNonDirFaces ( ) const
overrideprotectedvirtual

Reimplemented from Nektar::MultiRegions::AssemblyMap.

Definition at line 2939 of file AssemblyMapCG.cpp.

2940{
2941 return m_numNonDirFaces;
2942}

References m_numNonDirFaces.

◆ v_GetNumNonDirVertexModes()

int Nektar::MultiRegions::AssemblyMapCG::v_GetNumNonDirVertexModes ( ) const
overrideprotectedvirtual

Reimplemented from Nektar::MultiRegions::AssemblyMap.

Definition at line 2909 of file AssemblyMapCG.cpp.

2910{
2912}

References m_numNonDirVertexModes.

◆ v_GlobalToLocal() [1/2]

void Nektar::MultiRegions::AssemblyMapCG::v_GlobalToLocal ( const Array< OneD, const NekDouble > &  global,
Array< OneD, NekDouble > &  loc 
) const
overrideprotectedvirtual

Reimplemented from Nektar::MultiRegions::AssemblyMap.

Definition at line 2825 of file AssemblyMapCG.cpp.

2827{
2828 Array<OneD, const NekDouble> glo;
2829 if (global.data() == loc.data())
2830 {
2831 glo = Array<OneD, NekDouble>(m_numGlobalCoeffs, global.data());
2832 }
2833 else
2834 {
2835 glo = global; // create reference
2836 }
2837
2838 if (m_signChange)
2839 {
2841 m_localToGlobalMap.data(), loc.data());
2842 }
2843 else
2844 {
2846 loc.data());
2847 }
2848}
void Gathr(I n, const T *x, const I *y, T *z)
Gather vector z[i] = x[y[i]].
Definition Vmath.hpp:507

References Vmath::Gathr(), m_localToGlobalMap, m_localToGlobalSign, Nektar::MultiRegions::AssemblyMap::m_numGlobalCoeffs, Nektar::MultiRegions::AssemblyMap::m_numLocalCoeffs, and Nektar::MultiRegions::AssemblyMap::m_signChange.

◆ v_GlobalToLocal() [2/2]

void Nektar::MultiRegions::AssemblyMapCG::v_GlobalToLocal ( const NekVector< NekDouble > &  global,
NekVector< NekDouble > &  loc 
) const
overrideprotectedvirtual

Reimplemented from Nektar::MultiRegions::AssemblyMap.

Definition at line 2850 of file AssemblyMapCG.cpp.

2852{
2853 GlobalToLocal(global.GetPtr(), loc.GetPtr());
2854}
void GlobalToLocal(const Array< OneD, const NekDouble > &global, Array< OneD, NekDouble > &loc) const

References Nektar::NekVector< DataType >::GetPtr(), and Nektar::MultiRegions::AssemblyMap::GlobalToLocal().

◆ v_LinearSpaceMap()

AssemblyMapSharedPtr Nektar::MultiRegions::AssemblyMapCG::v_LinearSpaceMap ( const ExpList locexp,
GlobalSysSolnType  solnType 
)
overrideprotectedvirtual

Construct an AssemblyMapCG object which corresponds to the linear space of the current object.

This function is used to create a linear-space assembly map, which is then used in the linear space preconditioner in the conjugate gradient solve.

Reimplemented from Nektar::MultiRegions::AssemblyMap.

Definition at line 2573 of file AssemblyMapCG.cpp.

2575{
2576 AssemblyMapCGSharedPtr returnval;
2577
2578 int i, j;
2579 int nverts = 0;
2580 const std::shared_ptr<LocalRegions::ExpansionVector> exp = locexp.GetExp();
2581 int nelmts = exp->size();
2582 const bool verbose = locexp.GetSession()->DefinesCmdLineArgument("verbose");
2583
2584 // Get Default Map and turn off any searched values.
2586 m_session, locexp.GetComm());
2587 returnval->m_solnType = solnType;
2588 returnval->m_preconType = "Null";
2589 returnval->m_maxStaticCondLevel = 0;
2590 returnval->m_signChange = false;
2591 returnval->m_comm = m_comm;
2592
2593 // Count the number of vertices
2594 for (i = 0; i < nelmts; ++i)
2595 {
2596 nverts += (*exp)[i]->GetNverts();
2597 }
2598
2599 returnval->m_numLocalCoeffs = nverts;
2600 returnval->m_localToGlobalMap = Array<OneD, int>(nverts, -1);
2601
2602 // Store original global ids in this map
2603 returnval->m_localToGlobalBndMap = Array<OneD, int>(nverts, -1);
2604
2605 int cnt = 0;
2606 int cnt1 = 0;
2607 Array<OneD, int> GlobCoeffs(m_numGlobalCoeffs, -1);
2608
2609 // Set up local to global map;
2610 for (i = 0; i < nelmts; ++i)
2611 {
2612 for (j = 0; j < (*exp)[i]->GetNverts(); ++j)
2613 {
2614 returnval->m_localToGlobalMap[cnt] =
2615 returnval->m_localToGlobalBndMap[cnt] =
2616 m_localToGlobalMap[cnt1 + (*exp)[i]->GetVertexMap(j, true)];
2617 GlobCoeffs[returnval->m_localToGlobalMap[cnt]] = 1;
2618
2619 // Set up numLocalDirBndCoeffs
2620 if ((returnval->m_localToGlobalMap[cnt]) < m_numGlobalDirBndCoeffs)
2621 {
2622 returnval->m_numLocalDirBndCoeffs++;
2623 }
2624 cnt++;
2625 }
2626 cnt1 += (*exp)[i]->GetNcoeffs();
2627 }
2628
2629 cnt = 0;
2630 // Reset global numbering and count number of dofs
2631 for (i = 0; i < m_numGlobalCoeffs; ++i)
2632 {
2633 if (GlobCoeffs[i] != -1)
2634 {
2635 GlobCoeffs[i] = cnt++;
2636 }
2637 }
2638
2639 // Set up number of globalCoeffs;
2640 returnval->m_numGlobalCoeffs = cnt;
2641
2642 // Set up number of global Dirichlet boundary coefficients
2643 for (i = 0; i < m_numGlobalDirBndCoeffs; ++i)
2644 {
2645 if (GlobCoeffs[i] != -1)
2646 {
2647 returnval->m_numGlobalDirBndCoeffs++;
2648 }
2649 }
2650
2651 // Set up global to universal map
2652 if (m_globalToUniversalMap.size())
2653 {
2655 m_session->GetComm()->GetRowComm();
2656 int nglocoeffs = returnval->m_numGlobalCoeffs;
2657 returnval->m_globalToUniversalMap = Array<OneD, int>(nglocoeffs);
2658 returnval->m_globalToUniversalMapUnique = Array<OneD, int>(nglocoeffs);
2659
2660 // Reset local to global map and setup universal map
2661 for (i = 0; i < nverts; ++i)
2662 {
2663 cnt = returnval->m_localToGlobalMap[i];
2664 returnval->m_localToGlobalMap[i] = GlobCoeffs[cnt];
2665
2666 returnval->m_globalToUniversalMap[GlobCoeffs[cnt]] =
2668 }
2669
2670 Nektar::Array<OneD, long> tmp(nglocoeffs);
2671 Vmath::Zero(nglocoeffs, tmp, 1);
2672 for (unsigned int i = 0; i < nglocoeffs; ++i)
2673 {
2674 tmp[i] = returnval->m_globalToUniversalMap[i];
2675 }
2676 returnval->m_gsh = Gs::Init(tmp, vRowComm, verbose);
2677 Gs::Unique(tmp, vRowComm);
2678 for (unsigned int i = 0; i < nglocoeffs; ++i)
2679 {
2680 returnval->m_globalToUniversalMapUnique[i] = (tmp[i] >= 0 ? 1 : 0);
2681 }
2682 }
2683 else // not sure this option is ever needed.
2684 {
2685 for (i = 0; i < nverts; ++i)
2686 {
2687 cnt = returnval->m_localToGlobalMap[i];
2688 returnval->m_localToGlobalMap[i] = GlobCoeffs[cnt];
2689 }
2690 }
2691
2692 return returnval;
2693}
std::shared_ptr< AssemblyMapCG > AssemblyMapCGSharedPtr

References Nektar::MemoryManager< DataType >::AllocateSharedPtr(), Nektar::MultiRegions::ExpList::GetComm(), Nektar::MultiRegions::ExpList::GetExp(), Nektar::MultiRegions::ExpList::GetSession(), Gs::Init(), Nektar::MultiRegions::AssemblyMap::m_comm, m_globalToUniversalMap, m_localToGlobalMap, Nektar::MultiRegions::AssemblyMap::m_numGlobalCoeffs, Nektar::MultiRegions::AssemblyMap::m_numGlobalDirBndCoeffs, Nektar::MultiRegions::AssemblyMap::m_session, Gs::Unique(), and Vmath::Zero().

◆ v_LocalToGlobal()

void Nektar::MultiRegions::AssemblyMapCG::v_LocalToGlobal ( const Array< OneD, const NekDouble > &  loc,
Array< OneD, NekDouble > &  global,
bool  useComm 
) const
overrideprotectedvirtual

Reimplemented from Nektar::MultiRegions::AssemblyMap.

Definition at line 2793 of file AssemblyMapCG.cpp.

2796{
2797 Array<OneD, const NekDouble> local;
2798 if (global.data() == loc.data())
2799 {
2800 local = Array<OneD, NekDouble>(m_numLocalCoeffs, loc.data());
2801 }
2802 else
2803 {
2804 local = loc; // create reference
2805 }
2806
2807 if (m_signChange)
2808 {
2810 m_localToGlobalMap.data(), global.data());
2811 }
2812 else
2813 {
2814 Vmath::Scatr(m_numLocalCoeffs, local.data(), m_localToGlobalMap.data(),
2815 global.data());
2816 }
2817
2818 // ensure all values are unique by calling a max
2819 if (useComm)
2820 {
2821 Gs::Gather(global, Gs::gs_max, m_gsh);
2822 }
2823}
void Scatr(int n, const T *x, const int *y, T *z)
Scatter vector z[y[i]] = x[i].
Definition Vmath.hpp:539

References Gs::Gather(), Gs::gs_max, Nektar::MultiRegions::AssemblyMap::m_gsh, m_localToGlobalMap, m_localToGlobalSign, Nektar::MultiRegions::AssemblyMap::m_numLocalCoeffs, Nektar::MultiRegions::AssemblyMap::m_signChange, and Vmath::Scatr().

◆ v_UniversalAssemble() [1/2]

void Nektar::MultiRegions::AssemblyMapCG::v_UniversalAssemble ( Array< OneD, NekDouble > &  pGlobal) const
overrideprotectedvirtual

Reimplemented from Nektar::MultiRegions::AssemblyMap.

Definition at line 2890 of file AssemblyMapCG.cpp.

2891{
2892 Gs::Gather(pGlobal, Gs::gs_add, m_gsh);
2893}

References Gs::Gather(), Gs::gs_add, and Nektar::MultiRegions::AssemblyMap::m_gsh.

◆ v_UniversalAssemble() [2/2]

void Nektar::MultiRegions::AssemblyMapCG::v_UniversalAssemble ( Array< OneD, NekDouble > &  pGlobal,
int  offset 
) const
overrideprotectedvirtual

Reimplemented from Nektar::MultiRegions::AssemblyMap.

Definition at line 2895 of file AssemblyMapCG.cpp.

2897{
2898 Array<OneD, NekDouble> tmp(offset);
2899 Vmath::Vcopy(offset, pGlobal, 1, tmp, 1);
2900 UniversalAssemble(pGlobal);
2901 Vmath::Vcopy(offset, tmp, 1, pGlobal, 1);
2902}
void Vcopy(int n, const T *x, const int incx, T *y, const int incy)
Definition Vmath.hpp:825

References Nektar::MultiRegions::AssemblyMap::UniversalAssemble(), and Vmath::Vcopy().

Member Data Documentation

◆ m_copyLocalDirDofs

std::set<ExtraDirDof> Nektar::MultiRegions::AssemblyMapCG::m_copyLocalDirDofs
protected

Set indicating degrees of freedom which are Dirichlet but whose value is stored on another processor.

Definition at line 139 of file AssemblyMapCG.h.

Referenced by AssemblyMapCG(), and GetCopyLocalDirDofs().

◆ m_extraDirEdges

Array<OneD, int> Nektar::MultiRegions::AssemblyMapCG::m_extraDirEdges
protected

Extra dirichlet edges in parallel.

Definition at line 132 of file AssemblyMapCG.h.

Referenced by CreateGraph(), and v_GetExtraDirEdges().

◆ m_fullSystemBandWidth

int Nektar::MultiRegions::AssemblyMapCG::m_fullSystemBandWidth
protected

Bandwith of the full matrix system (no static condensation).

Definition at line 110 of file AssemblyMapCG.h.

Referenced by CalculateFullSystemBandWidth(), and v_GetFullSystemBandWidth().

◆ m_globalToUniversalMap

Array<OneD, int> Nektar::MultiRegions::AssemblyMapCG::m_globalToUniversalMap
protected

◆ m_globalToUniversalMapUnique

Array<OneD, int> Nektar::MultiRegions::AssemblyMapCG::m_globalToUniversalMapUnique
protected

Integer map of unique process coeffs to universal space (signed)

Definition at line 114 of file AssemblyMapCG.h.

Referenced by Nektar::CoupledAssemblyMap::CoupledAssemblyMap(), SetUpUniversalC0ContMap(), v_GetGlobalToUniversalMapUnique(), and v_GetGlobalToUniversalMapUnique().

◆ m_localToGlobalMap

Array<OneD, int> Nektar::MultiRegions::AssemblyMapCG::m_localToGlobalMap
protected

◆ m_localToGlobalSign

Array<OneD, NekDouble> Nektar::MultiRegions::AssemblyMapCG::m_localToGlobalSign
protected

◆ m_maxStaticCondLevel

int Nektar::MultiRegions::AssemblyMapCG::m_maxStaticCondLevel
protected

Maximum static condensation level.

Definition at line 136 of file AssemblyMapCG.h.

Referenced by AssemblyMapCG().

◆ m_numDirEdges

int Nektar::MultiRegions::AssemblyMapCG::m_numDirEdges
protected

Number of Dirichlet edges.

Definition at line 122 of file AssemblyMapCG.h.

Referenced by CreateGraph(), and v_GetNumDirEdges().

◆ m_numDirFaces

int Nektar::MultiRegions::AssemblyMapCG::m_numDirFaces
protected

Number of Dirichlet faces.

Definition at line 124 of file AssemblyMapCG.h.

Referenced by CreateGraph(), and v_GetNumDirFaces().

◆ m_numLocalBndCondCoeffs

int Nektar::MultiRegions::AssemblyMapCG::m_numLocalBndCondCoeffs
protected

Number of local boundary condition coefficients.

Definition at line 130 of file AssemblyMapCG.h.

Referenced by AssemblyMapCG(), and CreateGraph().

◆ m_numLocDirBndCondDofs

int Nektar::MultiRegions::AssemblyMapCG::m_numLocDirBndCondDofs
protected

Number of local boundary condition degrees of freedom.

Definition at line 134 of file AssemblyMapCG.h.

◆ m_numNonDirEdgeModes

int Nektar::MultiRegions::AssemblyMapCG::m_numNonDirEdgeModes
protected

Number of non Dirichlet edge modes.

Definition at line 118 of file AssemblyMapCG.h.

Referenced by CreateGraph(), and v_GetNumNonDirEdgeModes().

◆ m_numNonDirEdges

int Nektar::MultiRegions::AssemblyMapCG::m_numNonDirEdges
protected

Number of Dirichlet edges.

Definition at line 126 of file AssemblyMapCG.h.

Referenced by CreateGraph(), and v_GetNumNonDirEdges().

◆ m_numNonDirFaceModes

int Nektar::MultiRegions::AssemblyMapCG::m_numNonDirFaceModes
protected

Number of non Dirichlet face modes.

Definition at line 120 of file AssemblyMapCG.h.

Referenced by CreateGraph(), and v_GetNumNonDirFaceModes().

◆ m_numNonDirFaces

int Nektar::MultiRegions::AssemblyMapCG::m_numNonDirFaces
protected

Number of Dirichlet faces.

Definition at line 128 of file AssemblyMapCG.h.

Referenced by CreateGraph(), and v_GetNumNonDirFaces().

◆ m_numNonDirVertexModes

int Nektar::MultiRegions::AssemblyMapCG::m_numNonDirVertexModes
protected

Number of non Dirichlet vertex modes.

Definition at line 116 of file AssemblyMapCG.h.

Referenced by CreateGraph(), and v_GetNumNonDirVertexModes().

◆ m_parallelDirBndSign

std::set<int> Nektar::MultiRegions::AssemblyMapCG::m_parallelDirBndSign
protected

Set indicating the local coeffs just touching parallel dirichlet boundary that have a sign change.

Definition at line 142 of file AssemblyMapCG.h.

Referenced by AssemblyMapCG(), and GetParallelDirBndSign().