MFEM v4.10.0
Finite element discretization library
Loading...
Searching...
No Matches
preconditioners.cpp
Go to the documentation of this file.
1// Copyright (c) 2010-2026, Lawrence Livermore National Security, LLC. Produced
2// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
3// LICENSE and NOTICE for details. LLNL-CODE-806117.
4//
5// This file is part of the MFEM library. For more information and source code
6// availability visit https://mfem.org.
7//
8// MFEM is free software; you can redistribute it and/or modify it under the
9// terms of the BSD-3 license. We welcome feedback and contributions, see file
10// CONTRIBUTING.md for details.
11
12#include "preconditioners.hpp"
13
14namespace mfem
15{
16
17#ifdef MFEM_USE_MPI
18
20 const ParFiniteElementSpace * pfespace, int print_level)
21{
22 FiniteElementCollection const &fec = *(pfespace->FEColl());
23 const int vdim = pfespace->GetVDim();
24 const int dim = pfespace->GetParMesh()->Dimension();
25 Solver * prec = nullptr;
26 if (dynamic_cast<const H1_FECollection*>(&fec) ||
27 dynamic_cast<const L2_FECollection*>(&fec))
28 {
29 prec = new HypreBoomerAMG();
30 dynamic_cast<HypreBoomerAMG*>(prec)->SetPrintLevel(print_level);
31 if (vdim > 1)
32 {
33 dynamic_cast<HypreBoomerAMG*>(prec)->SetSystemsOptions(vdim);
34 }
35 return prec;
36 }
37 else if (dynamic_cast<const RT_FECollection*>(&fec) && dim == 3)
38 {
39 prec = new HypreADS(const_cast<ParFiniteElementSpace*>(pfespace));
40 dynamic_cast<HypreADS*>(prec)->SetPrintLevel(print_level);
41 return prec;
42 }
43 else if (dynamic_cast<const ND_FECollection*>(&fec) ||
44 dynamic_cast<const RT_FECollection*>(&fec))
45 {
46 prec = new HypreAMS(const_cast<ParFiniteElementSpace*>(pfespace));
47 dynamic_cast<HypreAMS*>(prec)->SetPrintLevel(print_level);
48 return prec;
49 }
50 else
51 {
52 MFEM_ABORT("Unsupported FiniteElementCollection type");
53 }
54 return prec;
55}
56
57
59 &pfes_,
60 const std::vector<Array<int>> & ess_bdr_marker_)
61 : pfes(pfes_), ess_bdr_marker(ess_bdr_marker_), nblocks(pfes.Size())
62{
63 MFEM_VERIFY(nblocks > 0, "Empty pfes.");
64 pmesh = pfes[0]->GetParMesh();
65 MFEM_VERIFY(pmesh, "pfes[0] has null ParMesh.");
66 MFEM_VERIFY(ess_bdr_marker.size() == static_cast<size_t>(nblocks),
67 "ess_bdr_marker size must match nblocks.");
68 int bdr_size = (pmesh->bdr_attributes.Size() > 0) ? pmesh->bdr_attributes.Max()
69 : 0;
70 for (int i = 0; i<nblocks; i++)
71 {
72 MFEM_VERIFY(ess_bdr_marker[i].Size() == bdr_size,
73 "ess_bdr_marker[" << i << "] size must match max bdr_attribute in mesh.");
74 }
75}
76
78 int b) const
79{
80 if (lev == maxlevels - 1) { return pfes[b]; }
81 return fes_owned[lev][b].get();
82}
83
85 *pfespace)
86const
87{
88 return (dynamic_cast<const L2_FECollection*>(pfespace->FEColl()) ||
89 dynamic_cast<const RT_FECollection*>(pfespace->FEColl())) ? 0 : 1;
90}
91
93{
95 Array<int> levels(nblocks);
96 for (int i = 0; i < nblocks; i++)
97 {
98 orders[i] = pfes[i]->FEColl()->GetConstructorOrder();
99 levels[i] = orders[i] - GetFESpaceMinimumOrder(pfes[i]);
100 }
101
102 maxlevels = levels.Min() + 1;
103 if (mgmaxlevels > 0)
104 {
105 maxlevels = std::min(maxlevels, mgmaxlevels);
106 }
107
108 MFEM_VERIFY(maxlevels >= 1, "Invalid maxlevels computed.");
109
110 fec_owned.resize(maxlevels-1);
111 fes_owned.resize(maxlevels-1);
112 T_level.resize(maxlevels-1);
113
114 for (int lev = 0; lev < maxlevels-1; lev++)
115 {
116 fec_owned[lev].resize(nblocks);
117 fes_owned[lev].resize(nblocks);
118 T_level[lev].resize(nblocks);
119 }
120
121 // Build ParFES hierarchy for each block
122 for (int b = 0; b < nblocks; b++)
123 {
124 const FiniteElementCollection *fec_ref = pfes[b]->FEColl();
125 const int vdim = pfes[b]->GetVDim();
126 const Ordering::Type ordering = pfes[b]->GetOrdering();
127
128 for (int lev = 1; lev <= maxlevels - 1; lev++)
129 {
130 const int p = orders[b] - lev;
131
132 auto &fec_ptr = fec_owned[maxlevels - lev - 1][b];
133 auto &fes_ptr = fes_owned[maxlevels - lev - 1][b];
134
135 fec_ptr.reset(fec_ref->Clone(p));
136 fes_ptr = std::make_unique<ParFiniteElementSpace>(pmesh, fec_ptr.get(),
137 vdim, ordering);
138 }
139 }
140
141 // build true dof lists for all levels
142 ess_tdof_list.resize(maxlevels);
143 Array<int> tdof_offsets(nblocks+1);
144 for (int i = 0; i< maxlevels; i++)
145 {
146 tdof_offsets[0] = 0;
147 for (int b = 0; b < nblocks; b++)
148 {
149 tdof_offsets[b+1] = GetParFESpace(i,b)->GetTrueVSize();
150 }
151 tdof_offsets.PartialSum();
152 Array<int> tdof_list;
153 Array<int> block_tdof_list;
154 for (int b = 0; b < nblocks; b++)
155 {
156 block_tdof_list.SetSize(0);
157 GetParFESpace(i,b)->GetEssentialTrueDofs(ess_bdr_marker[b], block_tdof_list);
158 for (int j = 0; j < block_tdof_list.Size(); j++)
159 {
160 block_tdof_list[j] += tdof_offsets[b];
161 }
162 tdof_list.Append(block_tdof_list);
163 }
164 ess_tdof_list[i] = tdof_list;
165 }
166}
167
169{
170 MFEM_VERIFY(lev >= 0 &&
171 lev < maxlevels - 1, "Invalid level in BuildProlongation().");
172
173 Array<int> coarse_offsets(nblocks + 1); coarse_offsets[0] = 0;
174 Array<int> fine_offsets(nblocks + 1); fine_offsets[0] = 0;
175
176 for (int b = 0; b < nblocks; b++)
177 {
178 coarse_offsets[b+1] = coarse_offsets[b] + GetParFESpace(lev,
179 b)->GetTrueVSize();
180 fine_offsets[b+1] = fine_offsets[b] + GetParFESpace(lev+1,
181 b)->GetTrueVSize();
182 }
183
184 BlockOperator *Pblk = new BlockOperator(fine_offsets, coarse_offsets);
185 Pblk->owns_blocks = 0;
186
187 for (int b = 0; b < nblocks; b++)
188 {
189 T_level[lev][b] = std::make_unique<PRefinementTransferOperator>(
190 *GetParFESpace(lev, b), *GetParFESpace(lev+1, b), true);
191
192 HypreParMatrix *P =
193 dynamic_cast<HypreParMatrix*>(T_level[lev][b]->GetTrueTransferOperator());
194 MFEM_VERIFY(P, "PRefinement transfer returned null.");
195 Pblk->SetBlock(b, b, P);
196 }
197 return Pblk;
198}
199
200
203 const std::vector<Array<int>> & ess_bdr_marker_,
204 const BlockOperator &Op_, int mgmaxlevels,
205 real_t smoother_relax_factor, bool mumps_coarse_solver,
206 int coarse_cg_max_iter, real_t coarse_cg_rel_tol)
207 : Multigrid(), hierarchy(pfes_, ess_bdr_marker_), Op(Op_)
208{
209#ifndef MFEM_USE_MUMPS
210 if (mumps_coarse_solver)
211 {
212 MFEM_WARNING("MFEM not built with MUMPS."
213 "Switching to default coarse solver (CG).");
214 }
215 mumps_coarse_solver = false;
216#endif
217
218 hierarchy.BuildSpaceHierarchy(mgmaxlevels);
219
220 const int maxlevels = hierarchy.maxlevels;
221 const int nblocks = hierarchy.nblocks;
222
223 operators.SetSize(maxlevels);
224 ownedOperators.SetSize(maxlevels);
225 smoothers.SetSize(maxlevels);
226 ownedSmoothers.SetSize(maxlevels);
227
228 operators[maxlevels-1] = const_cast<BlockOperator*>(&Op);
229 ownedOperators[maxlevels-1] = false;
230
231 const int nP = std::max(0, maxlevels - 1);
232 prolongations.SetSize(nP);
234
235 // Build prolongations and Galerkin operators
236 for (int lev = nP - 1; lev >= 0; lev--)
237 {
238 BlockOperator *Pblk = hierarchy.BuildProlongation(lev);
239 prolongations[lev] =
240 new RectangularConstrainedOperator(Pblk, hierarchy.ess_tdof_list[lev],
241 hierarchy.ess_tdof_list[lev+1], true);
242 ownedProlongations[lev] = true;
243
244 BlockOperator *OpLevel = new BlockOperator(Pblk->ColOffsets());
245 OpLevel->owns_blocks = 1;
246
247 BlockOperator *OpFine = dynamic_cast<BlockOperator*>(operators[lev+1]);
248 MFEM_VERIFY(OpFine, "Expected BlockOperator at fine level.");
249
250 for (int i = 0; i < nblocks; i++)
251 {
252 HypreParMatrix *Pi = dynamic_cast<HypreParMatrix*>(&Pblk->GetBlock(i, i));
253 MFEM_VERIFY(Pi, "Expected HypreParMatrix prolongation block.");
254 HypreParMatrix *Pit = Pi->Transpose();
255
256 for (int j = 0; j < nblocks; j++)
257 {
258 if (OpFine->IsZeroBlock(i, j)) { continue; }
259
260 const HypreParMatrix *A_fine =
261 dynamic_cast<const HypreParMatrix*>(&OpFine->GetBlock(i, j));
262 MFEM_VERIFY(A_fine, "Expected HypreParMatrix block.");
263
264 if (i == j)
265 {
266 OpLevel->SetBlock(i, i, RAP(A_fine, Pi));
267 }
268 else
269 {
270 HypreParMatrix *Pj = dynamic_cast<HypreParMatrix*>(&Pblk->GetBlock(j, j));
271 MFEM_VERIFY(Pj, "Expected HypreParMatrix prolongation block.");
272
273 HypreParMatrix *APj = ParMult(A_fine, Pj, true);
274 HypreParMatrix *PtAP = ParMult(Pit, APj, true);
275 delete APj;
276 OpLevel->SetBlock(i, j, PtAP);
277 }
278 }
279 delete Pit;
280 }
281 operators[lev] = OpLevel;
282 ownedOperators[lev] = true;
283 }
284
285 // Build smoothers
286 for (int lev = 0; lev < operators.Size(); lev++)
287 {
288 auto *cOp = dynamic_cast<BlockOperator*>(operators[lev]);
289 MFEM_VERIFY(cOp, "Expected BlockOperator in operators[].");
290
291 if (lev == 0 && operators.Size() > 1) // coarse
292 {
293#ifdef MFEM_USE_MUMPS
294 if (mumps_coarse_solver)
295 {
296 HypreParMatrix *Acoarse = cOp->GetMonolithicHypreParMatrix();
297 auto *mumps_solver = new MUMPSSolver(MPI_COMM_WORLD);
298 mumps_solver->SetPrintLevel(0);
299 mumps_solver->SetOperator(*Acoarse);
300 delete Acoarse;
301
302 smoothers[lev] = mumps_solver;
303 ownedSmoothers[lev] = true;
304 }
305 else
306#endif
307 {
308 auto *bd = new BlockDiagonalPreconditioner(cOp->RowOffsets());
309 bd->owns_blocks = 1;
310
311 for (int b = 0; b < nblocks; b++)
312 {
313 const HypreParMatrix *Ab =
314 dynamic_cast<const HypreParMatrix*>(&cOp->GetBlock(b, b));
315 MFEM_VERIFY(Ab, "Expected HypreParMatrix block.");
316
317 auto solver = MakeFESpaceDefaultSolver(hierarchy.GetParFESpace(lev, b), 0);
318 solver->SetOperator(*Ab);
319 bd->SetDiagonalBlock(b, solver);
320 }
321
322 coarse_prec.reset(bd);
323
324 auto *cg = new CGSolver(MPI_COMM_WORLD);
325 cg->SetPrintLevel(-1);
326 cg->SetRelTol(coarse_cg_rel_tol);
327 cg->SetMaxIter(coarse_cg_max_iter);
328 cg->SetOperator(*cOp);
329 cg->SetPreconditioner(*coarse_prec);
330
331 smoothers[lev] = cg;
332 ownedSmoothers[lev] = true;
333 }
334 }
335 else
336 {
337 auto *prec = new SymmetricBlockDiagonalPreconditioner(cOp->RowOffsets(),
338 smoother_relax_factor);
339 prec->owns_blocks = 1;
340
341 for (int b = 0; b < nblocks; b++)
342 {
343 const HypreParMatrix *Ab =
344 dynamic_cast<const HypreParMatrix*>(&cOp->GetBlock(b, b));
345 MFEM_VERIFY(Ab, "Expected HypreParMatrix block.");
346
347 auto solver = MakeFESpaceDefaultSolver(hierarchy.GetParFESpace(lev, b), 0);
348 solver->SetOperator(*Ab);
349 prec->SetDiagonalBlock(b, solver);
350 }
351 smoothers[lev] = prec;
352 ownedSmoothers[lev] = true;
353 }
354 }
355}
356
357
360 const std::vector<Array<int>> & ess_bdr_marker,
361 const ComplexOperator &Op_, int mgmaxlevels,
362 real_t smoother_relax_factor, bool mumps_coarse_solver,
363 int coarse_cg_max_iter, real_t coarse_cg_rel_tol)
364 : Multigrid(), Op(Op_)
365{
366#ifndef MFEM_USE_MUMPS
367 if (mumps_coarse_solver)
368 {
369 MFEM_WARNING("MFEM not built with MUMPS."
370 "Switching to default coarse solver (CG).");
371 }
372 mumps_coarse_solver = false;
373#endif
374
375
376 const auto *Op_r = dynamic_cast<const BlockOperator*>(&Op.real());
377 const auto *Op_i = dynamic_cast<const BlockOperator*>(&Op.imag());
378 MFEM_VERIFY(Op_r, "Expected BlockOperator from ComplexOperator real part.");
379 MFEM_VERIFY(Op_i, "Expected BlockOperator from ComplexOperator imag part.");
380
381 const int nblocks = Op_r->NumRowBlocks();
382 MFEM_VERIFY(nblocks == Op_i->NumRowBlocks(), "Real/imag block counts differ.");
383 hierarchy = std::make_unique<PRefinementHierarchy>(pfes_, ess_bdr_marker);
384
385 hierarchy->BuildSpaceHierarchy(mgmaxlevels);
386
387 const int maxlevels = hierarchy->maxlevels;
388
389 operators.SetSize(maxlevels);
390 ownedOperators.SetSize(maxlevels);
391 smoothers.SetSize(maxlevels);
392 ownedSmoothers.SetSize(maxlevels);
393
394 operators[maxlevels-1] = const_cast<ComplexOperator*>(&Op);
395 ownedOperators[maxlevels-1] = false;
396
397 const int nP = std::max(0, maxlevels - 1);
398 prolongations.SetSize(nP);
400
401 for (int lev = nP - 1; lev >= 0; lev--)
402 {
403 BlockOperator *Pblk = hierarchy->BuildProlongation(lev);
404
405 auto ConstrOp = new RectangularConstrainedOperator(Pblk,
406 hierarchy->ess_tdof_list[lev],
407 hierarchy->ess_tdof_list[lev+1], true);
408
409 // prolongation as complex (real=Pblk, imag=nullptr)
410 prolongations[lev] = new ComplexOperator(ConstrOp, nullptr, true, true);
411 ownedProlongations[lev] = true;
412
413 auto *OpLevel_r = new BlockOperator(Pblk->ColOffsets());
414 auto *OpLevel_i = new BlockOperator(Pblk->ColOffsets());
415 OpLevel_r->owns_blocks = 1;
416 OpLevel_i->owns_blocks = 1;
417
418 auto *cOp = dynamic_cast<ComplexOperator*>(operators[lev+1]);
419 MFEM_VERIFY(cOp, "Expected ComplexOperator at fine level.");
420
421 auto *cOp_r = dynamic_cast<BlockOperator*>(&cOp->real());
422 auto *cOp_i = dynamic_cast<BlockOperator*>(&cOp->imag());
423 MFEM_VERIFY(cOp_r, "Expected BlockOperator fine real part.");
424 MFEM_VERIFY(cOp_i, "Expected BlockOperator fine imag part.");
425
426 for (int i = 0; i < nblocks; i++)
427 {
428 HypreParMatrix *Pi = dynamic_cast<HypreParMatrix*>(&Pblk->GetBlock(i, i));
429 MFEM_VERIFY(Pi, "Expected HypreParMatrix prolongation block.");
430 HypreParMatrix *Pit = Pi->Transpose();
431
432 for (int j = 0; j < nblocks; j++)
433 {
434 if (!cOp_r->IsZeroBlock(i, j))
435 {
436 const HypreParMatrix *A_fine_r =
437 dynamic_cast<const HypreParMatrix*>(&cOp_r->GetBlock(i, j));
438 MFEM_VERIFY(A_fine_r, "Expected HypreParMatrix block (real).");
439
440 if (i == j)
441 {
442 OpLevel_r->SetBlock(i, i, RAP(A_fine_r, Pi));
443 }
444 else
445 {
446 HypreParMatrix *Pj = dynamic_cast<HypreParMatrix*>(&Pblk->GetBlock(j, j));
447 MFEM_VERIFY(Pj, "Expected HypreParMatrix prolongation block.");
448
449 HypreParMatrix *APj = ParMult(A_fine_r, Pj, true);
450 HypreParMatrix *PtAP = ParMult(Pit, APj, true);
451 delete APj;
452
453 OpLevel_r->SetBlock(i, j, PtAP);
454 }
455 }
456
457 if (!cOp_i->IsZeroBlock(i, j))
458 {
459 const HypreParMatrix *A_fine_i =
460 dynamic_cast<const HypreParMatrix*>(&cOp_i->GetBlock(i, j));
461 MFEM_VERIFY(A_fine_i, "Expected HypreParMatrix block (imag).");
462
463 if (i == j)
464 {
465 OpLevel_i->SetBlock(i, i, RAP(A_fine_i, Pi));
466 }
467 else
468 {
469 HypreParMatrix *Pj = dynamic_cast<HypreParMatrix*>(&Pblk->GetBlock(j, j));
470 MFEM_VERIFY(Pj, "Expected HypreParMatrix prolongation block.");
471
472 HypreParMatrix *APj = ParMult(A_fine_i, Pj, true);
473 HypreParMatrix *PtAP = ParMult(Pit, APj, true);
474 delete APj;
475
476 OpLevel_i->SetBlock(i, j, PtAP);
477 }
478 }
479 }
480
481 delete Pit;
482 }
483
484 auto *OpLevel_c = new ComplexOperator(OpLevel_r, OpLevel_i, true, true);
485 operators[lev] = OpLevel_c;
486 ownedOperators[lev] = true;
487 }
488
489 // smoothers
490 for (int lev = 0; lev < operators.Size(); lev++)
491 {
492 auto *cOp = dynamic_cast<ComplexOperator*>(operators[lev]);
493 MFEM_VERIFY(cOp, "Expected ComplexOperator in operators[].");
494
495 auto *cOp_r = dynamic_cast<BlockOperator*>(&cOp->real());
496 MFEM_VERIFY(cOp_r, "Expected BlockOperator real part in ComplexOperator.");
497
498 if (lev == 0 && operators.Size() > 1) // coarse
499 {
500#ifdef MFEM_USE_MUMPS
501 if (mumps_coarse_solver)
502 {
505 delete Ahc;
506
507 auto *mumps_solver = new MUMPSSolver(MPI_COMM_WORLD);
508 mumps_solver->SetPrintLevel(0);
509 mumps_solver->SetOperator(*A);
510 delete A;
511
512 smoothers[lev] = mumps_solver;
513 ownedSmoothers[lev] = true;
514 }
515 else
516#endif
517 {
518 auto *prec_r = new BlockDiagonalPreconditioner(cOp_r->RowOffsets());
519 prec_r->owns_blocks = 1;
520
521 for (int b = 0; b < nblocks; b++)
522 {
523 const HypreParMatrix *Ab =
524 dynamic_cast<const HypreParMatrix*>(&cOp_r->GetBlock(b, b));
525 MFEM_VERIFY(Ab, "Expected HypreParMatrix block.");
526
527 auto solver = MakeFESpaceDefaultSolver(hierarchy->GetParFESpace(lev, b), 0);
528 solver->SetOperator(*Ab);
529 prec_r->SetDiagonalBlock(b, solver);
530 }
531
532 coarse_prec.reset(new ComplexPreconditioner(prec_r, true));
533
534 auto *cg = new CGSolver(MPI_COMM_WORLD);
535 cg->SetPrintLevel(-1);
536 cg->SetRelTol(coarse_cg_rel_tol);
537 cg->SetMaxIter(coarse_cg_max_iter);
538 cg->SetOperator(*cOp);
539 cg->SetPreconditioner(*coarse_prec);
540
541 smoothers[lev] = cg;
542 ownedSmoothers[lev] = true;
543 }
544 }
545 else
546 {
547 auto *prec_r = new SymmetricBlockDiagonalPreconditioner(cOp_r->RowOffsets(),
548 smoother_relax_factor);
549 prec_r->owns_blocks = 1;
550
551 for (int b = 0; b < nblocks; b++)
552 {
553 const HypreParMatrix *Ab =
554 dynamic_cast<const HypreParMatrix*>(&cOp_r->GetBlock(b, b));
555 MFEM_VERIFY(Ab, "Expected HypreParMatrix block.");
556
557 auto solver = MakeFESpaceDefaultSolver(hierarchy->GetParFESpace(lev, b), 0);
558 solver->SetOperator(*Ab);
559 prec_r->SetDiagonalBlock(b, solver);
560 }
561
562 smoothers[lev] = new ComplexPreconditioner(prec_r, true);
563 ownedSmoothers[lev] = true;
564 }
565 }
566}
567
568#endif
569
570} // namespace mfem
T Max() const
Find the maximal element in the array, using the comparison operator < for class T.
Definition array.cpp:69
void SetSize(int nsize)
Change the logical size of the array, keep existing entries.
Definition array.hpp:869
T Min() const
Find the minimal element in the array, using the comparison operator < for class T.
Definition array.cpp:86
int Size() const
Return the logical size of the array.
Definition array.hpp:192
void PartialSum()
Fill the entries of the array with the cumulative sum of the entries.
Definition array.cpp:104
int Append(const T &el)
Append element 'el' to array, resize if necessary.
Definition array.hpp:941
A class to handle Block diagonal preconditioners in a matrix-free implementation.
A class to handle Block systems in a matrix-free implementation.
int IsZeroBlock(int i, int j) const
Check if block (i,j) is a zero block.
void SetBlock(int iRow, int iCol, Operator *op, real_t c=1.0)
Add a block op in the block-entry (iblock, jblock).
Operator & GetBlock(int i, int j)
Return a reference to block i,j.
Array< int > & ColOffsets()
Return the columns offsets for block starts.
Conjugate gradient method.
Definition solvers.hpp:627
Specialization of the ComplexOperator built from a pair of HypreParMatrices.
HypreParMatrix * GetSystemMatrix() const
Mimic the action of a complex operator using two real operators.
virtual Operator & imag()
ComplexHypreParMatrix * AsComplexHypreParMatrix() const
Return a newly allocated ComplexHypreParMatrix representation.
virtual Operator & real()
Real or imaginary part accessor methods.
ComplexPRefinementMultigrid(const Array< ParFiniteElementSpace * > &pfes_, const std::vector< Array< int > > &ess_bdr_marker, const ComplexOperator &Op_, int mgmaxlevels=-1, real_t smoother_relax_factor=2.0/3, bool mumps_coarse_solver=false, int coarse_cg_max_iter=10, real_t coarse_cg_rel_tol=1e-3)
Collection of finite elements from the same family in multiple dimensions. This class is used to matc...
Definition fe_coll.hpp:27
virtual FiniteElementCollection * Clone(int p) const
Instantiate a new collection of the same type with a different order.
Definition fe_coll.cpp:462
const FiniteElementCollection * FEColl() const
Definition fespace.hpp:854
int GetVDim() const
Returns the vector dimension of the finite element space.
Definition fespace.hpp:817
Arbitrary order H1-conforming (continuous) finite elements.
Definition fe_coll.hpp:291
The Auxiliary-space Divergence Solver in hypre.
Definition hypre.hpp:2066
The Auxiliary-space Maxwell Solver in hypre.
Definition hypre.hpp:1989
The BoomerAMG solver in hypre.
Definition hypre.hpp:1829
Wrapper for hypre's ParCSR matrix class.
Definition hypre.hpp:419
HypreParMatrix * Transpose() const
Returns the transpose of *this.
Definition hypre.cpp:1742
Arbitrary order "L2-conforming" discontinuous finite elements.
Definition fe_coll.hpp:369
MUMPS: A Parallel Sparse Direct Solver.
Definition mumps.hpp:39
Array< int > bdr_attributes
A list of all unique boundary attributes used by the Mesh.
Definition mesh.hpp:309
int Dimension() const
Dimension of the reference space used within the elements.
Definition mesh.hpp:1314
Array< Operator * > operators
Definition multigrid.hpp:35
Array< bool > ownedSmoothers
Definition multigrid.hpp:38
Array< bool > ownedOperators
Definition multigrid.hpp:37
Array< Solver * > smoothers
Definition multigrid.hpp:36
Multigrid solver class.
Array< bool > ownedProlongations
Array< Operator * > prolongations
Arbitrary order H(curl)-conforming Nedelec finite elements.
Definition fe_coll.hpp:526
Type
Ordering methods:
Definition ordering.hpp:17
std::vector< Array< int > > ess_tdof_list
std::vector< std::vector< std::unique_ptr< PRefinementTransferOperator > > > T_level
const Array< ParFiniteElementSpace * > & pfes
std::vector< std::vector< std::unique_ptr< ParFiniteElementSpace > > > fes_owned
int GetFESpaceMinimumOrder(const ParFiniteElementSpace *pfespace) const
std::vector< std::vector< std::unique_ptr< FiniteElementCollection > > > fec_owned
std::vector< Array< int > > ess_bdr_marker
void BuildSpaceHierarchy(int mgmaxlevels=-1)
Computes orders/maxlevels and constructs fec/fes hierarchy and T_level storage.
BlockOperator * BuildProlongation(int lev)
Builds block-diagonal prolongation for level lev (coarse=lev, fine=lev+1). Its diagonal blocks are Hy...
const ParFiniteElementSpace * GetParFESpace(int lev, int b) const
PRefinementHierarchy(const Array< ParFiniteElementSpace * > &pfes_, const std::vector< Array< int > > &ess_bdr_marker_)
PRefinementMultigrid(const Array< ParFiniteElementSpace * > &pfes_, const std::vector< Array< int > > &ess_bdr_marker_, const BlockOperator &Op_, int mgmaxlevels=-1, real_t smoother_relax_factor=2.0/3, bool mumps_coarse_solver=false, int coarse_cg_max_iter=10, real_t coarse_cg_rel_tol=1e-3)
Abstract parallel finite element space.
Definition pfespace.hpp:31
void GetEssentialTrueDofs(const Array< int > &bdr_attr_is_ess, Array< int > &ess_tdof_list, int component=-1) const override
int GetTrueVSize() const override
Return the number of local vector true dofs.
Definition pfespace.hpp:365
ParMesh * GetParMesh() const
Definition pfespace.hpp:341
Arbitrary order H(div)-conforming Raviart-Thomas finite elements.
Definition fe_coll.hpp:430
Rectangular Operator for imposing essential boundary conditions on the input space using only the act...
Base class for solvers.
Definition operator.hpp:855
int dim
Definition ex24.cpp:53
real_t b
Definition lissajous.cpp:42
Solver * MakeFESpaceDefaultSolver(const ParFiniteElementSpace *pfespace, int print_level)
Creates a default solver for a given parallel FE space. The default solvers are the following:
void RAP(const DenseMatrix &A, const DenseMatrix &P, DenseMatrix &RAP)
HypreParMatrix * ParMult(const HypreParMatrix *A, const HypreParMatrix *B, bool own_matrix)
Definition hypre.cpp:3057
float real_t
Definition config.hpp:46
real_t p(const Vector &x, real_t t)