16 using namespace blocksolvers;
41 int* I =
new int[fes.
GetNE()+1];
46 double* D =
new double[J.Size()];
47 fill_n(D, J.Size(), 1.0);
51 DFSSpaces::DFSSpaces(
int order,
int num_refine,
ParMesh *mesh,
53 : hdiv_fec_(order, mesh->Dimension()), l2_fec_(order, mesh->Dimension()),
54 l2_0_fec_(0, mesh->Dimension()), ess_bdr_attr_(ess_attr), level_(0)
58 mfem_error(
"DFSDataCollector: High order spaces on tetrahedra are not supported");
79 el_l2dof_.reserve(num_refine+1);
80 el_l2dof_.push_back(
ElemToDof(*coarse_l2_fes_));
86 data_.
Q_l2.resize(num_refine);
88 data_.
C.resize(num_refine+1);
110 int * I =
new int [tdof_agg.NumRows()+1]();
111 int * J =
new int[tdof_agg.NumNonZeroElems()];
117 for (
int i = 0; i < tdof_agg.NumRows(); ++i)
119 bool agg_bdr = is_bdr[i] || is_shared.RowSize(i) || tdof_agg.RowSize(i)>1;
120 if (agg_bdr) { I[i+1] = I[i];
continue; }
122 J[counter++] = tdof_agg.GetRowColumns(i)[0];
125 double * D =
new double[I[tdof_agg.NumRows()]];
126 std::fill_n(D, I[tdof_agg.NumRows()], 1.0);
128 SparseMatrix intdof_agg(I, J, D, tdof_agg.NumRows(), tdof_agg.NumCols());
132 void DFSSpaces::MakeDofRelationTables(
int level)
136 auto& elem_agg = (
const SparseMatrix&)*l2_0_fes_->GetUpdateOperator();
140 el_l2dof_.push_back(
ElemToDof(*l2_fes_));
141 data_.
agg_l2dof[level].Reset(
Mult(agg_el, el_l2dof_[level+1]));
144 hdiv_fes_->GetEssentialTrueDofs(all_bdr_attr_, bdr_tdofs);
146 *hdiv_fes_->Dof_TrueDof_Matrix(), agg_starts);
152 auto GetP = [
this](
OperatorPtr& P, unique_ptr<ParFiniteElementSpace>& cfes,
156 fes.GetTrueTransferOperator(*cfes, P);
161 (level_ < (int)data_.
P_l2.size()-1) ? cfes->Update() : cfes.reset();
164 GetP(data_.
P_hdiv[level_], coarse_hdiv_fes_, *hdiv_fes_,
true);
165 GetP(data_.
P_l2[level_], coarse_l2_fes_, *l2_fes_,
false);
166 MakeDofRelationTables(level_);
168 GetP(data_.
P_hcurl[level_], coarse_hcurl_fes_, *hcurl_fes_,
true);
170 Vector trash1(hcurl_fes_->GetVSize()), trash2(hdiv_fes_->GetVSize());
174 curl.EliminateTrialDofs(ess_bdr_attr_, trash1, trash2);
176 data_.
C[level_+1].Reset(curl.ParallelAssemble());
180 if (level_ == (
int)data_.
P_l2.size()) { DataFinalize(); }
183 void DFSSpaces::DataFinalize()
192 for (
int l = (
int)data_.
P_l2.size()-1; l >= 0; --l)
197 auto cW =
Mult(*PTW, P_l2);
207 :
Solver(B.NumRows()), BBT_solver_(B.GetComm())
222 :
Solver(M.NumRows()+B.NumRows()), local_system_(height), offset_(M.NumRows())
224 local_system_.
CopyMN(M, 0, 0);
225 local_system_.
CopyMN(B, offset_, 0);
226 local_system_.
CopyMNt(B, 0, offset_);
228 local_system_.
SetRow(offset_, 0.0);
229 local_system_.
SetCol(offset_, 0.0);
230 local_system_(offset_, offset_) = -1.0;
236 const double x0 = x[offset_];
237 const_cast<Vector&
>(x)[offset_] = 0.0;
240 local_solver_.
Mult(x, y);
242 const_cast<Vector&
>(x)[offset_] = x0;
251 :
Solver(M.NumRows() + B.NumRows()), agg_hdivdof_(agg_hdivdof),
252 agg_l2dof_(agg_l2dof), solvers_loc_(agg_l2dof.NumRows())
267 for (
int agg = 0; agg < (int)solvers_loc_.size(); agg++)
273 M_diag.
GetSubMatrix(hdivdofs_loc_, hdivdofs_loc_, M_loc);
275 solvers_loc_[agg].Reset(
new LocalSolver(M_loc, B_loc));
286 static_cast<Vector&
>(Pi_x) = x;
290 Vector coarse_l2_projection(Pi_x.BlockSize(1));
291 coarse_l2_projector_->
MultTranspose(Pi_x.GetBlock(1), coarse_l2_projection);
293 Pi_x.GetBlock(1) -= coarse_l2_projection;
295 for (
int agg = 0; agg < (int)solvers_loc_.size(); agg++)
300 offsets_loc_[1] = hdivdofs_loc_.
Size();
301 offsets_loc_[2] = offsets_loc_[1]+l2dofs_loc_.
Size();
303 BlockVector rhs_loc(offsets_loc_), sol_loc(offsets_loc_);
304 Pi_x.GetBlock(0).GetSubVector(hdivdofs_loc_, rhs_loc.GetBlock(0));
305 Pi_x.GetBlock(1).GetSubVector(l2dofs_loc_, rhs_loc.GetBlock(1));
307 solvers_loc_[agg]->Mult(rhs_loc, sol_loc);
309 blk_y.GetBlock(0).AddElementVector(hdivdofs_loc_, sol_loc.
GetBlock(0));
310 blk_y.GetBlock(1).AddElementVector(l2dofs_loc_, sol_loc.
GetBlock(1));
313 coarse_l2_projector_->
Mult(blk_y.GetBlock(1), coarse_l2_projection);
314 blk_y.GetBlock(1) -= coarse_l2_projection;
319 :
DarcySolver(M.NumRows(), B.NumRows()), op_(offsets_), prec_(offsets_),
345 for (
int dof : ess_zero_dofs_) { y[dof] = 0.0; }
350 :
DarcySolver(M.NumRows(), B.NumRows()), data_(data), param_(data.param),
351 BT_(B.
Transpose()), BBT_solver_(B, param_.BBT_solve_param),
352 ops_offsets_(data.P_l2.size()+1), ops_(ops_offsets_.size()),
353 blk_Ps_(ops_.Size()-1), smoothers_(ops_.Size())
357 ops_.Last()->SetBlock(0, 0, const_cast<HypreParMatrix*>(&M));
358 ops_.Last()->SetBlock(1, 0, const_cast<HypreParMatrix*>(&B));
359 ops_.Last()->SetBlock(0, 1, BT_.
Ptr());
361 for (
int l = data.
P_l2.size(); l >= 0; --l)
363 auto& M_f =
static_cast<HypreParMatrix&
>(ops_[l]->GetBlock(0, 0));
364 auto& B_f =
static_cast<HypreParMatrix&
>(ops_[l]->GetBlock(1, 0));
370 B_f.GetDiag(B_f_diag);
383 smoothers_[l] = coarse_solver;
395 agg_l2dof_l, P_l2_l, Q_l2_l);
400 S1->owns_blocks =
true;
401 smoothers_[l] =
new ProductSolver(ops_[l], S0, S1,
false,
true,
true);
411 ops_offsets_[l-1].SetSize(3, 0);
412 ops_offsets_[l-1][1] = M_c->
NumRows();
415 blk_Ps_[l-1] =
new BlockOperator(ops_offsets_[l], ops_offsets_[l-1]);
416 blk_Ps_[l-1]->SetBlock(0, 0, &P_hdiv_l);
417 blk_Ps_[l-1]->SetBlock(1, 1, &P_l2_l);
420 ops_[l-1]->SetBlock(0, 0, M_c);
421 ops_[l-1]->SetBlock(1, 0, B_c);
422 ops_[l-1]->SetBlock(0, 1, B_c->
Transpose());
423 ops_[l-1]->owns_blocks =
true;
430 own_smoothers =
true;
433 if (data_.
P_l2.size() == 0) {
return; }
440 own_ops, own_smoothers, own_Ps));
451 ops.Last()->EliminateZeroRows();
452 ops.Last()->DropSmallEntries(1e-14);
457 static_cast<HypreSmoother*
>(smoothers.Last())->SetOperatorSymmetry(
true);
459 for (
int l = Ps.Size()-1; l >= 0; --l)
465 static_cast<HypreSmoother*
>(smoothers[l])->SetOperatorSymmetry(
true);
468 prec_.
Reset(
new Multigrid(ops, smoothers, Ps, own_ops, own_smoothers, own_Ps));
478 for (
int i = 0; i < ops_.Size(); ++i)
481 delete smoothers_[i];
482 if (i == ops_.Size() - 1) {
break; }
487 void DivFreeSolver::SolveParticular(
const Vector& rhs,
Vector& sol)
const 489 std::vector<Vector> rhss(smoothers_.Size());
490 std::vector<Vector> sols(smoothers_.Size());
492 rhss.back().SetDataAndSize(const_cast<double*>(rhs.
HostRead()), rhs.
Size());
495 for (
int l = blk_Ps_.Size()-1; l >= 0; --l)
497 rhss[l].SetSize(blk_Ps_[l]->
NumCols());
498 sols[l].SetSize(blk_Ps_[l]->
NumCols());
503 blk_Ps_[l]->MultTranspose(rhss[l+1], rhss[l]);
506 for (
int l = 0; l < smoothers_.Size(); ++l)
508 smoothers_[l]->Mult(rhss[l], sols[l]);
511 for (
int l = 0; l < blk_Ps_.Size(); ++l)
514 blk_Ps_[l]->Mult(sols[l], P_sol);
519 void DivFreeSolver::SolveDivFree(
const Vector &rhs,
Vector& sol)
const 521 Vector rhs_divfree(data_.
C.back()->NumCols());
522 data_.
C.back()->MultTranspose(rhs, rhs_divfree);
524 Vector potential_divfree(rhs_divfree.Size());
525 potential_divfree = 0.0;
526 solver_->
Mult(rhs_divfree, potential_divfree);
528 data_.
C.back()->Mult(potential_divfree, sol);
531 void DivFreeSolver::SolvePotential(
const Vector& rhs,
Vector& sol)
const 535 BBT_solver_.
Mult(rhs_p, sol);
540 MFEM_VERIFY(x.
Size() ==
offsets_[2],
"MLDivFreeSolver: x size is invalid");
541 MFEM_VERIFY(y.
Size() ==
offsets_[2],
"MLDivFreeSolver: y size is invalid");
543 if (ops_.Size() == 1) { smoothers_[0]->Mult(x, y);
return; }
548 ops_.Last()->Mult(y, resid);
549 add(1.0, x, -1.0, resid, resid);
556 solver_->
Mult(resid, correction);
564 SolveParticular(resid, correction);
569 cout <<
"Particular solution found in " << ch.
RealTime() <<
"s.\n";
575 ops_.Last()->Mult(y, resid);
576 add(1.0, x, -1.0, resid, resid);
583 cout <<
"Divergence free solution found in " << ch.
RealTime() <<
"s.\n";
589 auto M =
dynamic_cast<HypreParMatrix&
>(ops_.Last()->GetBlock(0, 0));
596 cout <<
"Scalar potential found in " << ch.
RealTime() <<
"s.\n";
603 if (ops_.Size() == 1)
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 ...
Conjugate gradient method.
virtual void Mult(const Vector &x, Vector &y) const
Operator application: y=A(x).
void EliminateCol(int col, DiagonalPolicy dpolicy=DIAG_ZERO)
Eliminates the column col from the matrix.
void SetCol(int c, const double *col)
void GetDiag(Vector &d) const
Returns the Diagonal of A.
A class to handle Vectors in a block fashion.
void SetRow(int r, const double *row)
DivFreeSolver(const HypreParMatrix &M, const HypreParMatrix &B, const DFSData &data)
void Mult(const double *x, double *y) const
Matrix vector multiplication with the inverse of dense matrix.
void SetSize(int s)
Resize the vector to size s.
virtual const double * HostRead() const
Shortcut for mfem::Read(vec.GetMemory(), vec.Size(), false).
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.
void Mult(const Table &A, const Table &B, Table &C)
C = A * B (as boolean matrices)
std::vector< OperatorPtr > Q_l2
Pointer to an Operator of a specified type.
virtual void Mult(const Vector &b, Vector &x) const
Operator application: y=A(x).
Abstract solver class for Darcy's flow.
virtual void Mult(const Vector &x, Vector &y) const
Operator application: y=A(x).
Array< int > coarsest_ess_hdivdofs
int Size() const
Returns the size of the vector.
Data type dense matrix using column-major storage.
virtual double * HostWrite()
Shortcut for mfem::Write(vec.GetMemory(), vec.Size(), false).
int NumRows() const
Get the number of rows (size of output) of the Operator. Synonym with Height().
virtual void Mult(const Vector &x, Vector &y) const =0
Operator application: y=A(x).
const Element * GetElement(int i) const
Abstract parallel finite element space.
SaddleSchwarzSmoother(const HypreParMatrix &M, const HypreParMatrix &B, const SparseMatrix &agg_hdivdof, const SparseMatrix &agg_l2dof, const HypreParMatrix &P_l2, const HypreParMatrix &Q_l2)
std::vector< OperatorPtr > P_hcurl
void GetSubMatrix(const Array< int > &rows, const Array< int > &cols, DenseMatrix &subm) const
HypreParMatrix * ParMult(const HypreParMatrix *A, const HypreParMatrix *B, bool own_matrix)
virtual void Mult(const Vector &x, Vector &y) const
Operator application: y=A(x).
void add(const Vector &v1, const Vector &v2, Vector &v)
void AddDomainInterpolator(DiscreteInterpolator *di)
Adds a domain interpolator. Assumes ownership of di.
IterSolveParameters coarse_solve_param
LocalSolver(const DenseMatrix &M, const DenseMatrix &B)
Operator & GetDiagonalBlock(int iblock)
Return a reference to block i,i.
ID for class SparseMatrix.
The BoomerAMG solver in hypre.
Data for the divergence free solver.
General product operator: x -> (A*B)(x) = A(B(x)).
virtual void SetPreconditioner(Solver &pr)
This should be called before SetOperator.
virtual void SetPrintLevel(int print_lvl)
Legacy method to set the level of verbosity of the solver output.
A class to handle Block diagonal preconditioners in a matrix-free implementation. ...
Wrapper for the block-diagonal-preconditioned MINRES defined in ex5p.cpp.
Jacobi preconditioner in hypre.
SparseMatrix ElemToDof(const ParFiniteElementSpace &fes)
void mfem_error(const char *msg)
Function called when an error is encountered. Used by the macros MFEM_ABORT, MFEM_ASSERT, MFEM_VERIFY.
void SetMaxIter(int max_it)
std::vector< OperatorPtr > P_hdiv
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...
virtual void SetOperator(const Operator &op)
Set/update the solver for the given operator.
virtual int GetNumIterations() const
Parallel smoothers in hypre.
virtual void SetOperator(const Operator &op)
Set/update the solver for the given operator.
virtual void SetOperator(const Operator &op)
Also calls SetOperator for the preconditioner if there is one.
void GetDiag(Vector &diag) const
Get the local diagonal of the matrix.
int GetNE() const
Returns number of elements in the mesh.
void Start()
Start the stopwatch. The elapsed time is not cleared.
double * GetData() const
Return a pointer to the beginning of the Vector data.
BDPMinresSolver(HypreParMatrix &M, HypreParMatrix &B, IterSolveParameters param)
MPI_Comm GetComm() const
MPI communicator.
void SetAbsTol(double atol)
void SetRelTol(double rtol)
Abstract base class for iterative solver.
OperatorHandle OperatorPtr
Add an alternative name for OperatorHandle – OperatorPtr.
SparseMatrix * AggToInteriorDof(const Array< int > &bdr_truedofs, const SparseMatrix &agg_elem, const SparseMatrix &elem_dof, const HypreParMatrix &dof_truedof, Array< HYPRE_BigInt > &agg_starts)
void SetSize(int nsize)
Change the logical size of the array, keep existing entries.
void EliminateRowCol(int rc, const double sol, Vector &rhs, DiagonalPolicy dpolicy=DIAG_ONE)
Eliminate row rc and column rc and modify the rhs using sol.
void Transpose(const Table &A, Table &At, int ncols_A_)
Transpose a Table.
virtual void Mult(const Vector &x, Vector &y) const
Operator application: y=A(x).
std::vector< OperatorPtr > agg_hdivdof
std::vector< OperatorPtr > agg_l2dof
Parameters for the divergence free solver.
int NumCols() const
Get the number of columns (size of input) of the Operator. Synonym with Width().
HypreParMatrix * Transpose() const
Returns the transpose of *this.
std::vector< OperatorPtr > C
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 SetOptions(IterativeSolver &solver, const IterSolveParameters ¶m)
HypreParMatrix * TwoStepsRAP(const HypreParMatrix &Rt, const HypreParMatrix &A, const HypreParMatrix &P)
OpType * As() const
Return the Operator pointer statically cast to a specified OpType. Similar to the method Get()...
Block diagonal solver for symmetric A, each block is inverted by direct solver.
virtual void Mult(const Vector &x, Vector &y) const
Operator application: y=A(x).
int GetVSize() const
Return the number of vector dofs, i.e. GetNDofs() x GetVDim().
void GetRowColumnsRef(const SparseMatrix &A, int row, Array< int > &cols)
Operator * Ptr() const
Access the underlying Operator pointer.
int Size() const
Return the logical size of the array.
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...
void MakeRef(T *, int)
Make this Array a reference to a pointer.
virtual void SetOperator(const Operator &op)
Also calls SetOperator for the preconditioner if there is one.
Arbitrary order H(curl)-conforming Nedelec finite elements.
ID for class HypreParMatrix.
virtual void SetPreconditioner(Solver &pr)
This should be called before SetOperator.
Parameters for iterative solver.
void DropSmallEntries(double tol)
Wrapper for hypre_ParCSRMatrixDropSmallEntries in different versions of hypre. Drop off-diagonal entr...
Arbitrary order H1-conforming (continuous) finite elements.
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 SetSize(int s)
Change the size of the DenseMatrix to s x s.
Solver for local problems in SaddleSchwarzSmoother.
Wrapper for hypre's ParCSR matrix class.
A class to handle Block systems in a matrix-free implementation.
BBTSolver(const HypreParMatrix &B, IterSolveParameters param)
Class for parallel meshes.
const Table & GetElementToDofTable() const
Return a reference to the internal Table that stores the lists of scalar dofs, for each mesh element...
virtual Type GetType() const =0
Returns element's type.
std::vector< OperatorPtr > P_l2
static void AdjustVDofs(Array< int > &vdofs)
HYPRE_Int Mult(HypreParVector &x, HypreParVector &y, double alpha=1.0, double beta=0.0) const
Computes y = alpha * A * x + beta * y.
void Clear()
Clear the elapsed time on the stopwatch and restart it if it's running.
void SetBlock(int iRow, int iCol, Operator *op, double c=1.0)
Add a block op in the block-entry (iblock, jblock).
void Reset(OpType *A, bool own_A=true)
Reset the OperatorHandle to the given OpType pointer, A.
void SetDiagonalBlock(int iblock, Operator *op)
Add a square block op in the block-entry (iblock, iblock).
Vector & GetBlock(int i)
Get the i-th vector in the block.