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);
71 tr_fes.SetSize(nblocks);
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>();
119void 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();
150void 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);
178void 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();
257void 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);
293 vdofs.Append(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];
310void 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);
343 dofs.Append(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];
360void 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; }
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 tr_fes[i]->GetElementVDofs(el, vdofs_i, doftrans_i);
478 for (
int j = 0; j<tr_fes.Size(); j++)
480 if (!tr_fes[j]) {
continue; }
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 tr_fes[j]->GetElementVDofs(el, vdofs_j, doftrans_j);
501 offsets[j],offsets[j+1], Ae);
512 offsets[i+1]-offsets[i]);
519void BlockStaticCondensation::BuildProlongation()
526 for (
int i = 0; i<nblocks; i++)
528 if (!tr_fes[i]) {
continue; }
529 const SparseMatrix *P_ = tr_fes[i]->GetConformingProlongation();
532 const SparseMatrix *R_ = tr_fes[i]->GetRestrictionMatrix();
533 P->
SetBlock(skip,skip,
const_cast<SparseMatrix*
>(P_));
534 R->
SetBlock(skip,skip,
const_cast<SparseMatrix*
>(R_));
541void BlockStaticCondensation::BuildParallelProlongation()
543 MFEM_VERIFY(parallel,
"BuildParallelProlongation: wrong code path");
544 pP =
new BlockOperator(rdof_offsets, rtdof_offsets);
545 R =
new BlockMatrix(rtdof_offsets, rdof_offsets);
549 for (
int i = 0; i<nblocks; i++)
551 if (!tr_fes[i]) {
continue; }
552 const HypreParMatrix *P_ =
553 dynamic_cast<ParFiniteElementSpace *
>(tr_fes[i])->Dof_TrueDof_Matrix();
556 const SparseMatrix *R_ = tr_fes[i]->GetRestrictionMatrix();
557 pP->
SetBlock(skip,skip,
const_cast<HypreParMatrix*
>(P_));
558 R->
SetBlock(skip,skip,
const_cast<SparseMatrix*
>(R_));
566 if (!pP) { BuildParallelProlongation(); }
577 for (
int i = 0; i<nblocks; i++)
579 if (!tr_fes[i]) {
continue; }
583 for (
int j = 0; j<nblocks; j++)
585 if (!tr_fes[j]) {
continue; }
587 if (skip_i == skip_j)
618void BlockStaticCondensation::ConformingAssemble(
int skip_zeros)
621 if (!P) { BuildProlongation(); }
648 if (S_e) { S_e->
Finalize(skip_zeros); }
658 bool conforming =
true;
659 for (
int i = 0; i<nblocks; i++)
661 if (!tr_fes[i]) {
continue; }
662 const SparseMatrix *P_ = tr_fes[i]->GetConformingProlongation();
669 if (!conforming) { ConformingAssemble(0); }
670 const int remove_zeros = 0;
678 FillEssTdofLists(ess_rtdof_list);
681 const int remove_zeros = 0;
685 delete S_e; S_e =
nullptr;
692void BlockStaticCondensation::ConvertMarkerToReducedTrueDofs(
701 int * data = tdof_marker.
GetData();
702 for (
int i = 0; i<nblocks; i++)
704 tdof_marker0.
MakeRef(&data[tdof_offsets[i]],tdof_offsets[i+1]-tdof_offsets[i]);
705 const SparseMatrix * R_ = fes[i]->GetRestrictionMatrix();
708 dof_marker0.
MakeRef(tdof_marker0);
712 dof_marker0.
SetSize(fes[i]->GetVSize());
715 dof_marker.
Append(dof_marker0);
718 int rdofs = rdof_edof.
Size();
719 Array<int> rdof_marker(rdofs);
721 for (
int i = 0; i < rdofs; i++)
723 rdof_marker[i] = dof_marker[rdof_edof[i]];
727 Array<int> rtdof_marker0;
728 Array<int> rdof_marker0;
729 int * rdata = rdof_marker.
GetData();
731 for (
int i = 0; i<nblocks; i++)
733 if (!tr_fes[i]) {
continue; }
734 rdof_marker0.MakeRef(&rdata[rdof_offsets[k]],rdof_offsets[k+1]-rdof_offsets[k]);
735 const SparseMatrix *tr_R = tr_fes[i]->GetRestrictionMatrix();
738 rtdof_marker0.MakeRef(rdof_marker0);
743 tr_R->BooleanMult(rdof_marker0, rtdof_marker0);
745 rtdof_marker.
Append(rtdof_marker0);
750void BlockStaticCondensation::FillEssTdofLists(
const Array<int> & ess_tdof_list)
753 for (
int i = 0; i<ess_tdof_list.Size(); i++)
755 int tdof = ess_tdof_list[i];
756 for (j = 0; j < rblocks; j++)
758 if (rtdof_offsets[j+1] > tdof) {
break; }
760 ess_tdofs[j]->Append(tdof-rtdof_offsets[j]);
770 ConvertMarkerToReducedTrueDofs(tdof_marker, rtdof_marker);
778 MFEM_VERIFY(!parallel,
"EliminateReducedTrueDofs::Wrong Code path");
784 offsets.
MakeRef( (P) ? rtdof_offsets : rdof_offsets);
790 int h = offsets[i+1] - offsets[i];
793 int w = offsets[j+1] - offsets[j];
804 MFEM_ASSERT(sol.
Size() == dof_offsets.
Last(),
"'sol' has incorrect size");
805 const int nrdofs = rdof_offsets.Last();
816 for (
int i = 0; i < nrdofs; i++)
818 sol_r(i) = sol(rdof_edof[i]);
825 R->
Mult(blsol_r, sc_sol);
831 int copy_interior)
const
859 for (
int j = 0; j<rblocks; j++)
861 if (!ess_tdofs[j]->Size()) {
continue; }
865 for (
int i = 0; i < ess_tdofs[j]->Size(); i++)
867 int tdof = (*ess_tdofs[j])[i];
868 int gdof = tdof + rtdof_offsets[j];
869 B(gdof) = diag(tdof)*X(gdof);
882 const int nrdofs = rdof_offsets.Last();
883 const int nrtdofs = rtdof_offsets.
Last();
884 MFEM_VERIFY(sc_sol.
Size() == nrtdofs,
"'sc_sol' has incorrect size");
896 P->
Mult(sc_sol, sol_r);
903 pP->
Mult(sc_sol, sol_r);
907 if (rdof_offsets.Last() == dof_offsets.
Last())
919 const int NE = mesh->
GetNE();
925 for (
int iel = 0; iel < NE; iel++)
927 lsol.
SetSize(lmat[iel]->Width() + lmat[iel]->Height());
928 GetReducedElementVDofs(iel, trace_vdofs);
934 lsi.
SetSize(lmat[iel]->Height());
935 lmat[iel]->Mult(lsr,lsi);
940 GetReducedElementIndicesAndOffsets(iel,tr_idx, int_idx, idx_offs);
945 GetElementVDofs(iel, vdofs);
954 delete S_e; S_e =
nullptr;
958 if (P) {
delete P; } P=
nullptr;
959 if (R) {
delete R; } R=
nullptr;
964 delete pS; pS=
nullptr;
965 delete pS_e; pS_e=
nullptr;
966 for (
int i = 0; i<rblocks; i++)
970 delete pP; pP=
nullptr;
974 for (
int i=0; i<lmat.Size(); i++)
976 delete lmat[i]; lmat[i] =
nullptr;
977 delete lvec[i]; lvec[i] =
nullptr;
void SetSize(int nsize)
Change the logical size of the array, keep existing entries.
int Size() const
Return the logical size of the array.
void PartialSum()
Fill the entries of the array with the cumulative sum of the entries.
void MakeRef(T *data_, int size_, bool own_data=false)
Make this Array a reference to a pointer.
int Append(const T &el)
Append element 'el' to array, resize if necessary.
T * GetData()
Returns the data.
T & Last()
Return the last element in the array.
void MultTranspose(const Vector &x, Vector &y) const override
MatrixTranspose-Vector Multiplication y = A'*x.
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....
void SetBlock(int i, int j, SparseMatrix *mat)
Set A(i,j) = mat.
void Mult(const Vector &x, Vector &y) const override
Matrix-Vector Multiplication y = A*x.
int NumColBlocks() const
Return the number of column blocks.
int IsZeroBlock(int i, int j) const
Check if block (i,j) is a zero block.
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...
SparseMatrix & GetBlock(int i, int j)
Return a reference to block (i,j). Reference may be invalid if Aij(i,j) == NULL.
void AddMult(const Vector &x, Vector &y, const real_t val=1.) const override
Matrix-Vector Multiplication y = y + val*A*x.
int owns_blocks
If owns_blocks the SparseMatrix objects Aij will be deallocated.
void Finalize(int skip_zeros=1) override
Finalize all the submatrices.
int NumRowBlocks() const
Return the number of row blocks.
A class to handle Block systems in a matrix-free implementation.
void Mult(const Vector &x, Vector &y) const override
Operator application.
void SetBlock(int iRow, int iCol, Operator *op, real_t c=1.0)
Add a block op in the block-entry (iblock, jblock).
Operator & GetBlock(int i, int j)
Return a reference to block i,j.
void MultTranspose(const Vector &x, Vector &y) const override
Action of the transpose operator.
~BlockStaticCondensation()
void FormSystemMatrix(Operator::DiagonalPolicy diag_policy)
void EliminateReducedTrueDofs(const Array< int > &ess_rtdof_list, Matrix::DiagonalPolicy dpolicy)
Eliminate the given reduced true dofs from the Schur complement matrix S.
void SetEssentialTrueDofs(const Array< int > &ess_tdof_list)
Determine and save internally essential reduced true dofs.
BlockStaticCondensation(Array< FiniteElementSpace * > &fes_)
void ParallelAssemble(BlockMatrix *m)
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 ComputeSolution(const Vector &sc_sol, Vector &sol) const
void ReduceSolution(const Vector &sol, Vector &sc_sol) const
void Finalize(int skip_zeros=0)
Finalize the construction of the Schur complement matrix.
void AssembleReducedSystem(int el, DenseMatrix &elmat, Vector &elvect)
A class to handle Vectors in a block fashion.
Vector & GetBlock(int i)
Get the i-th vector in the block.
Data type dense matrix using column-major storage.
void GetSubMatrix(const Array< int > &idx, DenseMatrix &A) const
@ DISCONTINUOUS
Field is discontinuous across element interfaces.
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...
static void MarkerToList(const Array< int > &marker, Array< int > &list)
Convert a Boolean marker array to a list containing all marked indices.
Wrapper for hypre's ParCSR matrix class.
void GetDiag(Vector &diag) const
Get the local diagonal of the matrix.
void EliminateRows(const Array< int > &rows)
Eliminate rows from the diagonal and off-diagonal blocks of the matrix.
void EliminateRowsCols(const Array< int > &rows_cols, const HypreParVector &X, HypreParVector &B)
HypreParMatrix * EliminateCols(const Array< int > &cols)
void GetElementVertices(int i, Array< int > &v) const
Returns the indices of the vertices of element i.
int GetNE() const
Returns number of elements.
int Dimension() const
Dimension of the reference space used within the elements.
void GetElementFaces(int i, Array< int > &faces, Array< int > &ori) const
Return the indices and the orientations of all faces of element i.
void GetElementEdges(int i, Array< int > &edges, Array< int > &cor) const
Return the indices and the orientations of all edges of element i.
int Height() const
Get the height (size of output) of the Operator. Synonym with NumRows().
DiagonalPolicy
Defines operator diagonal policy upon elimination of rows and/or columns.
int Width() const
Get the width (size of input) of the Operator. Synonym with NumCols().
Abstract parallel finite element space.
HYPRE_BigInt GlobalVSize() const
HYPRE_BigInt * GetDofOffsets() const
Class for parallel meshes.
void BooleanMultTranspose(const Array< int > &x, Array< int > &y) const
y = At * x, treating all entries as booleans (zero=false, nonzero=true).
void AddSubMatrix(const Array< int > &rows, const Array< int > &cols, const DenseMatrix &subm, int skip_zeros=1)
void Neg()
(*this) = -(*this)
void SetDataAndSize(real_t *d, int s)
Set the Vector data and size.
void SetSubVector(const Array< int > &dofs, const real_t value)
Set the entries listed in dofs to the given value.
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...
int Size() const
Returns the size of the vector.
void SetSize(int s)
Resize the vector to size s.
real_t * GetData() const
Return a pointer to the beginning of the Vector data.
void SetSubVectorComplement(const Array< int > &dofs, const real_t val)
Set all vector entries NOT in the dofs Array to the given val.
void GetSubVector(const Array< int > &dofs, Vector &elemvect) const
Extract entries listed in dofs to the output Vector elemvect.
void MakeRef(Vector &base, int offset, int size)
Reset the Vector to be a reference to a sub-vector of base.
int GetVDim(const FieldDescriptor &f)
Get the vdim of a field descriptor.
int GetTrueVSize(const FieldDescriptor &f)
Get the true dof size of a field descriptor.
void Mult(const Table &A, const Table &B, Table &C)
C = A * B (as boolean matrices)
void TransformDual(const DofTransformation &ran_dof_trans, const DofTransformation &dom_dof_trans, DenseMatrix &elmat)
void Transpose(const Table &A, Table &At, int ncols_A_)
Transpose a Table.
void RAP(const DenseMatrix &A, const DenseMatrix &P, DenseMatrix &RAP)