MFEM v4.9.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::blocksolvers
17{
18
19static HypreParMatrix* TwoStepsRAP(const HypreParMatrix *Rt,
20 const HypreParMatrix *A,
21 const HypreParMatrix *P)
22{
23 OperatorPtr R(Rt->Transpose());
24 OperatorPtr RA(ParMult(R.As<HypreParMatrix>(), A));
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_ = std::make_unique<ND_FECollection>(order+1, mesh->Dimension());
63 }
64 else
65 {
66 hcurl_fec_ = std::make_unique<H1_FECollection>(order+1, mesh->Dimension());
67 }
68
69 all_bdr_attr_.SetSize(ess_attr.Size(), 1);
70 hdiv_fes_ = std::make_unique<ParFiniteElementSpace>(mesh, &hdiv_fec_);
71 l2_fes_ = std::make_unique<ParFiniteElementSpace>(mesh, &l2_fec_);
72 coarse_hdiv_fes_ = std::make_unique<ParFiniteElementSpace>(*hdiv_fes_);
73 coarse_l2_fes_ = std::make_unique<ParFiniteElementSpace>(*l2_fes_);
74 l2_0_fes_ = std::make_unique<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);
82 data_.P_l2.resize(num_refine);
83
84 data_.Q_l2.resize(num_refine);
85 hdiv_fes_->GetEssentialTrueDofs(ess_attr, data_.coarsest_ess_hdivdofs);
86 data_.C.resize(num_refine+1);
87 data_.Ae.resize(num_refine+1);
88
89 hcurl_fes_ = std::make_unique<ParFiniteElementSpace>(mesh, hcurl_fec_.get());
90 coarse_hcurl_fes_ = std::make_unique<ParFiniteElementSpace>(*hcurl_fes_);
91 data_.P_hcurl.resize(num_refine);
92}
93
95 const SparseMatrix& agg_elem,
96 const SparseMatrix& elem_dof,
97 const HypreParMatrix& dof_truedof,
98 Array<HYPRE_BigInt>& agg_starts)
99{
100 OperatorPtr agg_dof(Mult(agg_elem, elem_dof));
101 SparseMatrix& agg_dof_ref = *agg_dof.As<SparseMatrix>();
102 OperatorPtr agg_tdof(dof_truedof.LeftDiagMult(agg_dof_ref, agg_starts));
103 OperatorPtr agg_tdof_T(agg_tdof.As<HypreParMatrix>()->Transpose());
104 SparseMatrix tdof_agg, is_shared;
105 HYPRE_BigInt* trash;
106 agg_tdof_T.As<HypreParMatrix>()->GetDiag(tdof_agg);
107 agg_tdof_T.As<HypreParMatrix>()->GetOffd(is_shared, trash);
108
109 int *I = new int[tdof_agg.NumRows()+1]();
110 int *J = new int[tdof_agg.NumNonZeroElems()];
111
112 Array<int> is_bdr;
113 FiniteElementSpace::ListToMarker(bdr_truedofs, tdof_agg.NumRows(), is_bdr);
114
115 int counter = 0;
116 for (int i = 0; i < tdof_agg.NumRows(); ++i)
117 {
118 bool agg_bdr = is_bdr[i] || is_shared.RowSize(i) || tdof_agg.RowSize(i)>1;
119 if (agg_bdr) { I[i+1] = I[i]; continue; }
120 I[i+1] = I[i] + 1;
121 J[counter++] = tdof_agg.GetRowColumns(i)[0];
122 }
123
124 auto *D = new real_t[I[tdof_agg.NumRows()]];
125 std::fill_n(D, I[tdof_agg.NumRows()], 1.0);
126
127 SparseMatrix intdof_agg(I, J, D, tdof_agg.NumRows(), tdof_agg.NumCols());
128 return Transpose(intdof_agg);
129}
130
131void DFSSpaces::MakeDofRelationTables(int level)
132{
133 Array<HYPRE_BigInt> agg_starts(Array<HYPRE_BigInt>(l2_0_fes_->GetDofOffsets(),
134 2));
135 auto& elem_agg = (const SparseMatrix&)*l2_0_fes_->GetUpdateOperator();
136 OperatorPtr agg_elem(Transpose(elem_agg));
137 SparseMatrix& agg_el = *agg_elem.As<SparseMatrix>();
138
139 el_l2dof_.push_back(ElemToDof(*l2_fes_));
140 data_.agg_l2dof[level].Reset(Mult(agg_el, el_l2dof_[level+1]));
141
142 Array<int> bdr_tdofs;
143 hdiv_fes_->GetEssentialTrueDofs(all_bdr_attr_, bdr_tdofs);
144 auto tmp = AggToInteriorDof(bdr_tdofs, agg_el, ElemToDof(*hdiv_fes_),
145 *hdiv_fes_->Dof_TrueDof_Matrix(), agg_starts);
146 data_.agg_hdivdof[level].Reset(tmp);
147}
148
150{
151 auto GetP = [&](std::unique_ptr<OperatorPtr> &P,
152 std::unique_ptr<ParFiniteElementSpace> &cfes,
153 ParFiniteElementSpace& fes, const bool remove_zero)
154 {
155 fes.Update();
157 fes.GetTrueTransferOperator(*cfes, *T);
158 P.reset(T);
159 if (remove_zero) { P->As<HypreParMatrix>()->DropSmallEntries(1e-16); }
160 (level_ < (int)data_.P_l2.size()-1) ? cfes->Update() : cfes.reset();
161 };
162
163 GetP(data_.P_hdiv[level_], coarse_hdiv_fes_, *hdiv_fes_, true);
164 GetP(data_.P_l2[level_], coarse_l2_fes_, *l2_fes_, false);
165
166 MakeDofRelationTables(level_);
167
168 GetP(data_.P_hcurl[level_], coarse_hcurl_fes_, *hcurl_fes_, true);
169
170 ParDiscreteLinearOperator curl(hcurl_fes_.get(), hdiv_fes_.get());
172 curl.Assemble();
173 curl.Finalize();
174 data_.C[level_+1].Reset(curl.ParallelAssemble());
175 mfem::Array<int> ess_hcurl_tdof;
176 hcurl_fes_->GetEssentialTrueDofs(ess_bdr_attr_, ess_hcurl_tdof);
177 data_.Ae[level_+1].reset(
178 data_.C[level_+1].As<HypreParMatrix>()
179 ->EliminateCols(ess_hcurl_tdof));
180
181 ++level_;
182
183 if (level_ == (int)data_.P_l2.size()) { DataFinalize(); }
184}
185
186void DFSSpaces::DataFinalize()
187{
188 ParBilinearForm mass(l2_fes_.get());
189 mass.AddDomainIntegrator(new MassIntegrator());
190 mass.Assemble();
191 mass.Finalize();
192 OperatorPtr W(mass.LoseMat());
193
194 SparseMatrix P_l2;
195 for (int l = (int)data_.P_l2.size()-1; l >= 0; --l)
196 {
197 data_.P_l2[l]->As<HypreParMatrix>()->GetDiag(P_l2);
198 OperatorPtr PT_l2(Transpose(P_l2));
199 auto PTW = Mult(*PT_l2.As<SparseMatrix>(), *W.As<SparseMatrix>());
200 auto cW = Mult(*PTW, P_l2);
201 auto cW_inv = new SymDirectSubBlockSolver(*cW, el_l2dof_[l]);
202 data_.Q_l2[l].Reset(new ProductOperator(cW_inv, PTW, true, true));
203 W.Reset(cW);
204 }
205
206 l2_0_fes_.reset();
207}
208
210 : Solver(B.NumRows()), BBT_solver_(B.GetComm())
211{
212 OperatorPtr BT(B.Transpose());
213 BBT_.Reset(ParMult(&B, BT.As<HypreParMatrix>()));
214 BBT_.As<HypreParMatrix>()->CopyColStarts();
215
216 BBT_prec_.Reset(new HypreBoomerAMG(*BBT_.As<HypreParMatrix>()));
217 BBT_prec_.As<HypreBoomerAMG>()->SetPrintLevel(0);
218
219 SetOptions(BBT_solver_, param);
220 BBT_solver_.SetOperator(*BBT_);
221 BBT_solver_.SetPreconditioner(*BBT_prec_.As<HypreBoomerAMG>());
222}
223
225 : Solver(M.NumRows()+B.NumRows()), local_system_(height), offset_(M.NumRows())
226{
227 local_system_.CopyMN(M, 0, 0);
228 local_system_.CopyMN(B, offset_, 0);
229 local_system_.CopyMNt(B, 0, offset_);
230
231 local_system_.SetRow(offset_, 0.0);
232 local_system_.SetCol(offset_, 0.0);
233 local_system_(offset_, offset_) = -1.0;
234 local_solver_.SetOperator(local_system_);
235}
236
237void LocalSolver::Mult(const Vector &x, Vector &y) const
238{
239 const real_t x0 = x[offset_];
240 const_cast<Vector&>(x)[offset_] = 0.0;
241
242 y.SetSize(local_system_.NumRows());
243 local_solver_.Mult(x, y);
244
245 const_cast<Vector&>(x)[offset_] = x0;
246}
247
249 const HypreParMatrix& B,
250 const SparseMatrix& agg_hdivdof,
251 const SparseMatrix& agg_l2dof,
252 const HypreParMatrix& P_l2,
253 const ProductOperator& Q_l2)
254 : Solver(M.NumRows() + B.NumRows()), agg_hdivdof_(agg_hdivdof),
255 agg_l2dof_(agg_l2dof), solvers_loc_(agg_l2dof.NumRows())
256{
257 coarse_l2_projector_.Reset(new ProductOperator(&P_l2, &Q_l2, false, false));
258
259 offsets_loc_.SetSize(3, 0);
260 offsets_.SetSize(3, 0);
261 offsets_[1] = M.NumRows();
262 offsets_[2] = M.NumRows() + B.NumRows();
263
264 SparseMatrix M_diag, B_diag;
265 M.GetDiag(M_diag);
266 B.GetDiag(B_diag);
267
268 DenseMatrix B_loc, M_loc;
269
270 for (int agg = 0; agg < (int)solvers_loc_.size(); agg++)
271 {
272 GetRowColumnsRef(agg_hdivdof_, agg, hdivdofs_loc_);
273 GetRowColumnsRef(agg_l2dof_, agg, l2dofs_loc_);
274 M_loc.SetSize(hdivdofs_loc_.Size(), hdivdofs_loc_.Size());
275 B_loc.SetSize(l2dofs_loc_.Size(), hdivdofs_loc_.Size());
276 M_diag.GetSubMatrix(hdivdofs_loc_, hdivdofs_loc_, M_loc);
277 B_diag.GetSubMatrix(l2dofs_loc_, hdivdofs_loc_, B_loc);
278 solvers_loc_[agg].Reset(new LocalSolver(M_loc, B_loc));
279 }
280}
281
282void SaddleSchwarzSmoother::Mult(const Vector & x, Vector & y) const
283{
284 y.SetSize(offsets_[2]);
285 y = 0.0;
286
287 BlockVector blk_y(y.GetData(), offsets_);
288 BlockVector Pi_x(offsets_); // aggregate-wise average free projection of x
289 static_cast<Vector&>(Pi_x) = x;
290
291 // Right hand side: F_l = F - W_l P_l2[l] (W_{l+1})^{-1} P_l2[l]^T F
292 // This ensures the existence of solutions to the local problems
293 Vector coarse_l2_projection(Pi_x.BlockSize(1));
294 coarse_l2_projector_->MultTranspose(Pi_x.GetBlock(1), coarse_l2_projection);
295
296 Pi_x.GetBlock(1) -= coarse_l2_projection;
297
298 for (int agg = 0; agg < (int)solvers_loc_.size(); agg++)
299 {
300 GetRowColumnsRef(agg_hdivdof_, agg, hdivdofs_loc_);
301 GetRowColumnsRef(agg_l2dof_, agg, l2dofs_loc_);
302
303 offsets_loc_[1] = hdivdofs_loc_.Size();
304 offsets_loc_[2] = offsets_loc_[1]+l2dofs_loc_.Size();
305
306 BlockVector rhs_loc(offsets_loc_), sol_loc(offsets_loc_);
307 Pi_x.GetBlock(0).GetSubVector(hdivdofs_loc_, rhs_loc.GetBlock(0));
308 Pi_x.GetBlock(1).GetSubVector(l2dofs_loc_, rhs_loc.GetBlock(1));
309
310 solvers_loc_[agg]->Mult(rhs_loc, sol_loc);
311
312 blk_y.GetBlock(0).AddElementVector(hdivdofs_loc_, sol_loc.GetBlock(0));
313 blk_y.GetBlock(1).AddElementVector(l2dofs_loc_, sol_loc.GetBlock(1));
314 }
315
316 coarse_l2_projector_->Mult(blk_y.GetBlock(1), coarse_l2_projection);
317 blk_y.GetBlock(1) -= coarse_l2_projection;
318}
319
321 const HypreParMatrix &B,
322 const DFSData& data)
323 : DarcySolver(M.NumRows(), B.NumRows()), data_(data), param_(data.param),
324 BT_(B.Transpose()),
325 BBT_solver_(B, param_.BBT_solve_param),
326 ops_offsets_(data.P_l2.size()+1),
327 ops_(ops_offsets_.size()),
328 blk_Ps_(ops_.size()-1),
329 smoothers_(ops_.size())
330{
331 ops_offsets_.back().MakeRef(DarcySolver::offsets_);
332 ops_.back() = std::make_unique<BlockOperator>(ops_offsets_.back());
333 ops_.back()->SetBlock(0, 0, const_cast<HypreParMatrix*>(&M));
334 ops_.back()->SetBlock(1, 0, const_cast<HypreParMatrix*>(&B));
335 ops_.back()->SetBlock(0, 1, BT_.Ptr());
336
337 for (int l = data.P_l2.size(); l >= 0; --l)
338 {
339 auto &M_f = static_cast<const HypreParMatrix&>(ops_[l]->GetBlock(0, 0));
340 auto &B_f = static_cast<const HypreParMatrix&>(ops_[l]->GetBlock(1, 0));
341
342 if (l == 0)
343 {
344 SparseMatrix M_f_diag, B_f_diag;
345 M_f.GetDiag(M_f_diag);
346 B_f.GetDiag(B_f_diag);
347 for (int dof : data.coarsest_ess_hdivdofs)
348 {
349 M_f_diag.EliminateRowCol(dof);
350 B_f_diag.EliminateCol(dof);
351 }
352
353 const IterSolveParameters& param = param_.coarse_solve_param;
354 auto coarse_solver = new BDPMinresSolver(M_f, B_f, param);
355 if (ops_.size() > 1)
356 {
357 coarse_solver->SetEssZeroDofs(data.coarsest_ess_hdivdofs);
358 }
359 smoothers_[l].reset(coarse_solver);
360 continue;
361 }
362
363 auto P_hdiv_l = data.P_hdiv[l-1]->As<HypreParMatrix>();
364 auto P_l2_l = data.P_l2[l-1]->As<HypreParMatrix>();
365 SparseMatrix& agg_hdivdof_l = *data.agg_hdivdof[l-1].As<SparseMatrix>();
366 SparseMatrix& agg_l2dof_l = *data.agg_l2dof[l-1].As<SparseMatrix>();
367 ProductOperator& Q_l2_l = *data.Q_l2[l-1].As<ProductOperator>();
368 auto* C_l = data.C[l].As<HypreParMatrix>();
369
370 auto S0 = new SaddleSchwarzSmoother(M_f, B_f, agg_hdivdof_l,
371 agg_l2dof_l, *P_l2_l, Q_l2_l);
372 if (param_.coupled_solve)
373 {
374 auto S1 = new BlockDiagonalPreconditioner(ops_offsets_[l]);
375 S1->SetDiagonalBlock(0, new AuxSpaceSmoother(M_f, C_l));
376 S1->owns_blocks = 1;
377 smoothers_[l] =
378 std::make_unique<ProductSolver>(ops_[l].get(), S0, S1, false, true, true);
379 }
380 else
381 {
382 smoothers_[l].reset(S0);
383 }
384
385 HypreParMatrix* M_c = TwoStepsRAP(P_hdiv_l, &M_f, P_hdiv_l);
386 HypreParMatrix* B_c = TwoStepsRAP(P_l2_l, &B_f, P_hdiv_l);
387
388 ops_offsets_[l-1].SetSize(3, 0);
389 ops_offsets_[l-1][1] = M_c->NumRows();
390 ops_offsets_[l-1][2] = M_c->NumRows() + B_c->NumRows();
391
392 blk_Ps_[l-1] =
393 std::make_unique<BlockOperator>(ops_offsets_[l], ops_offsets_[l-1]);
394 blk_Ps_[l-1]->SetBlock(0, 0, P_hdiv_l);
395 blk_Ps_[l-1]->SetBlock(1, 1, P_l2_l);
396
397 ops_[l-1] =
398 std::make_unique<BlockOperator>(ops_offsets_[l-1]);
399 ops_[l-1]->SetBlock(0, 0, M_c);
400 ops_[l-1]->SetBlock(1, 0, B_c);
401 ops_[l-1]->SetBlock(0, 1, B_c->Transpose());
402 ops_[l-1]->owns_blocks = 1;
403 }
404
405 if (data_.P_l2.size() == 0) { return; }
406
407 Array<bool> own_ops(ops_.size());
408 Array<bool> own_smoothers(smoothers_.size());
409 Array<bool> own_blk_Ps(blk_Ps_.size());
410 own_ops = false, own_smoothers = false, own_blk_Ps = false;
411
412 Array<Solver*> smoothers(smoothers_.size());
413
414 if (param_.coupled_solve)
415 {
416 solver_.Reset(new GMRESSolver(B.GetComm()));
417 solver_.As<GMRESSolver>()->SetOperator(*(ops_.back()));
418 Array<BlockOperator*> ops(ops_.size()), blk_Ps(blk_Ps_.size());
419 for (size_t i = 0; i < ops_.size(); ++i) { ops[i] = ops_[i].get(); }
420 for (size_t i = 0; i < blk_Ps_.size(); ++i) { blk_Ps[i] = blk_Ps_[i].get(); }
421 for (size_t i = 0; i < smoothers_.size(); ++i) { smoothers[i] = smoothers_[i].get(); }
422 prec_.Reset(new Multigrid(ops, smoothers, blk_Ps,
423 own_ops, own_smoothers, own_blk_Ps));
424 }
425 else
426 {
427 Array<HypreParMatrix*> ops(data_.P_hcurl.size()+1);
428 Array<HypreParMatrix*> Ps(data_.P_hcurl.size());
429 auto C_finest = data.C.back().As<HypreParMatrix>();
430 ops.Last() = TwoStepsRAP(C_finest, &M, C_finest);
431 ops.Last()->EliminateZeroRows();
432 ops.Last()->DropSmallEntries(1e-14);
433 solver_.Reset(new CGSolver(B.GetComm()));
434 solver_.As<CGSolver>()->SetOperator(*ops.Last());
435 smoothers.Last() = new HypreSmoother(*ops.Last());
436 static_cast<HypreSmoother*>(smoothers.Last())->SetOperatorSymmetry(true);
437 for (int l = Ps.Size()-1; l >= 0; --l)
438 {
439 Ps[l] = data_.P_hcurl[l]->As<HypreParMatrix>();
440 ops[l] = TwoStepsRAP(Ps[l], ops[l+1], Ps[l]);
441 ops[l]->DropSmallEntries(1e-14);
442 smoothers[l] = new HypreSmoother(*ops[l]);
443 static_cast<HypreSmoother*>(smoothers[l])->SetOperatorSymmetry(true);
444 }
445 own_ops = true, own_smoothers = true;
446 prec_.Reset(new Multigrid(ops, smoothers, Ps,
447 own_ops, own_smoothers, own_blk_Ps));
448 }
449
450 solver_.As<IterativeSolver>()->SetPreconditioner(*prec_.As<Solver>());
451 SetOptions(*solver_.As<IterativeSolver>(), param_);
452}
453
454void DivFreeSolver::SolveParticular(const Vector& rhs, Vector& sol) const
455{
456 std::vector<Vector> rhss(smoothers_.size()), sols(smoothers_.size());
457 rhss.back().SetDataAndSize(const_cast<real_t*>(rhs.HostRead()), rhs.Size());
458 sols.back().SetDataAndSize(sol.HostWrite(), sol.Size());
459
460 for (int l = blk_Ps_.size()-1; l >= 0; --l)
461 {
462 rhss[l].SetSize(blk_Ps_[l]->NumCols());
463 sols[l].SetSize(blk_Ps_[l]->NumCols());
464
465 sols[l] = 0.0;
466 rhss[l] = 0.0;
467
468 blk_Ps_[l]->MultTranspose(rhss[l+1], rhss[l]);
469 }
470
471 for (size_t l = 0; l < smoothers_.size(); ++l)
472 {
473 smoothers_[l]->Mult(rhss[l], sols[l]);
474 }
475
476 for (size_t l = 0; l < blk_Ps_.size(); ++l)
477 {
478 Vector P_sol(blk_Ps_[l]->NumRows());
479 blk_Ps_[l]->Mult(sols[l], P_sol);
480 sols[l+1] += P_sol;
481 }
482}
483
484void DivFreeSolver::SolveDivFree(const Vector &rhs, Vector& sol) const
485{
486 Vector rhs_divfree(data_.C.back()->NumCols());
487 data_.C.back()->MultTranspose(rhs, rhs_divfree);
488
489 Vector potential_divfree(rhs_divfree.Size());
490 potential_divfree = 0.0;
491 solver_->Mult(rhs_divfree, potential_divfree);
492
493 data_.C.back()->Mult(potential_divfree, sol);
494}
495
496void DivFreeSolver::SolvePotential(const Vector& rhs, Vector& sol) const
497{
498 Vector rhs_p(BT_->NumCols());
499 BT_->MultTranspose(rhs, rhs_p);
500 BBT_solver_.Mult(rhs_p, sol);
501}
502
503void DivFreeSolver::Mult(const Vector & x, Vector & y) const
504{
505 MFEM_VERIFY(x.Size() == offsets_[2], "MLDivFreeSolver: x size is invalid");
506 MFEM_VERIFY(y.Size() == offsets_[2], "MLDivFreeSolver: y size is invalid");
507
508 if (ops_.size() == 1) { smoothers_[0]->Mult(x, y); return; }
509
510 BlockVector blk_y(y, offsets_);
511
512 BlockVector resid(offsets_);
513 ops_.back()->Mult(y, resid);
514 add(1.0, x, -1.0, resid, resid);
515
516 BlockVector correction(offsets_);
517 correction = 0.0;
518
519 if (param_.coupled_solve)
520 {
521 solver_->Mult(resid, correction);
522 y += correction;
523 }
524 else
525 {
526 StopWatch ch;
527 ch.Start();
528
529 SolveParticular(resid, correction);
530 blk_y += correction;
531
532 if (param_.verbose)
533 {
534 cout << "Particular solution found in " << ch.RealTime() << "s.\n";
535 }
536
537 ch.Clear();
538 ch.Start();
539
540 ops_.back()->Mult(y, resid);
541 add(1.0, x, -1.0, resid, resid);
542
543 SolveDivFree(resid.GetBlock(0), correction.GetBlock(0));
544 blk_y.GetBlock(0) += correction.GetBlock(0);
545
546 if (param_.verbose)
547 {
548 cout << "Divergence free solution found in " << ch.RealTime() << "s.\n";
549 }
550
551 ch.Clear();
552 ch.Start();
553
554 auto& M = dynamic_cast<const HypreParMatrix&>(ops_.back()->GetBlock(0, 0));
555 M.Mult(-1.0, correction.GetBlock(0), 1.0, resid.GetBlock(0));
556 SolvePotential(resid.GetBlock(0), correction.GetBlock(1));
557 blk_y.GetBlock(1) += correction.GetBlock(1);
558
559 if (param_.verbose)
560 {
561 cout << "Scalar potential found in " << ch.RealTime() << "s.\n";
562 }
563 }
564}
565
567{
568 if (ops_.size() == 1)
569 {
570 return static_cast<BDPMinresSolver*>
571 (smoothers_.at(0).get())->GetNumIterations();
572 }
573 return solver_.As<IterativeSolver>()->GetNumIterations();
574}
575
576} // namespace mfem::blocksolvers
void SetSize(int nsize)
Change the logical size of the array, keep existing entries.
Definition array.hpp:840
int Size() const
Return the logical size of the array.
Definition array.hpp:166
void MakeRef(T *data_, int size_, bool own_data=false)
Make this Array a reference to a pointer.
Definition array.hpp:1053
T * begin()
STL-like begin. Returns pointer to the first element of the array.
Definition array.hpp:366
T & Last()
Return the last element in the array.
Definition array.hpp:945
A class to handle Block diagonal preconditioners 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:627
void SetOperator(const Operator &op) override
Set/update the solver for the given operator.
Definition solvers.hpp:640
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:116
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:1280
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:282
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:779
int GetNE() const
Returns number of elements in the mesh.
Definition fespace.hpp:869
int GetVSize() const
Return the number of vector dofs, i.e. GetNDofs() x GetVDim().
Definition fespace.hpp:826
GMRES method.
Definition solvers.hpp:661
The BoomerAMG solver in hypre.
Definition hypre.hpp:1737
Wrapper for hypre's ParCSR matrix class.
Definition hypre.hpp:419
void DropSmallEntries(real_t tol)
Wrapper for hypre_ParCSRMatrixDropSmallEntries in different versions of hypre. Drop off-diagonal entr...
Definition hypre.cpp:2352
void GetDiag(Vector &diag) const
Get the local diagonal of the matrix.
Definition hypre.cpp:1607
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:2042
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:1863
MPI_Comm GetComm() const
MPI communicator.
Definition hypre.hpp:609
HypreParMatrix * Transpose() const
Returns the transpose of *this.
Definition hypre.cpp:1732
HypreParMatrix * EliminateCols(const Array< int > &cols)
Definition hypre.cpp:2424
Parallel smoothers in hypre.
Definition hypre.hpp:1066
Abstract base class for iterative solver.
Definition solvers.hpp:91
virtual void SetPreconditioner(Solver &pr)
This should be called before SetOperator.
Definition solvers.cpp:178
const Element * GetElement(int i) const
Return pointer to the i'th element object.
Definition mesh.hpp:1434
int GetNE() const
Returns number of elements.
Definition mesh.hpp:1377
int Dimension() const
Dimension of the reference space used within the elements.
Definition mesh.hpp:1306
void Finalize(int skip_zeros=1) override
Finalizes the matrix initialization if the AssemblyLevel is AssemblyLevel::LEGACY.
Multigrid solver class.
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:298
@ Hypre_ParCSR
ID for class HypreParMatrix.
Definition operator.hpp:299
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:100
Class for parallel bilinear form.
HypreParMatrix * ParallelAssemble() const
Returns the matrix "assembled" on the true dofs.
Abstract parallel finite element space.
Definition pfespace.hpp:31
Class for parallel meshes.
Definition pmesh.hpp:34
General product operator: x -> (A*B)(x) = A(B(x)).
Definition operator.hpp:906
Base class for solvers.
Definition operator.hpp:792
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:128
int * GetI()
Definition table.hpp:127
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:524
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:785
int Size() const
Returns the size of the vector.
Definition vector.hpp:234
void SetSize(int s)
Resize the vector to size s.
Definition vector.hpp:584
virtual real_t * HostWrite()
Shortcut for mfem::Write(vec.GetMemory(), vec.Size(), false).
Definition vector.hpp:532
real_t * GetData() const
Return a pointer to the beginning of the Vector data.
Definition vector.hpp:243
void GetSubVector(const Array< int > &dofs, Vector &elemvect) const
Extract entries listed in dofs to the output Vector elemvect.
Definition vector.cpp:676
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 ProductOperator &Q_l2)
Block diagonal solver for symmetric A, each block is inverted by direct solver.
HYPRE_Int HYPRE_BigInt
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:505
void add(const Vector &v1, const Vector &v2, Vector &v)
Definition vector.cpp:414
void Transpose(const Table &A, Table &At, int ncols_A_)
Transpose a Table.
Definition table.cpp:443
HypreParMatrix * ParMult(const HypreParMatrix *A, const HypreParMatrix *B, bool own_matrix)
Definition hypre.cpp:3021
float real_t
Definition config.hpp:46
Data for the divergence free solver.
std::vector< OperatorPtr > agg_l2dof
std::vector< UniqueOperatorPtr > P_l2
std::vector< OperatorPtr > Q_l2
std::vector< UniqueHypreParMatrix > Ae
std::vector< UniqueOperatorPtr > P_hdiv
std::vector< UniqueOperatorPtr > P_hcurl
std::vector< OperatorPtr > agg_hdivdof
std::vector< OperatorPtr > C
Parameters for the divergence free solver.