Nektar++
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
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, const bool &IsLocal=false)
 
void DoAssembleLoc (const Array< OneD, NekDouble > &pInput, Array< OneD, NekDouble > &pOutput, const bool &ZeroDir)
 Apply an assembly and scatter back to lcoal array. More...
 
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, const bool &isLocal=false) 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_InitObject ()
 
virtual void v_DoPreconditioner (const Array< OneD, NekDouble > &pInput, Array< OneD, NekDouble > &pOutput, const bool &isLocal=false)
 Apply a preconditioner to the conjugate gradient method. 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...
 
virtual void v_BuildPreconditioner ()
 

Protected Attributes

bool m_isFull
 
DNekBlkMatSharedPtr m_blkMat
 
- Protected Attributes inherited from Nektar::MultiRegions::Preconditioner
const std::weak_ptr< GlobalLinSysm_linsys
 
std::string m_preconType
 
DNekMatSharedPtr m_preconditioner
 
std::weak_ptr< AssemblyMapm_locToGloMap
 
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 63 of file PreconditionerBlock.cpp.

66 : Preconditioner(plinsys, pLocToGloMap)
67{
68}
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 125 of file PreconditionerBlock.cpp.

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

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 627 of file PreconditionerBlock.cpp.

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

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 81 of file PreconditionerBlock.cpp.

82{
83 GlobalLinSysKey key = m_linsys.lock()->GetKey();
84
85 // Different setup for HDG and CG.
86 if (key.GetMatrixType() == StdRegions::eHybridDGHelmBndLam)
87 {
89 }
90 else
91 {
93 }
94}
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,
const bool &  isLocal = false 
)
overrideprotectedvirtual

Apply preconditioner to pInput and store the result in pOutput.

Reimplemented from Nektar::MultiRegions::Preconditioner.

Definition at line 783 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
799 if (isLocal)
800 {
801 Array<OneD, NekDouble> wk(nGlobal);
802 Array<OneD, NekDouble> wk1(nGlobal);
803 asmMap->Assemble(pInput, wk);
804
805 NekVector<NekDouble> r(nNonDir, wk + nDir, eWrapper);
806 NekVector<NekDouble> z(nNonDir, wk1 + nDir, eWrapper);
807
808 z = M * r;
809 Vmath::Zero(nDir, wk1, 1);
810
811 asmMap->GlobalToLocal(wk1, pOutput);
812 }
813 else
814 {
815 NekVector<NekDouble> r(nNonDir, pInput, eWrapper);
816 NekVector<NekDouble> z(nNonDir, pOutput, eWrapper);
817 z = M * r;
818 }
819}
std::vector< double > z(NPUPPER)
NekMatrix< NekMatrix< NekDouble, StandardMatrixTag >, BlockMatrixTag > DNekBlkMat
Definition: NekTypeDefs.hpp:58
void Zero(int n, T *x, const int incx)
Zero vector.
Definition: Vmath.cpp:487

References Nektar::eWrapper, m_isFull, Nektar::MultiRegions::Preconditioner::m_locToGloMap, Nektar::UnitTests::z(), and Vmath::Zero().

◆ 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().