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; }
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)
515 offsets[i+1]-offsets[i]);
525void 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_));
547void 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)
624void 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;
698void 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);
756void 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");
902 P->
Mult(sc_sol, sol_r);
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);
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 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.
virtual void AddMult(const Vector &x, Vector &y, const real_t val=1.) const
Matrix-Vector Multiplication y = y + val*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.
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.
int owns_blocks
If owns_blocks the SparseMatrix objects Aij will be deallocated.
virtual void Finalize(int skip_zeros=1)
Finalize all the submatrices.
virtual void Mult(const Vector &x, Vector &y) const
Matrix-Vector Multiplication y = A*x.
virtual void MultTranspose(const Vector &x, Vector &y) const
MatrixTranspose-Vector Multiplication y = A'*x.
int NumRowBlocks() const
Return the number of row blocks.
A class to handle Block systems in a matrix-free implementation.
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.
virtual void Mult(const Vector &x, Vector &y) const
Operator application.
virtual void MultTranspose(const Vector &x, Vector &y) const
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.
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)