MFEM v4.7.0
Finite element discretization library
Loading...
Searching...
No Matches
div_free_solver.cpp
Go to the documentation of this file.
1// Copyright (c) 2010-2024, 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:697
int Size() const
Return the logical size of the array.
Definition array.hpp:144
void MakeRef(T *data_, int size_, bool own_data=false)
Make this Array a reference to a pointer.
Definition array.hpp:882
T * begin()
STL-like begin. Returns pointer to the first element of the array.
Definition array.hpp:302
T & Last()
Return the last element in the array.
Definition array.hpp:802
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:513
virtual void SetOperator(const Operator &op)
Also calls SetOperator for the preconditioner if there is one.
Definition solvers.hpp:526
void Mult(const real_t *x, real_t *y) const
Matrix vector multiplication with the inverse of dense matrix.
virtual void SetOperator(const Operator &op)
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:105
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:1136
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:265
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:667
int GetNE() const
Returns number of elements in the mesh.
Definition fespace.hpp:740
int GetVSize() const
Return the number of vector dofs, i.e. GetNDofs() x GetVDim().
Definition fespace.hpp:713
GMRES method.
Definition solvers.hpp:547
Arbitrary order H1-conforming (continuous) finite elements.
Definition fe_coll.hpp:260
The BoomerAMG solver in hypre.
Definition hypre.hpp:1691
Wrapper for hypre's ParCSR matrix class.
Definition hypre.hpp:388
void DropSmallEntries(real_t tol)
Wrapper for hypre_ParCSRMatrixDropSmallEntries in different versions of hypre. Drop off-diagonal entr...
Definition hypre.cpp:2309
void GetDiag(Vector &diag) const
Get the local diagonal of the matrix.
Definition hypre.cpp:1557
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:1994
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:1815
MPI_Comm GetComm() const
MPI communicator.
Definition hypre.hpp:578
HypreParMatrix * Transpose() const
Returns the transpose of *this.
Definition hypre.cpp:1684
Parallel smoothers in hypre.
Definition hypre.hpp:1020
Abstract base class for iterative solver.
Definition solvers.hpp:67
virtual void SetPreconditioner(Solver &pr)
This should be called before SetOperator.
Definition solvers.cpp:173
const Element * GetElement(int i) const
Return pointer to the i'th element object.
Definition mesh.hpp:1283
int GetNE() const
Returns number of elements.
Definition mesh.hpp:1226
int Dimension() const
Dimension of the reference space used within the elements.
Definition mesh.hpp:1160
virtual void Finalize(int skip_zeros=1)
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:465
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:797
Base class for solvers.
Definition operator.hpp:683
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
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.
virtual int NumNonZeroElems() const
Returns the number of the nonzero elements in the matrix.
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:114
int * GetI()
Definition table.hpp:113
Vector data type.
Definition vector.hpp:80
virtual const real_t * HostRead() const
Shortcut for mfem::Read(vec.GetMemory(), vec.Size(), false).
Definition vector.hpp:478
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:670
int Size() const
Returns the size of the vector.
Definition vector.hpp:218
void SetSize(int s)
Resize the vector to size s.
Definition vector.hpp:538
virtual real_t * HostWrite()
Shortcut for mfem::Write(vec.GetMemory(), vec.Size(), false).
Definition vector.hpp:486
real_t * GetData() const
Return a pointer to the beginning of the Vector data.
Definition vector.hpp:227
void GetSubVector(const Array< int > &dofs, Vector &elemvect) const
Extract entries listed in dofs to the output Vector elemvect.
Definition vector.cpp:578
BBTSolver(const HypreParMatrix &B, IterSolveParameters param)
virtual void Mult(const Vector &x, Vector &y) const
Operator application: y=A(x).
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.
virtual void SetOperator(const Operator &op)
Set/update the solver for the given operator.
DivFreeSolver(const HypreParMatrix &M, const HypreParMatrix &B, const DFSData &data)
virtual void Mult(const Vector &x, Vector &y) const
Operator application: y=A(x).
Solver for local problems in SaddleSchwarzSmoother.
virtual void Mult(const Vector &x, Vector &y) const
Operator application: y=A(x).
LocalSolver(const DenseMatrix &M, const DenseMatrix &B)
virtual void Mult(const Vector &x, Vector &y) const
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:476
void add(const Vector &v1, const Vector &v2, Vector &v)
Definition vector.cpp:316
void Transpose(const Table &A, Table &At, int ncols_A_)
Transpose a Table.
Definition table.cpp:414
HypreParMatrix * ParMult(const HypreParMatrix *A, const HypreParMatrix *B, bool own_matrix)
Definition hypre.cpp:2949
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.