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)
int Dimension() const
Dimension of the reference space used within the elements.
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
Return pointer to the i'th element object.
double RealTime()
Return the number of real seconds elapsed since the stopwatch was started.
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)
Remove the orientation information encoded into an array of dofs Some basis function types have a rel...
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.