25 for (
int k = 0; k<nblocks; k++)
27 if (!tr_fes[k]) {
continue; }
28 rdof_edof0.
SetSize(tr_fes[k]->GetVSize());
29 for (
int i = 0; i < mesh->
GetNE(); i++)
31 fes[k]->GetElementVDofs(i, vdofs);
32 tr_fes[k]->GetElementVDofs(i, rvdofs);
33 const int vdim = fes[k]->GetVDim();
34 const int nsd = vdofs.
Size()/vdim;
35 const int nsrd = rvdofs.
Size()/vdim;
36 for (
int vd = 0; vd < vdim; vd++)
38 for (
int j = 0; j < nsrd; j++)
40 int rvdof = rvdofs[j+nsrd*vd];
41 int vdof = vdofs[j+nsd*vd];
47 MFEM_ASSERT(vdof >= 0,
"incompatible volume and trace FE spaces");
48 rdof_edof0[rvdof] = vdof + dof_offsets[k];
52 rdof_edof.
Append(rdof_edof0);
61 if (dynamic_cast<ParFiniteElementSpace *>(fes_[0]))
72 mesh = fes[0]->GetMesh();
75 const FiniteElementCollection * fec;
76 for (
int i = 0; i < nblocks; i++)
78 fec = fes[i]->FEColl();
80 (
dynamic_cast<const H1_Trace_FECollection*
>(fec) ||
81 dynamic_cast<const ND_Trace_FECollection*>(fec) ||
82 dynamic_cast<const RT_Trace_FECollection*
>(fec));
86 pmesh =
dynamic_cast<ParMesh *
>(mesh);
88 nullptr : (IsTraceSpace[i]) ? fes[i] :
89 new ParFiniteElementSpace(pmesh, fec->GetTraceCollection(), fes[i]->GetVDim(),
90 fes[i]->GetOrdering());
95 nullptr : (IsTraceSpace[i]) ? fes[i] :
96 new FiniteElementSpace(mesh, fec->GetTraceCollection(), fes[i]->GetVDim(),
97 fes[i]->GetOrdering());
102 nullptr : (IsTraceSpace[i]) ? fes[i] :
103 new FiniteElementSpace(mesh, fec->GetTraceCollection(), fes[i]->GetVDim(),
104 fes[i]->GetOrdering());
106 if (tr_fes[i]) { rblocks++; }
110 ess_tdofs.SetSize(rblocks);
111 for (
int i = 0; i<rblocks; i++)
113 ess_tdofs[i] =
new Array<int>();
119 void BlockStaticCondensation::ComputeOffsets()
121 dof_offsets.
SetSize(nblocks+1);
122 tdof_offsets.
SetSize(nblocks+1);
126 rdof_offsets.
SetSize(rblocks+1);
127 rtdof_offsets.
SetSize(rblocks+1);
129 rtdof_offsets[0] = 0;
132 for (
int i =0; i<nblocks; i++)
134 dof_offsets[i+1] = fes[i]->GetVSize();
135 tdof_offsets[i+1] = fes[i]->GetTrueVSize();
138 rdof_offsets[j+1] = tr_fes[i]->GetVSize();
139 rtdof_offsets[j+1] = tr_fes[i]->GetTrueVSize();
150 void BlockStaticCondensation::Init()
152 lmat.SetSize(mesh->
GetNE());
153 lvec.SetSize(mesh->
GetNE());
154 for (
int i = 0; i < mesh->
GetNE(); i++)
162 S =
new BlockMatrix(rdof_offsets);
167 int h = rdof_offsets[i+1] - rdof_offsets[i];
170 int w = rdof_offsets[j+1] - rdof_offsets[j];
171 S->
SetBlock(i,j,
new SparseMatrix(h, w));
174 y =
new BlockVector(rdof_offsets);
178 void BlockStaticCondensation::GetReducedElementIndicesAndOffsets(
int el,
179 Array<int> & trace_ldofs,
180 Array<int> & interior_ldofs,
181 Array<int> & offsets)
const 184 offsets.SetSize(tr_fes.
Size()+1); offsets = 0;
186 Array<int> faces, ori;
201 MFEM_ABORT(
"BlockStaticCondensation::GetReducedElementIndicesAndOffsets: " 202 "dim > 3 not supported");
204 int numfaces = faces.Size();
206 trace_ldofs.SetSize(0);
207 interior_ldofs.SetSize(0);
212 for (
int i = 0; i<tr_fes.
Size(); i++)
219 ndof = fes[i]->GetVDim()*fes[i]->GetFE(el)->GetDof();
222 else if (IsTraceSpace[i])
224 for (
int iface = 0; iface < numfaces; iface++)
226 td += fes[i]->GetVDim()*fes[i]->GetFaceElement(faces[iface])->GetDof();
232 Array<int> trace_dofs;
233 ndof = fes[i]->GetVDim()*fes[i]->GetFE(el)->GetDof();
234 tr_fes[i]->GetElementVDofs(el, trace_dofs);
235 td = trace_dofs.
Size();
239 int_dofs.SetSize(ndof - td);
240 for (
int j = 0; j<td; j++)
242 tr_dofs[j] = skip + j;
244 for (
int j = 0; j<ndof-td; j++)
246 int_dofs[j] = skip + td + j;
250 trace_ldofs.Append(tr_dofs);
251 interior_ldofs.Append(int_dofs);
253 offsets.PartialSum();
257 void BlockStaticCondensation::GetReducedElementVDofs(
int el,
258 Array<int> & rdofs)
const 260 Array<int> faces, ori;
276 MFEM_ABORT(
"BlockStaticCondensation::GetReducedElementVDofs: " 277 "dim > 3 not supported");
279 int numfaces = faces.Size();
282 for (
int i = 0; i<tr_fes.
Size(); i++)
284 if (!tr_fes[i]) {
continue; }
288 Array<int> face_vdofs;
289 for (
int k = 0; k < numfaces; k++)
291 int iface = faces[k];
292 tr_fes[i]->GetFaceVDofs(iface, face_vdofs);
298 tr_fes[i]->GetElementVDofs(el, vdofs);
300 for (
int j=0; j<vdofs.Size(); j++)
302 vdofs[j] = (vdofs[j]>=0) ? vdofs[j]+rdof_offsets[skip] :
303 vdofs[j]-rdof_offsets[skip];
310 void BlockStaticCondensation::GetElementVDofs(
int el, Array<int> & vdofs)
const 312 Array<int> faces, ori;
328 MFEM_ABORT(
"BlockStaticCondensation::GetElementVDofs: " 329 "dim > 3 not supported");
331 int numfaces = faces.Size();
333 for (
int i = 0; i<tr_fes.
Size(); i++)
338 Array<int> face_vdofs;
339 for (
int k = 0; k < numfaces; k++)
341 int iface = faces[k];
342 fes[i]->GetFaceVDofs(iface, face_vdofs);
348 fes[i]->GetElementVDofs(el, dofs);
350 for (
int j=0; j<dofs.Size(); j++)
352 dofs[j] = (dofs[j]>=0) ? dofs[j]+dof_offsets[i] :
353 dofs[j]-dof_offsets[i];
360 void BlockStaticCondensation::GetLocalSchurComplement(
int el,
361 const Array<int> & tr_idx,
362 const Array<int> & int_idx,
363 const DenseMatrix & elmat,
364 const Vector & elvect,
368 int rdofs = tr_idx.Size();
369 int idofs = int_idx.Size();
370 MFEM_VERIFY(idofs != 0,
"Number of interior dofs is zero");
371 MFEM_VERIFY(rdofs != 0,
"Number of interface dofs is zero");
374 rvect.SetSize(rdofs);
376 DenseMatrix A_tt, A_ti, A_it, A_ii;
379 elmat.GetSubMatrix(tr_idx,A_tt);
380 elmat.GetSubMatrix(tr_idx,int_idx, A_ti);
381 elmat.GetSubMatrix(int_idx, tr_idx, A_it);
382 elmat.GetSubMatrix(int_idx, A_ii);
384 elvect.GetSubVector(tr_idx, y_t);
385 elvect.GetSubVector(int_idx, y_i);
387 DenseMatrixInverse lu(A_ii);
389 lmat[el] =
new DenseMatrix(idofs,rdofs);
390 lvec[el] =
new Vector(idofs);
392 lu.Mult(A_it,*lmat[el]);
393 lu.Mult(y_i,*lvec[el]);
402 A_ti.Mult(*lvec[el], rvect);
416 GetReducedElementIndicesAndOffsets(el, tr_idx,int_idx, offsets);
421 if (int_idx.
Size()!=0)
423 GetLocalSchurComplement(el,tr_idx,int_idx, elmat, elvect, rmat, rvec);
452 MFEM_ABORT(
"BlockStaticCondensation::AssembleReducedSystem: " 453 "dim > 3 not supported");
455 int numfaces = faces.
Size();
458 for (
int i = 0; i<tr_fes.
Size(); i++)
460 if (!tr_fes[i]) {
continue; }
462 doftrans_i =
nullptr;
466 for (
int k = 0; k < numfaces; k++)
468 int iface = faces[k];
469 tr_fes[i]->GetFaceVDofs(iface, face_vdofs);
470 vdofs_i.
Append(face_vdofs);
475 doftrans_i = tr_fes[i]->GetElementVDofs(el, vdofs_i);
478 for (
int j = 0; j<tr_fes.
Size(); j++)
480 if (!tr_fes[j]) {
continue; }
482 doftrans_j =
nullptr;
487 for (
int k = 0; k < numfaces; k++)
489 int iface = faces[k];
490 tr_fes[j]->GetFaceVDofs(iface, face_vdofs);
491 vdofs_j.
Append(face_vdofs);
496 doftrans_j = tr_fes[j]->GetElementVDofs(el, vdofs_j);
501 offsets[j],offsets[j+1], Ae);
502 if (doftrans_i || doftrans_j)
511 double * data = rvecptr->
GetData();
515 offsets[i+1]-offsets[i]);
525 void BlockStaticCondensation::BuildProlongation()
532 for (
int i = 0; i<nblocks; i++)
534 if (!tr_fes[i]) {
continue; }
535 const SparseMatrix *P_ = tr_fes[i]->GetConformingProlongation();
538 const SparseMatrix *R_ = tr_fes[i]->GetRestrictionMatrix();
539 P->
SetBlock(skip,skip,const_cast<SparseMatrix*>(P_));
540 R->
SetBlock(skip,skip,const_cast<SparseMatrix*>(R_));
547 void BlockStaticCondensation::BuildParallelProlongation()
549 MFEM_VERIFY(parallel,
"BuildParallelProlongation: wrong code path");
550 pP =
new BlockOperator(rdof_offsets, rtdof_offsets);
551 R =
new BlockMatrix(rtdof_offsets, rdof_offsets);
555 for (
int i = 0; i<nblocks; i++)
557 if (!tr_fes[i]) {
continue; }
558 const HypreParMatrix *P_ =
559 dynamic_cast<ParFiniteElementSpace *
>(tr_fes[i])->Dof_TrueDof_Matrix();
562 const SparseMatrix *R_ = tr_fes[i]->GetRestrictionMatrix();
563 pP->
SetBlock(skip,skip,const_cast<HypreParMatrix*>(P_));
564 R->
SetBlock(skip,skip,const_cast<SparseMatrix*>(R_));
572 if (!pP) { BuildParallelProlongation(); }
583 for (
int i = 0; i<nblocks; i++)
585 if (!tr_fes[i]) {
continue; }
589 for (
int j = 0; j<nblocks; j++)
591 if (!tr_fes[j]) {
continue; }
593 if (skip_i == skip_j)
624 void BlockStaticCondensation::ConformingAssemble(
int skip_zeros)
627 if (!P) { BuildProlongation(); }
654 if (S_e) { S_e->
Finalize(skip_zeros); }
664 bool conforming =
true;
665 for (
int i = 0; i<nblocks; i++)
667 if (!tr_fes[i]) {
continue; }
668 const SparseMatrix *P_ = tr_fes[i]->GetConformingProlongation();
675 if (!conforming) { ConformingAssemble(0); }
676 const int remove_zeros = 0;
684 FillEssTdofLists(ess_rtdof_list);
687 const int remove_zeros = 0;
691 delete S_e; S_e =
nullptr;
698 void BlockStaticCondensation::ConvertMarkerToReducedTrueDofs(
707 int * data = tdof_marker.
GetData();
708 for (
int i = 0; i<nblocks; i++)
710 tdof_marker0.
MakeRef(&data[tdof_offsets[i]],tdof_offsets[i+1]-tdof_offsets[i]);
711 const SparseMatrix * R_ = fes[i]->GetRestrictionMatrix();
714 dof_marker0.
MakeRef(tdof_marker0);
718 dof_marker0.
SetSize(fes[i]->GetVSize());
721 dof_marker.
Append(dof_marker0);
724 int rdofs = rdof_edof.
Size();
725 Array<int> rdof_marker(rdofs);
727 for (
int i = 0; i < rdofs; i++)
729 rdof_marker[i] = dof_marker[rdof_edof[i]];
733 Array<int> rtdof_marker0;
734 Array<int> rdof_marker0;
735 int * rdata = rdof_marker.
GetData();
737 for (
int i = 0; i<nblocks; i++)
739 if (!tr_fes[i]) {
continue; }
740 rdof_marker0.MakeRef(&rdata[rdof_offsets[k]],rdof_offsets[k+1]-rdof_offsets[k]);
741 const SparseMatrix *tr_R = tr_fes[i]->GetRestrictionMatrix();
744 rtdof_marker0.
MakeRef(rdof_marker0);
748 rtdof_marker0.SetSize(tr_fes[i]->GetTrueVSize());
749 tr_R->BooleanMult(rdof_marker0, rtdof_marker0);
751 rtdof_marker.
Append(rtdof_marker0);
756 void BlockStaticCondensation::FillEssTdofLists(
const Array<int> & ess_tdof_list)
759 for (
int i = 0; i<ess_tdof_list.Size(); i++)
761 int tdof = ess_tdof_list[i];
762 for (j = 0; j < rblocks; j++)
764 if (rtdof_offsets[j+1] > tdof) {
break; }
766 ess_tdofs[j]->Append(tdof-rtdof_offsets[j]);
776 ConvertMarkerToReducedTrueDofs(tdof_marker, rtdof_marker);
784 MFEM_VERIFY(!parallel,
"EliminateReducedTrueDofs::Wrong Code path");
790 offsets.
MakeRef( (P) ? rtdof_offsets : rdof_offsets);
796 int h = offsets[i+1] - offsets[i];
799 int w = offsets[j+1] - offsets[j];
810 MFEM_ASSERT(sol.
Size() == dof_offsets.
Last(),
"'sol' has incorrect size");
811 const int nrdofs = rdof_offsets.Last();
822 for (
int i = 0; i < nrdofs; i++)
824 sol_r(i) = sol(rdof_edof[i]);
831 R->
Mult(blsol_r, sc_sol);
837 int copy_interior)
const 865 for (
int j = 0; j<rblocks; j++)
867 if (!ess_tdofs[j]->Size()) {
continue; }
871 for (
int i = 0; i < ess_tdofs[j]->Size(); i++)
873 int tdof = (*ess_tdofs[j])[i];
874 int gdof = tdof + rtdof_offsets[j];
875 B(gdof) = diag(tdof)*X(gdof);
888 const int nrdofs = rdof_offsets.Last();
889 const int nrtdofs = rtdof_offsets.
Last();
890 MFEM_VERIFY(sc_sol.
Size() == nrtdofs,
"'sc_sol' has incorrect size");
901 sol_r.SetSize(nrdofs);
902 P->
Mult(sc_sol, sol_r);
908 sol_r.SetSize(nrdofs);
909 pP->
Mult(sc_sol, sol_r);
913 if (rdof_offsets.Last() == dof_offsets.
Last())
925 const int NE = mesh->
GetNE();
931 for (
int iel = 0; iel < NE; iel++)
933 lsol.
SetSize(lmat[iel]->Width() + lmat[iel]->Height());
934 GetReducedElementVDofs(iel, trace_vdofs);
937 sol_r.GetSubVector(trace_vdofs, lsr);
940 lsi.
SetSize(lmat[iel]->Height());
941 lmat[iel]->Mult(lsr,lsi);
946 GetReducedElementIndicesAndOffsets(iel,tr_idx, int_idx, idx_offs);
951 GetElementVDofs(iel, vdofs);
960 delete S_e; S_e =
nullptr;
964 if (P) {
delete P; } P=
nullptr;
965 if (R) {
delete R; } R=
nullptr;
970 delete pS; pS=
nullptr;
971 delete pS_e; pS_e=
nullptr;
972 for (
int i = 0; i<rblocks; i++)
976 delete pP; pP=
nullptr;
980 for (
int i=0; i<lmat.Size(); i++)
982 delete lmat[i]; lmat[i] =
nullptr;
983 delete lvec[i]; lvec[i] =
nullptr;
void EliminateRowsCols(const Array< int > &rows_cols, const HypreParVector &X, HypreParVector &B)
void SetSubVector(const Array< int > &dofs, const double value)
Set the entries listed in dofs to the given value.
void GetElementEdges(int i, Array< int > &edges, Array< int > &cor) const
Return the indices and the orientations of all edges of element i.
A class to handle Vectors in a block fashion.
void PartMult(const Array< int > &rows, const Vector &x, Vector &y) const
Partial matrix vector multiplication of (*this) with x involving only the rows given by rows...
Field is discontinuous across element interfaces.
int Dimension() const
Dimension of the reference space used within the elements.
int owns_blocks
If owns_blocks the SparseMatrix objects Aij will be deallocated.
void SetSize(int s)
Resize the vector to size s.
void Mult(const Table &A, const Table &B, Table &C)
C = A * B (as boolean matrices)
int Width() const
Get the width (size of input) of the Operator. Synonym with NumCols().
T * GetData()
Returns the data.
int Size() const
Returns the size of the vector.
Data type dense matrix using column-major storage.
Abstract parallel finite element space.
~BlockStaticCondensation()
void FormSystemMatrix(Operator::DiagonalPolicy diag_policy)
Operator & GetBlock(int i, int j)
Return a reference to block i,j.
static void MarkerToList(const Array< int > &marker, Array< int > &list)
Convert a Boolean marker array to a list containing all marked indices.
void SetBlock(int i, int j, SparseMatrix *mat)
Set A(i,j) = mat.
int NumRowBlocks() const
Return the number of row blocks.
virtual void Finalize(int skip_zeros=1)
Finalize all the submatrices.
void ReduceSystem(Vector &x, Vector &X, Vector &B, int copy_interior=0) const
Set the reduced solution X and r.h.s B vectors from the full linear system solution x and r...
void GetElementFaces(int i, Array< int > &faces, Array< int > &ori) const
Return the indices and the orientations of all faces of element i.
void ParallelAssemble(BlockMatrix *m)
int Append(const T &el)
Append element 'el' to array, resize if necessary.
virtual void MultTranspose(const Vector &x, Vector &y) const
MatrixTranspose-Vector Multiplication y = A'*x.
void GetElementVertices(int i, Array< int > &v) const
Returns the indices of the vertices of element i.
int NumColBlocks() const
Return the number of column blocks.
void GetDiag(Vector &diag) const
Get the local diagonal of the matrix.
void RAP(const DenseMatrix &A, const DenseMatrix &P, DenseMatrix &RAP)
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...
void AddSubMatrix(const Array< int > &rows, const Array< int > &cols, const DenseMatrix &subm, int skip_zeros=1)
void Finalize(int skip_zeros=0)
Finalize the construction of the Schur complement matrix.
void SetSubVectorComplement(const Array< int > &dofs, const double val)
Set all vector entries NOT in the dofs Array to the given val.
virtual void MultTranspose(const Vector &x, Vector &y) const
Action of the transpose operator.
double * GetData() const
Return a pointer to the beginning of the Vector data.
HypreParMatrix * EliminateCols(const Array< int > &cols)
virtual void Mult(const Vector &x, Vector &y) const
Operator application.
HYPRE_BigInt GlobalVSize() const
void ReduceSolution(const Vector &sol, Vector &sc_sol) const
void SetSize(int nsize)
Change the logical size of the array, keep existing entries.
void PartialSum()
Fill the entries of the array with the cumulative sum of the entries.
void Transpose(const Table &A, Table &At, int ncols_A_)
Transpose a Table.
virtual void Mult(const Vector &x, Vector &y) const
Matrix-Vector Multiplication y = A*x.
int Height() const
Get the height (size of output) of the Operator. Synonym with NumRows().
void SetDataAndSize(double *d, int s)
Set the Vector data and size.
void SetEssentialTrueDofs(const Array< int > &ess_tdof_list)
Determine and save internally essential reduced true dofs.
HYPRE_BigInt * GetDofOffsets() const
int GetNE() const
Returns number of elements.
void EliminateRows(const Array< int > &rows)
Eliminate rows from the diagonal and off-diagonal blocks of the matrix.
void AssembleReducedSystem(int el, DenseMatrix &elmat, Vector &elvect)
void GetSubMatrix(const Array< int > &idx, DenseMatrix &A) const
DiagonalPolicy
Defines operator diagonal policy upon elimination of rows and/or columns.
SparseMatrix & GetBlock(int i, int j)
Return a reference to block (i,j). Reference may be invalid if Aij(i,j) == NULL.
virtual void AddMult(const Vector &x, Vector &y, const double val=1.) const
Matrix-Vector Multiplication y = y + val*A*x.
int Size() const
Return the logical size of the array.
T & Last()
Return the last element in 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.
void ComputeSolution(const Vector &sc_sol, Vector &sol) const
void MakeRef(Vector &base, int offset, int size)
Reset the Vector to be a reference to a sub-vector of base.
void TransformDual(const DofTransformation *ran_dof_trans, const DofTransformation *dom_dof_trans, DenseMatrix &elmat)
void EliminateReducedTrueDofs(const Array< int > &ess_rtdof_list, Matrix::DiagonalPolicy dpolicy)
Eliminate the given reduced true dofs from the Schur complement matrix S.
BlockStaticCondensation(Array< FiniteElementSpace *> &fes_)
Wrapper for hypre's ParCSR matrix class.
A class to handle Block systems in a matrix-free implementation.
Class for parallel meshes.
void EliminateRowCols(const Array< int > &vdofs, BlockMatrix *Ae, DiagonalPolicy dpolicy=DIAG_ONE)
Eliminate the rows and columns corresponding to the entries in vdofs + save the eliminated entries in...
void SetBlock(int iRow, int iCol, Operator *op, double c=1.0)
Add a block op in the block-entry (iblock, jblock).
int IsZeroBlock(int i, int j) const
Check if block (i,j) is a zero block.
Vector & GetBlock(int i)
Get the i-th vector in the block.
void Neg()
(*this) = -(*this)
void BooleanMultTranspose(const Array< int > &x, Array< int > &y) const
y = At * x, treating all entries as booleans (zero=false, nonzero=true).