MFEM v4.8.0
Finite element discretization library
Loading...
Searching...
No Matches
div_free_solver.cpp
Go to the documentation of this file.
1// Copyright (c) 2010-2025, 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 "div_free_solver.hpp"
13
14using namespace std;
15
16namespace mfem
17{
18namespace blocksolvers
19{
21 const HypreParMatrix& P)
22{
23 OperatorPtr R(Rt.Transpose());
25 return ParMult(RA.As<HypreParMatrix>(), &P, true);
26}
27
28void GetRowColumnsRef(const SparseMatrix& A, int row, Array<int>& cols)
29{
30 cols.MakeRef(const_cast<int*>(A.GetRowColumns(row)), A.RowSize(row));
31}
32
34{
35 int* I = new int[fes.GetNE()+1];
36 copy_n(fes.GetElementToDofTable().GetI(), fes.GetNE()+1, I);
37 Array<int> J(new int[I[fes.GetNE()]], I[fes.GetNE()]);
38 copy_n(fes.GetElementToDofTable().GetJ(), J.Size(), J.begin());
39 fes.AdjustVDofs(J);
40 real_t* D = new real_t[J.Size()];
41 fill_n(D, J.Size(), 1.0);
42 return SparseMatrix(I, J, D, fes.GetNE(), fes.GetVSize());
43}
44
45DFSSpaces::DFSSpaces(int order, int num_refine, ParMesh *mesh,
46 const Array<int>& ess_attr, const DFSParameters& param)
47 : hdiv_fec_(order, mesh->Dimension()), l2_fec_(order, mesh->Dimension()),
48 l2_0_fec_(0, mesh->Dimension()), ess_bdr_attr_(ess_attr), level_(0)
49{
50 if (mesh->GetNE() > 0)
51 {
52 if (mesh->GetElement(0)->GetType() == Element::TETRAHEDRON && order)
53 {
54 MFEM_ABORT("DFSDataCollector: High order spaces on tetrahedra are not supported");
55 }
56 }
57
58 data_.param = param;
59
60 if (mesh->Dimension() == 3)
61 {
62 hcurl_fec_.reset(new ND_FECollection(order+1, mesh->Dimension()));
63 }
64 else
65 {
66 hcurl_fec_.reset(new H1_FECollection(order+1, mesh->Dimension()));
67 }
68
69 all_bdr_attr_.SetSize(ess_attr.Size(), 1);
70 hdiv_fes_.reset(new ParFiniteElementSpace(mesh, &hdiv_fec_));
71 l2_fes_.reset(new ParFiniteElementSpace(mesh, &l2_fec_));
72 coarse_hdiv_fes_.reset(new ParFiniteElementSpace(*hdiv_fes_));
73 coarse_l2_fes_.reset(new ParFiniteElementSpace(*l2_fes_));
74 l2_0_fes_.reset(new ParFiniteElementSpace(mesh, &l2_0_fec_));
75 l2_0_fes_->SetUpdateOperatorType(Operator::MFEM_SPARSEMAT);
76 el_l2dof_.reserve(num_refine+1);
77 el_l2dof_.push_back(ElemToDof(*coarse_l2_fes_));
78
79 data_.agg_hdivdof.resize(num_refine);
80 data_.agg_l2dof.resize(num_refine);
81 data_.P_hdiv.resize(num_refine, OperatorPtr(Operator::Hypre_ParCSR));
82 data_.P_l2.resize(num_refine, OperatorPtr(Operator::Hypre_ParCSR));
83 data_.Q_l2.resize(num_refine);
84 hdiv_fes_->GetEssentialTrueDofs(ess_attr, data_.coarsest_ess_hdivdofs);
85 data_.C.resize(num_refine+1);
86
87 hcurl_fes_.reset(new ParFiniteElementSpace(mesh, hcurl_fec_.get()));
88 coarse_hcurl_fes_.reset(new ParFiniteElementSpace(*hcurl_fes_));
89 data_.P_hcurl.resize(num_refine, OperatorPtr(Operator::Hypre_ParCSR));
90}
91
93 const SparseMatrix& agg_elem,
94 const SparseMatrix& elem_dof,
95 const HypreParMatrix& dof_truedof,
96 Array<HYPRE_BigInt>& agg_starts)
97{
98 OperatorPtr agg_dof(Mult(agg_elem, elem_dof));
99 SparseMatrix& agg_dof_ref = *agg_dof.As<SparseMatrix>();
100 OperatorPtr agg_tdof(dof_truedof.LeftDiagMult(agg_dof_ref, agg_starts));
101 OperatorPtr agg_tdof_T(agg_tdof.As<HypreParMatrix>()->Transpose());
102 SparseMatrix tdof_agg, is_shared;
103 HYPRE_BigInt* trash;
104 agg_tdof_T.As<HypreParMatrix>()->GetDiag(tdof_agg);
105 agg_tdof_T.As<HypreParMatrix>()->GetOffd(is_shared, trash);
106
107 int * I = new int [tdof_agg.NumRows()+1]();
108 int * J = new int[tdof_agg.NumNonZeroElems()];
109
110 Array<int> is_bdr;
111 FiniteElementSpace::ListToMarker(bdr_truedofs, tdof_agg.NumRows(), is_bdr);
112
113 int counter = 0;
114 for (int i = 0; i < tdof_agg.NumRows(); ++i)
115 {
116 bool agg_bdr = is_bdr[i] || is_shared.RowSize(i) || tdof_agg.RowSize(i)>1;
117 if (agg_bdr) { I[i+1] = I[i]; continue; }
118 I[i+1] = I[i] + 1;
119 J[counter++] = tdof_agg.GetRowColumns(i)[0];
120 }
121
122 real_t * D = new real_t[I[tdof_agg.NumRows()]];
123 std::fill_n(D, I[tdof_agg.NumRows()], 1.0);
124
125 SparseMatrix intdof_agg(I, J, D, tdof_agg.NumRows(), tdof_agg.NumCols());
126 return Transpose(intdof_agg);
127}
128
129void DFSSpaces::MakeDofRelationTables(int level)
130{
131 Array<HYPRE_BigInt> agg_starts(Array<HYPRE_BigInt>(l2_0_fes_->GetDofOffsets(),
132 2));
133 auto& elem_agg = (const SparseMatrix&)*l2_0_fes_->GetUpdateOperator();
134 OperatorPtr agg_elem(Transpose(elem_agg));
135 SparseMatrix& agg_el = *agg_elem.As<SparseMatrix>();
136
137 el_l2dof_.push_back(ElemToDof(*l2_fes_));
138 data_.agg_l2dof[level].Reset(Mult(agg_el, el_l2dof_[level+1]));
139
140 Array<int> bdr_tdofs;
141 hdiv_fes_->GetEssentialTrueDofs(all_bdr_attr_, bdr_tdofs);
142 auto tmp = AggToInteriorDof(bdr_tdofs, agg_el, ElemToDof(*hdiv_fes_),
143 *hdiv_fes_->Dof_TrueDof_Matrix(), agg_starts);
144 data_.agg_hdivdof[level].Reset(tmp);
145}
146
148{
149 auto GetP = [this](OperatorPtr& P, unique_ptr<ParFiniteElementSpace>& cfes,
150 ParFiniteElementSpace& fes, bool remove_zero)
151 {
152 fes.Update();
153 fes.GetTrueTransferOperator(*cfes, P);
154 if (remove_zero)
155 {
156 P.As<HypreParMatrix>()->DropSmallEntries(1e-16);
157 }
158 (level_ < (int)data_.P_l2.size()-1) ? cfes->Update() : cfes.reset();
159 };
160
161 GetP(data_.P_hdiv[level_], coarse_hdiv_fes_, *hdiv_fes_, true);
162 GetP(data_.P_l2[level_], coarse_l2_fes_, *l2_fes_, false);
163 MakeDofRelationTables(level_);
164
165 GetP(data_.P_hcurl[level_], coarse_hcurl_fes_, *hcurl_fes_, true);
166
167 ParDiscreteLinearOperator curl(hcurl_fes_.get(), hdiv_fes_.get());
169 curl.Assemble();
170 curl.Finalize();
171 data_.C[level_+1].Reset(curl.ParallelAssemble());
172 mfem::Array<int> ess_hcurl_tdof;
173 hcurl_fes_->GetEssentialTrueDofs(ess_bdr_attr_, ess_hcurl_tdof);
174 data_.C[level_+1].As<HypreParMatrix>()->EliminateCols(ess_hcurl_tdof);
175
176 ++level_;
177
178 if (level_ == (int)data_.P_l2.size()) { DataFinalize(); }
179}
180
181void DFSSpaces::DataFinalize()
182{
183 ParBilinearForm mass(l2_fes_.get());
184 mass.AddDomainIntegrator(new MassIntegrator());
185 mass.Assemble();
186 mass.Finalize();
187 OperatorPtr W(mass.LoseMat());
188
189 SparseMatrix P_l2;
190 for (int l = (int)data_.P_l2.size()-1; l >= 0; --l)
191 {
192 data_.P_l2[l].As<HypreParMatrix>()->GetDiag(P_l2);
193 OperatorPtr PT_l2(Transpose(P_l2));
194 auto PTW = Mult(*PT_l2.As<SparseMatrix>(), *W.As<SparseMatrix>());
195 auto cW = Mult(*PTW, P_l2);
196 auto cW_inv = new SymDirectSubBlockSolver(*cW, el_l2dof_[l]);
197 data_.Q_l2[l].Reset(new ProductOperator(cW_inv, PTW, true, true));
198 W.Reset(cW);
199 }
200
201 l2_0_fes_.reset();
202}
203
205 : Solver(B.NumRows()), BBT_solver_(B.GetComm())
206{
207 OperatorPtr BT(B.Transpose());
208 BBT_.Reset(ParMult(&B, BT.As<HypreParMatrix>()));
209 BBT_.As<HypreParMatrix>()->CopyColStarts();
210
211 BBT_prec_.Reset(new HypreBoomerAMG(*BBT_.As<HypreParMatrix>()));
212 BBT_prec_.As<HypreBoomerAMG>()->SetPrintLevel(0);
213
214 SetOptions(BBT_solver_, param);
215 BBT_solver_.SetOperator(*BBT_);
216 BBT_solver_.SetPreconditioner(*BBT_prec_.As<HypreBoomerAMG>());
217}
218
220 : Solver(M.NumRows()+B.NumRows()), local_system_(height), offset_(M.NumRows())
221{
222 local_system_.CopyMN(M, 0, 0);
223 local_system_.CopyMN(B, offset_, 0);
224 local_system_.CopyMNt(B, 0, offset_);
225
226 local_system_.SetRow(offset_, 0.0);
227 local_system_.SetCol(offset_, 0.0);
228 local_system_(offset_, offset_) = -1.0;
229 local_solver_.SetOperator(local_system_);
230}
231
232void LocalSolver::Mult(const Vector &x, Vector &y) const
233{
234 const real_t x0 = x[offset_];
235 const_cast<Vector&>(x)[offset_] = 0.0;
236
237 y.SetSize(local_system_.NumRows());
238 local_solver_.Mult(x, y);
239
240 const_cast<Vector&>(x)[offset_] = x0;
241}
242
244 const HypreParMatrix& B,
245 const SparseMatrix& agg_hdivdof,
246 const SparseMatrix& agg_l2dof,
247 const HypreParMatrix& P_l2,
248 const HypreParMatrix& Q_l2)
249 : Solver(M.NumRows() + B.NumRows()), agg_hdivdof_(agg_hdivdof),
250 agg_l2dof_(agg_l2dof), solvers_loc_(agg_l2dof.NumRows())
251{
252 coarse_l2_projector_.Reset(new ProductOperator(&P_l2, &Q_l2, false, false));
253
254 offsets_loc_.SetSize(3, 0);
255 offsets_.SetSize(3, 0);
256 offsets_[1] = M.NumRows();
257 offsets_[2] = M.NumRows() + B.NumRows();
258
259 SparseMatrix M_diag, B_diag;
260 M.GetDiag(M_diag);
261 B.GetDiag(B_diag);
262
263 DenseMatrix B_loc, M_loc;
264
265 for (int agg = 0; agg < (int)solvers_loc_.size(); agg++)
266 {
267 GetRowColumnsRef(agg_hdivdof_, agg, hdivdofs_loc_);
268 GetRowColumnsRef(agg_l2dof_, agg, l2dofs_loc_);
269 M_loc.SetSize(hdivdofs_loc_.Size(), hdivdofs_loc_.Size());
270 B_loc.SetSize(l2dofs_loc_.Size(), hdivdofs_loc_.Size());
271 M_diag.GetSubMatrix(hdivdofs_loc_, hdivdofs_loc_, M_loc);
272 B_diag.GetSubMatrix(l2dofs_loc_, hdivdofs_loc_, B_loc);
273 solvers_loc_[agg].Reset(new LocalSolver(M_loc, B_loc));
274 }
275}
276
277void SaddleSchwarzSmoother::Mult(const Vector & x, Vector & y) const
278{
279 y.SetSize(offsets_[2]);
280 y = 0.0;
281
282 BlockVector blk_y(y.GetData(), offsets_);
283 BlockVector Pi_x(offsets_); // aggregate-wise average free projection of x
284 static_cast<Vector&>(Pi_x) = x;
285
286 // Right hand side: F_l = F - W_l P_l2[l] (W_{l+1})^{-1} P_l2[l]^T F
287 // This ensures the existence of solutions to the local problems
288 Vector coarse_l2_projection(Pi_x.BlockSize(1));
289 coarse_l2_projector_->MultTranspose(Pi_x.GetBlock(1), coarse_l2_projection);
290
291 Pi_x.GetBlock(1) -= coarse_l2_projection;
292
293 for (int agg = 0; agg < (int)solvers_loc_.size(); agg++)
294 {
295 GetRowColumnsRef(agg_hdivdof_, agg, hdivdofs_loc_);
296 GetRowColumnsRef(agg_l2dof_, agg, l2dofs_loc_);
297
298 offsets_loc_[1] = hdivdofs_loc_.Size();
299 offsets_loc_[2] = offsets_loc_[1]+l2dofs_loc_.Size();
300
301 BlockVector rhs_loc(offsets_loc_), sol_loc(offsets_loc_);
302 Pi_x.GetBlock(0).GetSubVector(hdivdofs_loc_, rhs_loc.GetBlock(0));
303 Pi_x.GetBlock(1).GetSubVector(l2dofs_loc_, rhs_loc.GetBlock(1));
304
305 solvers_loc_[agg]->Mult(rhs_loc, sol_loc);
306
307 blk_y.GetBlock(0).AddElementVector(hdivdofs_loc_, sol_loc.GetBlock(0));
308 blk_y.GetBlock(1).AddElementVector(l2dofs_loc_, sol_loc.GetBlock(1));
309 }
310
311 coarse_l2_projector_->Mult(blk_y.GetBlock(1), coarse_l2_projection);
312 blk_y.GetBlock(1) -= coarse_l2_projection;
313}
314
316 const DFSData& data)
317 : DarcySolver(M.NumRows(), B.NumRows()), data_(data), param_(data.param),
318 BT_(B.Transpose()), BBT_solver_(B, param_.BBT_solve_param),
319 ops_offsets_(data.P_l2.size()+1), ops_(ops_offsets_.size()),
320 blk_Ps_(ops_.Size()-1), smoothers_(ops_.Size())
321{
322 ops_offsets_.back().MakeRef(DarcySolver::offsets_);
323 ops_.Last() = new BlockOperator(ops_offsets_.back());
324 ops_.Last()->SetBlock(0, 0, const_cast<HypreParMatrix*>(&M));
325 ops_.Last()->SetBlock(1, 0, const_cast<HypreParMatrix*>(&B));
326 ops_.Last()->SetBlock(0, 1, BT_.Ptr());
327
328 for (int l = data.P_l2.size(); l >= 0; --l)
329 {
330 auto& M_f = static_cast<const HypreParMatrix&>(ops_[l]->GetBlock(0, 0));
331 auto& B_f = static_cast<const HypreParMatrix&>(ops_[l]->GetBlock(1, 0));
332
333 if (l == 0)
334 {
335 SparseMatrix M_f_diag, B_f_diag;
336 M_f.GetDiag(M_f_diag);
337 B_f.GetDiag(B_f_diag);
338 for (int dof : data.coarsest_ess_hdivdofs)
339 {
340 M_f_diag.EliminateRowCol(dof);
341 B_f_diag.EliminateCol(dof);
342 }
343
344 const IterSolveParameters& param = param_.coarse_solve_param;
345 auto coarse_solver = new BDPMinresSolver(M_f, B_f, param);
346 if (ops_.Size() > 1)
347 {
348 coarse_solver->SetEssZeroDofs(data.coarsest_ess_hdivdofs);
349 }
350 smoothers_[l] = coarse_solver;
351 continue;
352 }
353
354 HypreParMatrix& P_hdiv_l = *data.P_hdiv[l-1].As<HypreParMatrix>();
355 HypreParMatrix& P_l2_l = *data.P_l2[l-1].As<HypreParMatrix>();
356 SparseMatrix& agg_hdivdof_l = *data.agg_hdivdof[l-1].As<SparseMatrix>();
357 SparseMatrix& agg_l2dof_l = *data.agg_l2dof[l-1].As<SparseMatrix>();
358 HypreParMatrix& Q_l2_l = *data.Q_l2[l-1].As<HypreParMatrix>();
359 HypreParMatrix* C_l = data.C[l].As<HypreParMatrix>();
360
361 auto S0 = new SaddleSchwarzSmoother(M_f, B_f, agg_hdivdof_l,
362 agg_l2dof_l, P_l2_l, Q_l2_l);
363 if (param_.coupled_solve)
364 {
365 auto S1 = new BlockDiagonalPreconditioner(ops_offsets_[l]);
366 S1->SetDiagonalBlock(0, new AuxSpaceSmoother(M_f, C_l));
367 S1->owns_blocks = true;
368 smoothers_[l] = new ProductSolver(ops_[l], S0, S1, false, true, true);
369 }
370 else
371 {
372 smoothers_[l] = S0;
373 }
374
375 HypreParMatrix* M_c = TwoStepsRAP(P_hdiv_l, M_f, P_hdiv_l);
376 HypreParMatrix* B_c = TwoStepsRAP(P_l2_l, B_f, P_hdiv_l);
377
378 ops_offsets_[l-1].SetSize(3, 0);
379 ops_offsets_[l-1][1] = M_c->NumRows();
380 ops_offsets_[l-1][2] = M_c->NumRows() + B_c->NumRows();
381
382 blk_Ps_[l-1] = new BlockOperator(ops_offsets_[l], ops_offsets_[l-1]);
383 blk_Ps_[l-1]->SetBlock(0, 0, &P_hdiv_l);
384 blk_Ps_[l-1]->SetBlock(1, 1, &P_l2_l);
385
386 ops_[l-1] = new BlockOperator(ops_offsets_[l-1]);
387 ops_[l-1]->SetBlock(0, 0, M_c);
388 ops_[l-1]->SetBlock(1, 0, B_c);
389 ops_[l-1]->SetBlock(0, 1, B_c->Transpose());
390 ops_[l-1]->owns_blocks = true;
391 }
392
393 Array<bool> own_ops(ops_.Size());
394 Array<bool> own_smoothers(smoothers_.Size());
395 Array<bool> own_Ps(blk_Ps_.Size());
396 own_ops = true;
397 own_smoothers = true;
398 own_Ps = true;
399
400 if (data_.P_l2.size() == 0) { return; }
401
402 if (param_.coupled_solve)
403 {
404 solver_.Reset(new GMRESSolver(B.GetComm()));
405 solver_.As<GMRESSolver>()->SetOperator(*(ops_.Last()));
406 prec_.Reset(new Multigrid(ops_, smoothers_, blk_Ps_,
407 own_ops, own_smoothers, own_Ps));
408 }
409 else
410 {
411 Array<HypreParMatrix*> ops(data_.P_hcurl.size()+1);
412 Array<Solver*> smoothers(ops.Size());
413 Array<HypreParMatrix*> Ps(data_.P_hcurl.size());
414 own_Ps = false;
415
416 HypreParMatrix& C_finest = *data.C.back().As<HypreParMatrix>();
417 ops.Last() = TwoStepsRAP(C_finest, M, C_finest);
418 ops.Last()->EliminateZeroRows();
419 ops.Last()->DropSmallEntries(1e-14);
420
421 solver_.Reset(new CGSolver(B.GetComm()));
422 solver_.As<CGSolver>()->SetOperator(*ops.Last());
423 smoothers.Last() = new HypreSmoother(*ops.Last());
424 static_cast<HypreSmoother*>(smoothers.Last())->SetOperatorSymmetry(true);
425
426 for (int l = Ps.Size()-1; l >= 0; --l)
427 {
428 Ps[l] = data_.P_hcurl[l].As<HypreParMatrix>();
429 ops[l] = TwoStepsRAP(*Ps[l], *ops[l+1], *Ps[l]);
430 ops[l]->DropSmallEntries(1e-14);
431 smoothers[l] = new HypreSmoother(*ops[l]);
432 static_cast<HypreSmoother*>(smoothers[l])->SetOperatorSymmetry(true);
433 }
434
435 prec_.Reset(new Multigrid(ops, smoothers, Ps, own_ops, own_smoothers, own_Ps));
436 }
437
438 solver_.As<IterativeSolver>()->SetPreconditioner(*prec_.As<Solver>());
439 SetOptions(*solver_.As<IterativeSolver>(), param_);
440}
441
443{
444 if (param_.coupled_solve) { return; }
445 for (int i = 0; i < ops_.Size(); ++i)
446 {
447 delete ops_[i];
448 delete smoothers_[i];
449 if (i == ops_.Size() - 1) { break; }
450 delete blk_Ps_[i];
451 }
452}
453
454void DivFreeSolver::SolveParticular(const Vector& rhs, Vector& sol) const
455{
456 std::vector<Vector> rhss(smoothers_.Size());
457 std::vector<Vector> sols(smoothers_.Size());
458
459 rhss.back().SetDataAndSize(const_cast<real_t*>(rhs.HostRead()), rhs.Size());
460 sols.back().SetDataAndSize(sol.HostWrite(), sol.Size());
461
462 for (int l = blk_Ps_.Size()-1; l >= 0; --l)
463 {
464 rhss[l].SetSize(blk_Ps_[l]->NumCols());
465 sols[l].SetSize(blk_Ps_[l]->NumCols());
466
467 sols[l] = 0.0;
468 rhss[l] = 0.0;
469
470 blk_Ps_[l]->MultTranspose(rhss[l+1], rhss[l]);
471 }
472
473 for (int l = 0; l < smoothers_.Size(); ++l)
474 {
475 smoothers_[l]->Mult(rhss[l], sols[l]);
476 }
477
478 for (int l = 0; l < blk_Ps_.Size(); ++l)
479 {
480 Vector P_sol(blk_Ps_[l]->NumRows());
481 blk_Ps_[l]->Mult(sols[l], P_sol);
482 sols[l+1] += P_sol;
483 }
484}
485
486void DivFreeSolver::SolveDivFree(const Vector &rhs, Vector& sol) const
487{
488 Vector rhs_divfree(data_.C.back()->NumCols());
489 data_.C.back()->MultTranspose(rhs, rhs_divfree);
490
491 Vector potential_divfree(rhs_divfree.Size());
492 potential_divfree = 0.0;
493 solver_->Mult(rhs_divfree, potential_divfree);
494
495 data_.C.back()->Mult(potential_divfree, sol);
496}
497
498void DivFreeSolver::SolvePotential(const Vector& rhs, Vector& sol) const
499{
500 Vector rhs_p(BT_->NumCols());
501 BT_->MultTranspose(rhs, rhs_p);
502 BBT_solver_.Mult(rhs_p, sol);
503}
504
505void DivFreeSolver::Mult(const Vector & x, Vector & y) const
506{
507 MFEM_VERIFY(x.Size() == offsets_[2], "MLDivFreeSolver: x size is invalid");
508 MFEM_VERIFY(y.Size() == offsets_[2], "MLDivFreeSolver: y size is invalid");
509
510 if (ops_.Size() == 1) { smoothers_[0]->Mult(x, y); return; }
511
512 BlockVector blk_y(y, offsets_);
513
514 BlockVector resid(offsets_);
515 ops_.Last()->Mult(y, resid);
516 add(1.0, x, -1.0, resid, resid);
517
518 BlockVector correction(offsets_);
519 correction = 0.0;
520
521 if (param_.coupled_solve)
522 {
523 solver_->Mult(resid, correction);
524 y += correction;
525 }
526 else
527 {
528 StopWatch ch;
529 ch.Start();
530
531 SolveParticular(resid, correction);
532 blk_y += correction;
533
534 if (param_.verbose)
535 {
536 cout << "Particular solution found in " << ch.RealTime() << "s.\n";
537 }
538
539 ch.Clear();
540 ch.Start();
541
542 ops_.Last()->Mult(y, resid);
543 add(1.0, x, -1.0, resid, resid);
544
545 SolveDivFree(resid.GetBlock(0), correction.GetBlock(0));
546 blk_y.GetBlock(0) += correction.GetBlock(0);
547
548 if (param_.verbose)
549 {
550 cout << "Divergence free solution found in " << ch.RealTime() << "s.\n";
551 }
552
553 ch.Clear();
554 ch.Start();
555
556 auto& M = dynamic_cast<const HypreParMatrix&>(ops_.Last()->GetBlock(0, 0));
557 M.Mult(-1.0, correction.GetBlock(0), 1.0, resid.GetBlock(0));
558 SolvePotential(resid.GetBlock(0), correction.GetBlock(1));
559 blk_y.GetBlock(1) += correction.GetBlock(1);
560
561 if (param_.verbose)
562 {
563 cout << "Scalar potential found in " << ch.RealTime() << "s.\n";
564 }
565 }
566}
567
569{
570 if (ops_.Size() == 1)
571 {
572 return static_cast<BDPMinresSolver*>(smoothers_[0])->GetNumIterations();
573 }
574 return solver_.As<IterativeSolver>()->GetNumIterations();
575}
576} // namespace blocksolvers
577} // namespace mfem
void SetSize(int nsize)
Change the logical size of the array, keep existing entries.
Definition array.hpp:758
int Size() const
Return the logical size of the array.
Definition array.hpp:147
void MakeRef(T *data_, int size_, bool own_data=false)
Make this Array a reference to a pointer.
Definition array.hpp:943
T * begin()
STL-like begin. Returns pointer to the first element of the array.
Definition array.hpp:322
T & Last()
Return the last element in the array.
Definition array.hpp:863
A class to handle Block diagonal preconditioners in a matrix-free implementation.
A class to handle Block systems in a matrix-free implementation.
A class to handle Vectors in a block fashion.
Vector & GetBlock(int i)
Get the i-th vector in the block.
Conjugate gradient method.
Definition solvers.hpp:538
void SetOperator(const Operator &op) override
Set/update the solver for the given operator.
Definition solvers.hpp:551
void Mult(const real_t *x, real_t *y) const
Matrix vector multiplication with the inverse of dense matrix.
void SetOperator(const Operator &op) override
Set/update the solver for the given operator.
Data type dense matrix using column-major storage.
Definition densemat.hpp:24
void SetRow(int r, const real_t *row)
void SetSize(int s)
Change the size of the DenseMatrix to s x s.
Definition densemat.hpp:108
void SetCol(int c, const real_t *col)
void CopyMNt(const DenseMatrix &A, int row_offset, int col_offset)
Copy matrix A^t to the location in *this at row_offset, col_offset.
void CopyMN(const DenseMatrix &A, int m, int n, int Aro, int Aco)
Copy the m x n submatrix of A at row/col offsets Aro/Aco to *this.
void AddDomainInterpolator(DiscreteInterpolator *di)
Adds a domain interpolator. Assumes ownership of di.
virtual void Assemble(int skip_zeros=1)
Construct the internal matrix representation of the discrete linear operator.
virtual Type GetType() const =0
Returns element's type.
const Table & GetElementToDofTable() const
Return a reference to the internal Table that stores the lists of scalar dofs, for each mesh element,...
Definition fespace.hpp:1287
static void AdjustVDofs(Array< int > &vdofs)
Remove the orientation information encoded into an array of dofs Some basis function types have a rel...
Definition fespace.cpp:310
static void ListToMarker(const Array< int > &list, int marker_size, Array< int > &marker, int mark_val=-1)
Convert an array of indices (list) to a Boolean marker array where all indices in the list are marked...
Definition fespace.cpp:809
int GetNE() const
Returns number of elements in the mesh.
Definition fespace.hpp:891
int GetVSize() const
Return the number of vector dofs, i.e. GetNDofs() x GetVDim().
Definition fespace.hpp:848
GMRES method.
Definition solvers.hpp:572
Arbitrary order H1-conforming (continuous) finite elements.
Definition fe_coll.hpp:275
The BoomerAMG solver in hypre.
Definition hypre.hpp:1717
Wrapper for hypre's ParCSR matrix class.
Definition hypre.hpp:408
void DropSmallEntries(real_t tol)
Wrapper for hypre_ParCSRMatrixDropSmallEntries in different versions of hypre. Drop off-diagonal entr...
Definition hypre.cpp:2350
void GetDiag(Vector &diag) const
Get the local diagonal of the matrix.
Definition hypre.cpp:1605
HypreParMatrix * LeftDiagMult(const SparseMatrix &D, HYPRE_BigInt *row_starts=NULL) const
Multiply the HypreParMatrix on the left by a block-diagonal parallel matrix D and return the result a...
Definition hypre.cpp:2040
HYPRE_Int Mult(HypreParVector &x, HypreParVector &y, real_t alpha=1.0, real_t beta=0.0) const
Computes y = alpha * A * x + beta * y.
Definition hypre.cpp:1861
MPI_Comm GetComm() const
MPI communicator.
Definition hypre.hpp:598
HypreParMatrix * Transpose() const
Returns the transpose of *this.
Definition hypre.cpp:1730
Parallel smoothers in hypre.
Definition hypre.hpp:1046
Abstract base class for iterative solver.
Definition solvers.hpp:86
virtual void SetPreconditioner(Solver &pr)
This should be called before SetOperator.
Definition solvers.cpp:174
const Element * GetElement(int i) const
Return pointer to the i'th element object.
Definition mesh.hpp:1339
int GetNE() const
Returns number of elements.
Definition mesh.hpp:1282
int Dimension() const
Dimension of the reference space used within the elements.
Definition mesh.hpp:1216
void Finalize(int skip_zeros=1) override
Finalizes the matrix initialization if the AssemblyLevel is AssemblyLevel::LEGACY.
Multigrid solver class.
Arbitrary order H(curl)-conforming Nedelec finite elements.
Definition fe_coll.hpp:482
Pointer to an Operator of a specified type.
Definition handle.hpp:34
OpType * As() const
Return the Operator pointer statically cast to a specified OpType. Similar to the method Get().
Definition handle.hpp:104
Operator * Ptr() const
Access the underlying Operator pointer.
Definition handle.hpp:87
void Reset(OpType *A, bool own_A=true)
Reset the OperatorHandle to the given OpType pointer, A.
Definition handle.hpp:145
virtual void Mult(const Vector &x, Vector &y) const =0
Operator application: y=A(x).
int NumCols() const
Get the number of columns (size of input) of the Operator. Synonym with Width().
Definition operator.hpp:75
@ MFEM_SPARSEMAT
ID for class SparseMatrix.
Definition operator.hpp:286
@ Hypre_ParCSR
ID for class HypreParMatrix.
Definition operator.hpp:287
int NumRows() const
Get the number of rows (size of output) of the Operator. Synonym with Height().
Definition operator.hpp:69
virtual void MultTranspose(const Vector &x, Vector &y) const
Action of the transpose operator: y=A^t(x). The default behavior in class Operator is to generate an ...
Definition operator.hpp:93
Class for parallel bilinear form.
HypreParMatrix * ParallelAssemble() const
Returns the matrix "assembled" on the true dofs.
Abstract parallel finite element space.
Definition pfespace.hpp:29
Class for parallel meshes.
Definition pmesh.hpp:34
General product operator: x -> (A*B)(x) = A(B(x)).
Definition operator.hpp:894
Base class for solvers.
Definition operator.hpp:780
Data type sparse matrix.
Definition sparsemat.hpp:51
void GetDiag(Vector &d) const
Returns the Diagonal of A.
void EliminateRowCol(int rc, const real_t sol, Vector &rhs, DiagonalPolicy dpolicy=DIAG_ONE)
Eliminate row rc and column rc and modify the rhs using sol.
void GetSubMatrix(const Array< int > &rows, const Array< int > &cols, DenseMatrix &subm) const
int NumNonZeroElems() const override
Returns the number of the nonzero elements in the matrix.
void EliminateCol(int col, DiagonalPolicy dpolicy=DIAG_ZERO)
Eliminates the column col from the matrix.
int * GetRowColumns(const int row)
Return a pointer to the column indices in a row.
int RowSize(const int i) const
Returns the number of elements in row i.
Timing object.
Definition tic_toc.hpp:36
double RealTime()
Return the number of real seconds elapsed since the stopwatch was started.
Definition tic_toc.cpp:432
void Start()
Start the stopwatch. The elapsed time is not cleared.
Definition tic_toc.cpp:411
void Clear()
Clear the elapsed time on the stopwatch and restart it if it's running.
Definition tic_toc.cpp:406
int * GetJ()
Definition table.hpp:122
int * GetI()
Definition table.hpp:121
Vector data type.
Definition vector.hpp:82
virtual const real_t * HostRead() const
Shortcut for mfem::Read(vec.GetMemory(), vec.Size(), false).
Definition vector.hpp:498
void AddElementVector(const Array< int > &dofs, const Vector &elemvect)
Add elements of the elemvect Vector to the entries listed in dofs. Negative dof values cause the -dof...
Definition vector.cpp:745
int Size() const
Returns the size of the vector.
Definition vector.hpp:226
void SetSize(int s)
Resize the vector to size s.
Definition vector.hpp:558
virtual real_t * HostWrite()
Shortcut for mfem::Write(vec.GetMemory(), vec.Size(), false).
Definition vector.hpp:506
real_t * GetData() const
Return a pointer to the beginning of the Vector data.
Definition vector.hpp:235
void GetSubVector(const Array< int > &dofs, Vector &elemvect) const
Extract entries listed in dofs to the output Vector elemvect.
Definition vector.cpp:653
void Mult(const Vector &x, Vector &y) const override
Operator application: y=A(x).
BBTSolver(const HypreParMatrix &B, IterSolveParameters param)
Wrapper for the block-diagonal-preconditioned MINRES employed in ex5p.cpp.
DFSSpaces(int order, int num_refine, ParMesh *mesh, const Array< int > &ess_attr, const DFSParameters &param)
Abstract solver class for Darcy's flow.
void SetOperator(const Operator &op) override
Set/update the solver for the given operator.
DivFreeSolver(const HypreParMatrix &M, const HypreParMatrix &B, const DFSData &data)
void Mult(const Vector &x, Vector &y) const override
Operator application: y=A(x).
Solver for local problems in SaddleSchwarzSmoother.
void Mult(const Vector &x, Vector &y) const override
Operator application: y=A(x).
LocalSolver(const DenseMatrix &M, const DenseMatrix &B)
void Mult(const Vector &x, Vector &y) const override
Operator application: y=A(x).
SaddleSchwarzSmoother(const HypreParMatrix &M, const HypreParMatrix &B, const SparseMatrix &agg_hdivdof, const SparseMatrix &agg_l2dof, const HypreParMatrix &P_l2, const HypreParMatrix &Q_l2)
Block diagonal solver for symmetric A, each block is inverted by direct solver.
HYPRE_Int HYPRE_BigInt
HypreParMatrix * TwoStepsRAP(const HypreParMatrix &Rt, const HypreParMatrix &A, const HypreParMatrix &P)
void SetOptions(IterativeSolver &solver, const IterSolveParameters &param)
void GetRowColumnsRef(const SparseMatrix &A, int row, Array< int > &cols)
SparseMatrix * AggToInteriorDof(const Array< int > &bdr_truedofs, const SparseMatrix &agg_elem, const SparseMatrix &elem_dof, const HypreParMatrix &dof_truedof, Array< HYPRE_BigInt > &agg_starts)
SparseMatrix ElemToDof(const ParFiniteElementSpace &fes)
OperatorHandle OperatorPtr
Add an alternative name for OperatorHandle – OperatorPtr.
Definition handle.hpp:212
void Mult(const Table &A, const Table &B, Table &C)
C = A * B (as boolean matrices)
Definition table.cpp:548
void add(const Vector &v1, const Vector &v2, Vector &v)
Definition vector.cpp:391
void Transpose(const Table &A, Table &At, int ncols_A_)
Transpose a Table.
Definition table.cpp:486
HypreParMatrix * ParMult(const HypreParMatrix *A, const HypreParMatrix *B, bool own_matrix)
Definition hypre.cpp:3007
float real_t
Definition config.hpp:43
Data for the divergence free solver.
std::vector< OperatorPtr > agg_l2dof
std::vector< OperatorPtr > P_hcurl
std::vector< OperatorPtr > P_hdiv
std::vector< OperatorPtr > P_l2
std::vector< OperatorPtr > Q_l2
std::vector< OperatorPtr > agg_hdivdof
std::vector< OperatorPtr > C
Parameters for the divergence free solver.