Nektar++
Public Member Functions | Static Public Member Functions | Static Public Attributes | Protected Member Functions | Protected Attributes | Private Member Functions | List of all members
Nektar::MultiRegions::PreconditionerBlock Class Reference

#include <PreconditionerBlock.h>

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

Public Member Functions

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

Static Public Member Functions

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

Static Public Attributes

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

Protected Member Functions

virtual void v_InitObject () override
 
virtual void v_DoPreconditioner (const Array< OneD, NekDouble > &pInput, Array< OneD, NekDouble > &pOutput) override
 Apply preconditioner to pInput and store the result in pOutput. More...
 
virtual void v_BuildPreconditioner () override
 
- Protected Member Functions inherited from Nektar::MultiRegions::Preconditioner
virtual DNekScalMatSharedPtr v_TransformedSchurCompl (int offset, int bndoffset, const std::shared_ptr< DNekScalMat > &loc_mat)
 Get block elemental transposed transformation matrix \(\mathbf{R}^{T}\). More...
 
virtual void v_DoPreconditionerWithNonVertOutput (const Array< OneD, NekDouble > &pInput, Array< OneD, NekDouble > &pOutput, const Array< OneD, NekDouble > &pNonVertOutput, Array< OneD, NekDouble > &pVertForce)
 Apply a preconditioner to the conjugate gradient method with an output for non-vertex degrees of freedom. More...
 
virtual void v_DoTransformBasisToLowEnergy (Array< OneD, NekDouble > &pInOut)
 Transform from original basis to low energy basis. More...
 
virtual void v_DoTransformCoeffsFromLowEnergy (Array< OneD, NekDouble > &pInOut)
 Transform from low energy coeffs to orignal basis. More...
 
virtual void v_DoTransformCoeffsToLowEnergy (const Array< OneD, NekDouble > &pInput, Array< OneD, NekDouble > &pOutput)
 Multiply by the block inverse transformation matrix. More...
 
virtual void v_DoTransformBasisFromLowEnergy (const Array< OneD, NekDouble > &pInput, Array< OneD, NekDouble > &pOutput)
 Multiply by the block transposed inverse transformation matrix. More...
 

Protected Attributes

bool m_isFull
 
DNekBlkMatSharedPtr m_blkMat
 
- Protected Attributes inherited from Nektar::MultiRegions::Preconditioner
const std::weak_ptr< GlobalLinSysm_linsys
 
PreconditionerType m_preconType
 
DNekMatSharedPtr m_preconditioner
 
std::weak_ptr< AssemblyMapm_locToGloMap
 
LibUtilities::CommSharedPtr m_comm
 

Private Member Functions

void BlockPreconditionerCG (void)
 Construct a block preconditioner from \(\mathbf{S}_{1}\) for the continuous Galerkin system. More...
 
void BlockPreconditionerHDG (void)
 Construct a block preconditioner for the hybridized discontinuous Galerkin system. More...
 

Detailed Description

Definition at line 50 of file PreconditionerBlock.h.

Constructor & Destructor Documentation

◆ PreconditionerBlock()

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

Definition at line 64 of file PreconditionerBlock.cpp.

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

◆ ~PreconditionerBlock()

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

Definition at line 73 of file PreconditionerBlock.h.

74  {
75  }

Member Function Documentation

◆ BlockPreconditionerCG()

void Nektar::MultiRegions::PreconditionerBlock::BlockPreconditionerCG ( void  )
private

Construct a block preconditioner from \(\mathbf{S}_{1}\) for the continuous Galerkin system.

The preconditioner for the statically-condensed system is defined as:

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

where \(\mathbf{S}_{1}\) is the local Schur complement matrix for each element and the subscript denotes the portion of the Schur complement associated with the vertex (vv), edge (eb) and face blocks (fb) respectively.

In case of the full system \(\mathbf{A}\), the preconditioner includes the interior blocks as well. The full block preconditioner is defined as:

\[\mathbf{M}^{-1}=\left[\begin{array}{cccc} \mathrm{Diag}[(\mathbf{A})_{vv}] & & & \\ & (\mathbf{A})_{eb} & & \\ & & (\mathbf{A})_{fb} & \\ & & & (\mathbf{A})_{int} \end{array}\right] \]

where the interior portion is added at the end following the ordering inside data structures.

Definition at line 126 of file PreconditionerBlock.cpp.

127 {
128  ExpListSharedPtr expList = m_linsys.lock()->GetLocMat().lock();
130  DNekScalBlkMatSharedPtr loc_mat;
131  DNekScalMatSharedPtr bnd_mat;
132 
133  int i, j, k, n, cnt, gId;
134  int meshVertId, meshEdgeId, meshFaceId;
135 
136  auto asmMap = m_locToGloMap.lock();
137 
138  const int nExp = expList->GetExpSize();
139  const int nDirBnd = asmMap->GetNumGlobalDirBndCoeffs();
140 
141  // Grab periodic geometry information.
142  PeriodicMap periodicVerts, periodicEdges, periodicFaces;
143  expList->GetPeriodicEntities(periodicVerts, periodicEdges, periodicFaces);
144 
145  // The vectors below are of size 3(+1) to have separate storage for
146  // vertices, edges and faces.
147  // For the full matrix approach additional storage for the
148  // interior matrices is required
149  int nStorage = m_isFull ? 4 : 3;
150 
151  // Maps from geometry ID to the matrix representing the extracted
152  // portion of S_1. For example idMats[2] folds the S_1 face blocks.
153  vector<map<int, vector<NekDouble>>> idMats(nStorage);
154 
155  // Maps from the global ID, as obtained from AssemblyMapCG's
156  // localToGlobalMap, to the geometry ID.
157  vector<map<int, int>> gidMeshIds(3);
158 
159  // Maps from the global ID to the number of degrees of freedom for
160  // this geometry object.
161  vector<map<int, int>> gidDofs(nStorage);
162 
163  // Array containing maximum information needed for the universal
164  // numbering later. For i = 0,1,2 for each geometry dimension:
165  //
166  // maxVertIds[2*i] = maximum geometry ID at dimension i
167  // maxVertIds[2*i+1] = maximum number of degrees of freedom for all
168  // elements of dimension i.
169  Array<OneD, int> maxVertIds(6, -1);
170 
171  // Figure out mapping from each elemental contribution to offset in
172  // (vert,edge,face) triples.
173  for (cnt = n = 0; n < nExp; ++n)
174  {
175  exp = expList->GetExp(n);
176 
177  // Grab reference to
178  // StaticCond: Local Schur complement matrix
179  // Full: Boundary and interior matrix
180  DNekScalMatSharedPtr schurMat;
181 
182  if (m_isFull)
183  {
184  // Get local matrix
185  auto tmpMat = m_linsys.lock()->GetBlock(n);
186 
187  // Get number of boundary dofs
188  int nBndDofs = exp->NumBndryCoeffs();
189  int nIntDofs = exp->GetNcoeffs() - nBndDofs;
190 
191  // Get boundary & interior maps
192  Array<OneD, unsigned int> bndMap(nBndDofs), intMap(nIntDofs);
193  exp->GetBoundaryMap(bndMap);
194  exp->GetInteriorMap(intMap);
195 
196  // Create temporary matrices
197  DNekMatSharedPtr bndryMat =
198  MemoryManager<DNekMat>::AllocateSharedPtr(nBndDofs, nBndDofs);
199 
200  // Extract boundary and send to StaticCond (Schur)
201  // framework
202  for (int i = 0; i < nBndDofs; ++i)
203  {
204  for (int j = 0; j < nBndDofs; ++j)
205  {
206  (*bndryMat)(i, j) = (*tmpMat)(bndMap[i], bndMap[j]);
207  }
208  }
209 
210  schurMat =
212 
213  // Extract interior matrix and save for block matrix setting
214  vector<NekDouble> tmpStore(nIntDofs * nIntDofs);
215  for (int i = 0; i < nIntDofs; ++i)
216  {
217  for (int j = 0; j < nIntDofs; ++j)
218  {
219  tmpStore[j + i * nIntDofs] =
220  (*tmpMat)(intMap[i], intMap[j]);
221  }
222  }
223 
224  // Save interior mats and nDofs
225  idMats[3][n] = tmpStore;
226  gidDofs[3][n] = nIntDofs;
227  // then intMat gets added to a block diagonal matrix that
228  // handles the extra interior dofs no need to do any
229  // communication for that because all interior dofs are
230  // local to each element
231  }
232  else
233  {
234  schurMat = m_linsys.lock()->GetStaticCondBlock(n)->GetBlock(0, 0);
235  }
236 
237  // Process vertices to extract relevant portion of the Schur
238  // complement matrix.
239  for (i = 0; i < exp->GetNverts(); ++i)
240  {
241  meshVertId = exp->GetGeom()->GetVid(i);
242  int locId = exp->GetVertexMap(i);
243 
244  // Get the global ID of this vertex.
245  gId = asmMap->GetLocalToGlobalMap(cnt + locId) - nDirBnd;
246 
247  // Ignore all Dirichlet vertices.
248  if (gId < 0)
249  {
250  continue;
251  }
252 
253  gidDofs[0][gId] = 1;
254 
255  // Extract vertex value from Schur complement matrix.
256  NekDouble vertVal = (*schurMat)(locId, locId);
257 
258  // See if we have processed this vertex from another
259  // element.
260  auto gIt = idMats[0].find(gId);
261 
262  if (gIt == idMats[0].end())
263  {
264  // If not then put our 'matrix' inside idMats.
265  idMats[0][gId] = vector<NekDouble>(1, vertVal);
266  }
267  else
268  {
269  // Otherwise combine with the value that is already
270  // there (i.e. do assembly on this degree of freedom).
271  gIt->second[0] += vertVal;
272  }
273 
274  // Now check to see if the vertex is periodic. If it is,
275  // then we change meshVertId to be the minimum of all the
276  // other periodic vertices, so that we don't end up
277  // duplicating the matrix in our final block matrix.
278  auto pIt = periodicVerts.find(meshVertId);
279  if (pIt != periodicVerts.end())
280  {
281  for (j = 0; j < pIt->second.size(); ++j)
282  {
283  meshVertId = min(meshVertId, pIt->second[j].id);
284  }
285  }
286 
287  // Finally record the other information we need into the
288  // other matrices.
289  gidMeshIds[0][gId] = meshVertId;
290  maxVertIds[0] = max(maxVertIds[0], meshVertId);
291  maxVertIds[1] = 1;
292  }
293 
294  // Process edges. This logic is mostly the same as the previous
295  // block.
296  for (i = 0; i < exp->GetGeom()->GetNumEdges(); ++i)
297  {
298  meshEdgeId = exp->GetGeom()->GetEid(i);
299 
300  Array<OneD, unsigned int> bmap, bmap2;
301  Array<OneD, int> sign;
302  StdRegions::Orientation edgeOrient = exp->GetGeom()->GetEorient(i);
303 
304  // Check if this edge is periodic. We may need to flip
305  // orientation if it is.
306  auto pIt = periodicEdges.find(meshEdgeId);
307  if (pIt != periodicEdges.end())
308  {
309  pair<int, StdRegions::Orientation> idOrient =
310  DeterminePeriodicEdgeOrientId(meshEdgeId, edgeOrient,
311  pIt->second);
312  meshEdgeId = idOrient.first;
313  edgeOrient = idOrient.second;
314  }
315 
316  // Grab edge interior map, and the edge inverse boundary
317  // map, so that we can extract this edge from the Schur
318  // complement matrix.
319  if (exp->GetGeom()->GetNumFaces()) // 3D Element calls
320  {
321  exp->as<LocalRegions::Expansion3D>()
322  ->GetEdgeInteriorToElementMap(i, bmap, sign, edgeOrient);
323  bmap2 = exp->as<LocalRegions::Expansion3D>()
324  ->GetEdgeInverseBoundaryMap(i);
325  }
326  else
327  {
328  exp->GetTraceInteriorToElementMap(i, bmap, sign, edgeOrient);
329  bmap2 = exp->as<LocalRegions::Expansion2D>()
330  ->GetTraceInverseBoundaryMap(i);
331  }
332 
333  // Allocate temporary storage for the extracted edge matrix.
334  const int nEdgeCoeffs = bmap.size();
335  vector<NekDouble> tmpStore(nEdgeCoeffs * nEdgeCoeffs);
336 
337  gId = asmMap->GetLocalToGlobalMap(cnt + bmap[0]);
338 
339  for (j = 0; j < nEdgeCoeffs; ++j)
340  {
341  // We record the minimum ID from the edge for our
342  // maps. This follows the logic that the assembly map
343  // ordering will always give us a contiguous ordering of
344  // global degrees of freedom for edge interior
345  // coefficients.
346  gId = min(gId,
347  asmMap->GetLocalToGlobalMap(cnt + bmap[j]) - nDirBnd);
348 
349  // Ignore Dirichlet edges.
350  if (gId < 0)
351  {
352  continue;
353  }
354 
355  const NekDouble sign1 = sign[j];
356 
357  // Extract this edge, along with sign array for assembly
358  // later.
359  for (k = 0; k < nEdgeCoeffs; ++k)
360  {
361  tmpStore[k + j * nEdgeCoeffs] =
362  sign1 * sign[k] * (*schurMat)(bmap2[j], bmap2[k]);
363  }
364  }
365 
366  if (gId < 0)
367  {
368  continue;
369  }
370 
371  gidDofs[1][gId] = nEdgeCoeffs;
372 
373  // Assemble this edge matrix with another one, if it exists.
374  auto gIt = idMats[1].find(gId);
375  if (gIt == idMats[1].end())
376  {
377  idMats[1][gId] = tmpStore;
378  }
379  else
380  {
381  ASSERTL1(tmpStore.size() == gIt->second.size(),
382  "Number of modes mismatch");
383  Vmath::Vadd(nEdgeCoeffs * nEdgeCoeffs, &gIt->second[0], 1,
384  &tmpStore[0], 1, &gIt->second[0], 1);
385  }
386 
387  gidMeshIds[1][gId] = meshEdgeId;
388  maxVertIds[2] = max(maxVertIds[2], meshEdgeId);
389  maxVertIds[3] = max(maxVertIds[3], nEdgeCoeffs);
390  }
391 
392  // Process faces. This logic is mostly the same as the previous
393  // block.
394  for (i = 0; i < exp->GetGeom()->GetNumFaces(); ++i)
395  {
396  meshFaceId = exp->GetGeom()->GetFid(i);
397 
398  Array<OneD, unsigned int> bmap, bmap2;
399  Array<OneD, int> sign;
400  StdRegions::Orientation faceOrient = exp->GetGeom()->GetForient(i);
401 
402  // Check if this face is periodic. We may need to flip
403  // orientation if it is.
404  auto pIt = periodicFaces.find(meshFaceId);
405  if (pIt != periodicFaces.end())
406  {
407  meshFaceId = min(meshFaceId, pIt->second[0].id);
408  faceOrient = DeterminePeriodicFaceOrient(faceOrient,
409  pIt->second[0].orient);
410  }
411 
412  exp->GetTraceInteriorToElementMap(i, bmap, sign, faceOrient);
413  bmap2 = exp->as<LocalRegions::Expansion3D>()
414  ->GetTraceInverseBoundaryMap(i);
415 
416  // Allocate temporary storage for the extracted face matrix.
417  const int nFaceCoeffs = bmap.size();
418  vector<NekDouble> tmpStore(nFaceCoeffs * nFaceCoeffs);
419 
420  gId = asmMap->GetLocalToGlobalMap(cnt + bmap[0]);
421 
422  for (j = 0; j < nFaceCoeffs; ++j)
423  {
424  gId = min(gId,
425  asmMap->GetLocalToGlobalMap(cnt + bmap[j]) - nDirBnd);
426 
427  // Ignore Dirichlet faces.
428  if (gId < 0)
429  {
430  continue;
431  }
432 
433  const NekDouble sign1 = sign[j];
434 
435  // Extract this face, along with sign array for assembly
436  // later.
437  for (k = 0; k < nFaceCoeffs; ++k)
438  {
439  tmpStore[k + j * nFaceCoeffs] =
440  sign1 * sign[k] * (*schurMat)(bmap2[j], bmap2[k]);
441  }
442  }
443 
444  if (gId < 0)
445  {
446  continue;
447  }
448 
449  gidDofs[2][gId] = nFaceCoeffs;
450 
451  // Assemble this face matrix with another one, if it exists.
452  auto gIt = idMats[2].find(gId);
453  if (gIt == idMats[2].end())
454  {
455  idMats[2][gId] = tmpStore;
456  }
457  else
458  {
459  ASSERTL1(tmpStore.size() == gIt->second.size(),
460  "Number of modes mismatch");
461  Vmath::Vadd(nFaceCoeffs * nFaceCoeffs, &gIt->second[0], 1,
462  &tmpStore[0], 1, &gIt->second[0], 1);
463  }
464 
465  gidMeshIds[2][gId] = meshFaceId;
466  maxVertIds[4] = max(maxVertIds[4], meshFaceId);
467  maxVertIds[5] = max(maxVertIds[5], nFaceCoeffs);
468  }
469 
470  cnt += exp->GetNcoeffs();
471  }
472 
473  // Perform a reduction to find maximum vertex, edge and face
474  // geometry IDs.
475  m_comm = expList->GetSession()->GetComm()->GetRowComm();
476  m_comm->AllReduce(maxVertIds, LibUtilities::ReduceMax);
477 
478  // Concatenate all matrices into contiguous storage and figure out
479  // universal ID numbering.
480  vector<NekDouble> storageBuf;
481  vector<long> globalToUniversal;
482 
483  for (i = 0, cnt = 1; i < 3; ++i)
484  {
485  const int maxDofs = maxVertIds[2 * i + 1];
486 
487  // Note that iterating over the map uses the property that keys
488  // are accessed in order of ascending order, putting everything
489  // in the right order for the global system.
490  for (auto &gIt : idMats[i])
491  {
492  // Copy matrix into storage.
493  storageBuf.insert(storageBuf.end(), gIt.second.begin(),
494  gIt.second.end());
495 
496  // Get mesh ID from global ID number.
497  ASSERTL1(gidMeshIds[i].count(gIt.first) > 0,
498  "Unable to find global ID " +
499  boost::lexical_cast<string>(gIt.first) +
500  " inside map");
501  meshVertId = gidMeshIds[i][gIt.first];
502 
503  for (j = 0; j < gIt.second.size(); ++j)
504  {
505  globalToUniversal.push_back(cnt +
506  meshVertId * maxDofs * maxDofs + j);
507  }
508 
509  // Free up the temporary storage.
510  gIt.second.clear();
511  }
512 
513  cnt += (maxVertIds[2 * i] + 1) * maxDofs * maxDofs;
514  }
515 
516  ASSERTL1(storageBuf.size() == globalToUniversal.size(),
517  "Storage buffer and global to universal map size does "
518  "not match");
519 
520  Array<OneD, NekDouble> storageData(storageBuf.size(), &storageBuf[0]);
521  Array<OneD, long> globalToUniversalMap(globalToUniversal.size(),
522  &globalToUniversal[0]);
523 
524  // Use GS to assemble data between processors.
525  Gs::gs_data *tmpGs =
526  Gs::Init(globalToUniversalMap, m_comm,
527  expList->GetSession()->DefinesCmdLineArgument("verbose"));
528  Gs::Gather(storageData, Gs::gs_add, tmpGs);
529 
530  // Figure out what storage we need in the block matrix.
531  int nblksSize = 1 + idMats[1].size() + idMats[2].size();
532  if (m_isFull)
533  {
534  nblksSize += idMats[3].size();
535  }
536  Array<OneD, unsigned int> n_blks(nblksSize);
537 
538  // Vertex block is a diagonal matrix.
539  n_blks[0] = idMats[0].size();
540 
541  // Now extract number of rows in each edge and face block from the
542  // gidDofs map.
543  cnt = 1;
544  for (i = 1; i < nStorage; ++i)
545  {
546  for (auto &gIt : idMats[i])
547  {
548  ASSERTL1(gidDofs[i].count(gIt.first) > 0,
549  "Unable to find number of degrees of freedom for "
550  "global ID " +
551  boost::lexical_cast<string>(gIt.first));
552 
553  n_blks[cnt++] = gidDofs[i][gIt.first];
554  }
555  }
556 
557  // Allocate storage for the block matrix.
558  m_blkMat =
560 
561  // We deal with the vertex matrix separately since all vertices can
562  // be condensed into a single, block-diagonal matrix.
564  n_blks[0], n_blks[0], 0.0, eDIAGONAL);
565 
566  // Fill the vertex matrix with the inverse of each vertex value.
567  cnt = 0;
568  for (auto gIt = idMats[0].begin(); gIt != idMats[0].end(); ++gIt, ++cnt)
569  {
570  (*vertMat)(cnt, cnt) = 1.0 / storageData[cnt];
571  }
572 
573  // Put the vertex matrix in the block matrix.
574  m_blkMat->SetBlock(0, 0, vertMat);
575 
576  // Finally, grab the matrices from the block storage, invert them
577  // and place them in the correct position inside the block matrix.
578  int cnt2 = 1;
579  for (i = 1; i < nStorage; ++i)
580  {
581  for (auto &gIt : idMats[i])
582  {
583  int nDofs = gidDofs[i][gIt.first];
584 
585  DNekMatSharedPtr tmp =
587 
588  for (j = 0; j < nDofs; ++j)
589  {
590  for (k = 0; k < nDofs; ++k)
591  {
592  // Interior matrices do not need mapping
593  // and are stored in idMats[3]
594  if (m_isFull && i == 3)
595  {
596  (*tmp)(j, k) = gIt.second[k + j * nDofs];
597  }
598  // Boundary matrices
599  else
600  {
601  (*tmp)(j, k) = storageData[k + j * nDofs + cnt];
602  }
603  }
604  }
605 
606  cnt += nDofs * nDofs;
607 
608  tmp->Invert();
609  m_blkMat->SetBlock(cnt2, cnt2, tmp);
610  ++cnt2;
611  }
612  }
613 }
#define ASSERTL1(condition, msg)
Assert Level 1 – Debugging which is used whether in FULLDEBUG or DEBUG compilation mode....
Definition: ErrorUtil.hpp:249
#define sign(a, b)
return the sign(b)*a
Definition: Polylib.cpp:49
static std::shared_ptr< DataType > AllocateSharedPtr(const Args &...args)
Allocate a shared pointer from the memory pool.
LibUtilities::CommSharedPtr m_comm
const std::weak_ptr< GlobalLinSys > m_linsys
std::weak_ptr< AssemblyMap > m_locToGloMap
static void Gather(Nektar::Array< OneD, NekDouble > pU, gs_op pOp, gs_data *pGsh, Nektar::Array< OneD, NekDouble > pBuffer=NullNekDouble1DArray)
Performs a gather-scatter operation of the provided values.
Definition: GsLib.hpp:270
@ gs_add
Definition: GsLib.hpp:62
static gs_data * Init(const Nektar::Array< OneD, long > pId, const LibUtilities::CommSharedPtr &pComm, bool verbose=true)
Initialise Gather-Scatter map.
Definition: GsLib.hpp:192
std::shared_ptr< Expansion > ExpansionSharedPtr
Definition: Expansion.h:68
std::shared_ptr< ExpList > ExpListSharedPtr
Shared pointer to an ExpList object.
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...
std::map< int, std::vector< PeriodicEntity > > PeriodicMap
StdRegions::Orientation DeterminePeriodicFaceOrient(StdRegions::Orientation faceOrient, StdRegions::Orientation perFaceOrient)
Determine relative orientation between two faces.
std::shared_ptr< DNekScalMat > DNekScalMatSharedPtr
std::shared_ptr< DNekScalBlkMat > DNekScalBlkMatSharedPtr
Definition: NekTypeDefs.hpp:79
std::shared_ptr< DNekMat > DNekMatSharedPtr
Definition: NekTypeDefs.hpp:75
double NekDouble
void Vadd(int n, const T *x, const int incx, const T *y, const int incy, T *z, const int incz)
Add vector z = x+y.
Definition: Vmath.cpp:359

References Nektar::MemoryManager< DataType >::AllocateSharedPtr(), ASSERTL1, Nektar::MultiRegions::DeterminePeriodicEdgeOrientId(), Nektar::MultiRegions::DeterminePeriodicFaceOrient(), Nektar::eDIAGONAL, Gs::Gather(), Gs::gs_add, Gs::Init(), m_blkMat, Nektar::MultiRegions::Preconditioner::m_comm, m_isFull, Nektar::MultiRegions::Preconditioner::m_linsys, Nektar::MultiRegions::Preconditioner::m_locToGloMap, Nektar::LibUtilities::ReduceMax, sign, and Vmath::Vadd().

Referenced by v_BuildPreconditioner().

◆ BlockPreconditionerHDG()

void Nektar::MultiRegions::PreconditionerBlock::BlockPreconditionerHDG ( void  )
private

Construct a block preconditioner for the hybridized discontinuous Galerkin system.

This system is built in a similar fashion to its continuous variant found in PreconditionerBlock::BlockPreconditionerCG. In this setting however, the matrix is constructed as:

\[ M^{-1} = \mathrm{Diag}[ (\mathbf{S_{1}})_{f}^{-1} ] \]

where each matrix is the Schur complement system restricted to a single face of the trace system.

Definition at line 628 of file PreconditionerBlock.cpp.

629 {
630  std::shared_ptr<MultiRegions::ExpList> expList =
631  ((m_linsys.lock())->GetLocMat()).lock();
632  std::shared_ptr<MultiRegions::ExpList> trace = expList->GetTrace();
634  DNekScalBlkMatSharedPtr loc_mat;
635  DNekScalMatSharedPtr bnd_mat;
636 
637  AssemblyMapDGSharedPtr asmMap =
638  std::dynamic_pointer_cast<AssemblyMapDG>(m_locToGloMap.lock());
639 
640  int i, j, k, n, cnt, cnt2;
641 
642  // Figure out number of Dirichlet trace elements
643  int nTrace = expList->GetTrace()->GetExpSize();
644  int nDir = asmMap->GetNumGlobalDirBndCoeffs();
645 
646  for (cnt = n = 0; n < nTrace; ++n)
647  {
648  if (cnt >= nDir)
649  {
650  break;
651  }
652 
653  cnt += trace->GetExp(n)->GetNcoeffs();
654  }
655 
656  nDir = n;
657 
658  // Allocate storage for block matrix. Need number of unique faces in
659  // trace space.
660  int maxTraceSize = -1;
661  map<int, int> arrayOffsets;
662 
663  for (cnt = 0, n = nDir; n < nTrace; ++n)
664  {
665  int nCoeffs = trace->GetExp(n)->GetNcoeffs();
666  int nCoeffs2 = nCoeffs * nCoeffs;
667 
668  arrayOffsets[n] = cnt;
669  cnt += nCoeffs2;
670 
671  if (maxTraceSize < nCoeffs2)
672  {
673  maxTraceSize = nCoeffs2;
674  }
675  }
676 
677  // Find maximum trace size.
678  m_comm = expList->GetSession()->GetComm()->GetRowComm();
679  m_comm->AllReduce(maxTraceSize, LibUtilities::ReduceMax);
680 
681  // Zero matrix storage.
682  Array<OneD, NekDouble> tmpStore(cnt, 0.0);
683 
684  // Assemble block matrices for each trace element.
685  for (cnt = n = 0; n < expList->GetExpSize(); ++n)
686  {
687  int elmt = n;
688  locExpansion = expList->GetExp(elmt);
689 
690  Array<OneD, LocalRegions::ExpansionSharedPtr> &elmtToTraceMap =
691  asmMap->GetElmtToTrace()[elmt];
692 
693  // Block matrix (lambda)
694  loc_mat = (m_linsys.lock())->GetStaticCondBlock(n);
695  bnd_mat = loc_mat->GetBlock(0, 0);
696 
697  int nFacets = locExpansion->GetNtraces();
698 
699  for (cnt2 = i = 0; i < nFacets; ++i)
700  {
701  int nCoeffs = elmtToTraceMap[i]->GetNcoeffs();
702  int elmtId = elmtToTraceMap[i]->GetElmtId();
703 
704  // Ignore Dirichlet edges.
705  if (elmtId < nDir)
706  {
707  cnt += nCoeffs;
708  cnt2 += nCoeffs;
709  continue;
710  }
711 
712  NekDouble *off = &tmpStore[arrayOffsets[elmtId]];
713 
714  for (j = 0; j < nCoeffs; ++j)
715  {
716  NekDouble sign1 = asmMap->GetLocalToGlobalBndSign(cnt + j);
717  for (k = 0; k < nCoeffs; ++k)
718  {
719  NekDouble sign2 = asmMap->GetLocalToGlobalBndSign(cnt + k);
720  off[j * nCoeffs + k] +=
721  (*bnd_mat)(cnt2 + j, cnt2 + k) * sign1 * sign2;
722  }
723  }
724 
725  cnt += nCoeffs;
726  cnt2 += nCoeffs;
727  }
728  }
729 
730  // Set up IDs for universal numbering.
731  Array<OneD, long> uniIds(tmpStore.size());
732  for (cnt = 0, n = nDir; n < nTrace; ++n)
733  {
734  LocalRegions::ExpansionSharedPtr traceExp = trace->GetExp(n);
735  int nCoeffs = traceExp->GetNcoeffs();
736  int geomId = traceExp->GetGeom()->GetGlobalID();
737 
738  for (i = 0; i < nCoeffs * nCoeffs; ++i)
739  {
740  uniIds[cnt++] = geomId * maxTraceSize + i + 1;
741  }
742  }
743 
744  // Assemble matrices across partitions.
745  Gs::gs_data *gsh =
746  Gs::Init(uniIds, m_comm,
747  expList->GetSession()->DefinesCmdLineArgument("verbose"));
748  Gs::Gather(tmpStore, Gs::gs_add, gsh);
749 
750  // Set up diagonal block matrix
751  Array<OneD, unsigned int> n_blks(nTrace - nDir);
752  for (n = 0; n < nTrace - nDir; ++n)
753  {
754  n_blks[n] = trace->GetExp(n + nDir)->GetNcoeffs();
755  }
756 
757  m_blkMat =
759 
760  for (n = 0; n < nTrace - nDir; ++n)
761  {
762  int nCoeffs = trace->GetExp(n + nDir)->GetNcoeffs();
763  DNekMatSharedPtr tmp =
765  NekDouble *off = &tmpStore[arrayOffsets[n + nDir]];
766 
767  for (i = 0; i < nCoeffs; ++i)
768  {
769  for (j = 0; j < nCoeffs; ++j)
770  {
771  (*tmp)(i, j) = off[i * nCoeffs + j];
772  }
773  }
774 
775  tmp->Invert();
776  m_blkMat->SetBlock(n, n, tmp);
777  }
778 }
std::shared_ptr< AssemblyMapDG > AssemblyMapDGSharedPtr
Definition: AssemblyMapDG.h:47

References Nektar::MemoryManager< DataType >::AllocateSharedPtr(), Nektar::eDIAGONAL, Gs::Gather(), Gs::gs_add, Gs::Init(), m_blkMat, Nektar::MultiRegions::Preconditioner::m_comm, Nektar::MultiRegions::Preconditioner::m_linsys, Nektar::MultiRegions::Preconditioner::m_locToGloMap, and Nektar::LibUtilities::ReduceMax.

Referenced by v_BuildPreconditioner().

◆ create()

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

Creates an instance of this class.

Definition at line 54 of file PreconditionerBlock.h.

57  {
60  pLocToGloMap);
61  p->InitObject();
62  return p;
63  }
std::shared_ptr< Preconditioner > PreconditionerSharedPtr
Definition: GlobalLinSys.h:60

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

◆ v_BuildPreconditioner()

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

Reimplemented from Nektar::MultiRegions::Preconditioner.

Definition at line 82 of file PreconditionerBlock.cpp.

83 {
84  GlobalLinSysKey key = m_linsys.lock()->GetKey();
85 
86  // Different setup for HDG and CG.
87  if (key.GetMatrixType() == StdRegions::eHybridDGHelmBndLam)
88  {
90  }
91  else
92  {
94  }
95 }
void BlockPreconditionerCG(void)
Construct a block preconditioner from for the continuous Galerkin system.
void BlockPreconditionerHDG(void)
Construct a block preconditioner for the hybridized discontinuous Galerkin system.

References BlockPreconditionerCG(), BlockPreconditionerHDG(), Nektar::StdRegions::eHybridDGHelmBndLam, Nektar::MultiRegions::GlobalMatrixKey::GetMatrixType(), and Nektar::MultiRegions::Preconditioner::m_linsys.

◆ v_DoPreconditioner()

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

Apply preconditioner to pInput and store the result in pOutput.

Reimplemented from Nektar::MultiRegions::Preconditioner.

Definition at line 784 of file PreconditionerBlock.cpp.

786 {
787  // Get assembly map and solver type
788  auto asmMap = m_locToGloMap.lock();
789 
790  // Determine matrix size
791  int nGlobal = m_isFull ? asmMap->GetNumGlobalCoeffs()
792  : asmMap->GetNumGlobalBndCoeffs();
793  int nDir = asmMap->GetNumGlobalDirBndCoeffs();
794  int nNonDir = nGlobal - nDir;
795 
796  // Apply preconditioner
797  DNekBlkMat &M = (*m_blkMat);
798  NekVector<NekDouble> r(nNonDir, pInput, eWrapper);
799  NekVector<NekDouble> z(nNonDir, pOutput, eWrapper);
800  z = M * r;
801 }
NekMatrix< NekMatrix< NekDouble, StandardMatrixTag >, BlockMatrixTag > DNekBlkMat
Definition: NekTypeDefs.hpp:58

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

◆ v_InitObject()

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

Member Data Documentation

◆ className

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

Name of class.

Registers the class with the Factory.

Definition at line 66 of file PreconditionerBlock.h.

◆ m_blkMat

DNekBlkMatSharedPtr Nektar::MultiRegions::PreconditionerBlock::m_blkMat
protected

Definition at line 79 of file PreconditionerBlock.h.

Referenced by BlockPreconditionerCG(), and BlockPreconditionerHDG().

◆ m_isFull

bool Nektar::MultiRegions::PreconditionerBlock::m_isFull
protected

Definition at line 78 of file PreconditionerBlock.h.

Referenced by BlockPreconditionerCG(), v_DoPreconditioner(), and v_InitObject().