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 tr_fec.SetSize(nblocks);
73 mesh = fes[0]->GetMesh();
76 const FiniteElementCollection * fec;
77 for (
int i = 0; i < nblocks; i++)
80 fec = fes[i]->FEColl();
82 (
dynamic_cast<const H1_Trace_FECollection*
>(fec) ||
83 dynamic_cast<const ND_Trace_FECollection*
>(fec) ||
84 dynamic_cast<const RT_Trace_FECollection*
>(fec));
88 pmesh =
dynamic_cast<ParMesh *
>(mesh);
90 nullptr : (IsTraceSpace[i]) ? fes[i] :
91 new ParFiniteElementSpace(pmesh, tr_fec[i] = fec->GetTraceCollection(),
93 fes[i]->GetOrdering());
98 nullptr : (IsTraceSpace[i]) ? fes[i] :
99 new FiniteElementSpace(mesh, tr_fec[i] = fec->GetTraceCollection(),
101 fes[i]->GetOrdering());
106 nullptr : (IsTraceSpace[i]) ? fes[i] :
107 new FiniteElementSpace(mesh, tr_fec[i] = fec->GetTraceCollection(),
109 fes[i]->GetOrdering());
111 if (tr_fes[i]) { rblocks++; }
115 ess_tdofs.SetSize(rblocks);
116 for (
int i = 0; i<rblocks; i++)
118 ess_tdofs[i] =
new Array<int>();
124void BlockStaticCondensation::ComputeOffsets()
126 dof_offsets.
SetSize(nblocks+1);
127 tdof_offsets.
SetSize(nblocks+1);
131 rdof_offsets.
SetSize(rblocks+1);
132 rtdof_offsets.
SetSize(rblocks+1);
134 rtdof_offsets[0] = 0;
137 for (
int i =0; i<nblocks; i++)
139 dof_offsets[i+1] = fes[i]->GetVSize();
140 tdof_offsets[i+1] = fes[i]->GetTrueVSize();
143 rdof_offsets[j+1] = tr_fes[i]->GetVSize();
144 rtdof_offsets[j+1] = tr_fes[i]->GetTrueVSize();
155void BlockStaticCondensation::Init()
157 lmat.SetSize(mesh->
GetNE());
158 lvec.SetSize(mesh->
GetNE());
159 for (
int i = 0; i < mesh->
GetNE(); i++)
167 S =
new BlockMatrix(rdof_offsets);
172 int h = rdof_offsets[i+1] - rdof_offsets[i];
175 int w = rdof_offsets[j+1] - rdof_offsets[j];
176 S->
SetBlock(i,j,
new SparseMatrix(h, w));
179 y =
new BlockVector(rdof_offsets);
183void BlockStaticCondensation::GetReducedElementIndicesAndOffsets(
int el,
184 Array<int> & trace_ldofs,
185 Array<int> & interior_ldofs,
186 Array<int> & offsets)
const
189 offsets.SetSize(tr_fes.Size()+1); offsets = 0;
191 Array<int> faces, ori;
206 MFEM_ABORT(
"BlockStaticCondensation::GetReducedElementIndicesAndOffsets: "
207 "dim > 3 not supported");
209 int numfaces = faces.Size();
211 trace_ldofs.SetSize(0);
212 interior_ldofs.SetSize(0);
217 for (
int i = 0; i<tr_fes.Size(); i++)
224 ndof = fes[i]->GetVDim()*fes[i]->GetFE(el)->GetDof();
227 else if (IsTraceSpace[i])
229 for (
int iface = 0; iface < numfaces; iface++)
231 td += fes[i]->GetVDim()*fes[i]->GetFaceElement(faces[iface])->GetDof();
237 Array<int> trace_dofs;
238 ndof = fes[i]->GetVDim()*fes[i]->GetFE(el)->GetDof();
239 tr_fes[i]->GetElementVDofs(el, trace_dofs);
240 td = trace_dofs.Size();
244 int_dofs.SetSize(ndof - td);
245 for (
int j = 0; j<td; j++)
247 tr_dofs[j] = skip + j;
249 for (
int j = 0; j<ndof-td; j++)
251 int_dofs[j] = skip + td + j;
255 trace_ldofs.Append(tr_dofs);
256 interior_ldofs.Append(int_dofs);
258 offsets.PartialSum();
262void BlockStaticCondensation::GetReducedElementVDofs(
int el,
263 Array<int> & rdofs)
const
265 Array<int> faces, ori;
281 MFEM_ABORT(
"BlockStaticCondensation::GetReducedElementVDofs: "
282 "dim > 3 not supported");
284 int numfaces = faces.Size();
287 for (
int i = 0; i<tr_fes.Size(); i++)
289 if (!tr_fes[i]) {
continue; }
293 Array<int> face_vdofs;
294 for (
int k = 0; k < numfaces; k++)
296 int iface = faces[k];
297 tr_fes[i]->GetFaceVDofs(iface, face_vdofs);
298 vdofs.Append(face_vdofs);
303 tr_fes[i]->GetElementVDofs(el, vdofs);
305 for (
int j=0; j<vdofs.Size(); j++)
307 vdofs[j] = (vdofs[j]>=0) ? vdofs[j]+rdof_offsets[skip] :
308 vdofs[j]-rdof_offsets[skip];
315void BlockStaticCondensation::GetElementVDofs(
int el, Array<int> & vdofs)
const
317 Array<int> faces, ori;
333 MFEM_ABORT(
"BlockStaticCondensation::GetElementVDofs: "
334 "dim > 3 not supported");
336 int numfaces = faces.Size();
338 for (
int i = 0; i<tr_fes.Size(); i++)
343 Array<int> face_vdofs;
344 for (
int k = 0; k < numfaces; k++)
346 int iface = faces[k];
347 fes[i]->GetFaceVDofs(iface, face_vdofs);
348 dofs.Append(face_vdofs);
353 fes[i]->GetElementVDofs(el, dofs);
355 for (
int j=0; j<dofs.Size(); j++)
357 dofs[j] = (dofs[j]>=0) ? dofs[j]+dof_offsets[i] :
358 dofs[j]-dof_offsets[i];
365void BlockStaticCondensation::GetLocalSchurComplement(
int el,
366 const Array<int> & tr_idx,
367 const Array<int> & int_idx,
368 const DenseMatrix & elmat,
369 const Vector & elvect,
373 int rdofs = tr_idx.Size();
374 int idofs = int_idx.Size();
375 MFEM_VERIFY(idofs != 0,
"Number of interior dofs is zero");
376 MFEM_VERIFY(rdofs != 0,
"Number of interface dofs is zero");
379 rvect.SetSize(rdofs);
381 DenseMatrix A_tt, A_ti, A_it, A_ii;
384 elmat.GetSubMatrix(tr_idx,A_tt);
385 elmat.GetSubMatrix(tr_idx,int_idx, A_ti);
386 elmat.GetSubMatrix(int_idx, tr_idx, A_it);
387 elmat.GetSubMatrix(int_idx, A_ii);
389 elvect.GetSubVector(tr_idx, y_t);
390 elvect.GetSubVector(int_idx, y_i);
392 DenseMatrixInverse lu(A_ii);
394 lmat[el] =
new DenseMatrix(idofs,rdofs);
395 lvec[el] =
new Vector(idofs);
397 lu.Mult(A_it,*lmat[el]);
398 lu.Mult(y_i,*lvec[el]);
407 A_ti.Mult(*lvec[el], rvect);
421 GetReducedElementIndicesAndOffsets(el, tr_idx,int_idx, offsets);
426 if (int_idx.
Size()!=0)
428 GetLocalSchurComplement(el,tr_idx,int_idx, elmat, elvect, rmat, rvec);
457 MFEM_ABORT(
"BlockStaticCondensation::AssembleReducedSystem: "
458 "dim > 3 not supported");
460 int numfaces = faces.
Size();
463 for (
int i = 0; i<tr_fes.Size(); i++)
465 if (!tr_fes[i]) {
continue; }
471 for (
int k = 0; k < numfaces; k++)
473 int iface = faces[k];
474 tr_fes[i]->GetFaceVDofs(iface, face_vdofs);
475 vdofs_i.
Append(face_vdofs);
480 tr_fes[i]->GetElementVDofs(el, vdofs_i, doftrans_i);
483 for (
int j = 0; j<tr_fes.Size(); j++)
485 if (!tr_fes[j]) {
continue; }
492 for (
int k = 0; k < numfaces; k++)
494 int iface = faces[k];
495 tr_fes[j]->GetFaceVDofs(iface, face_vdofs);
496 vdofs_j.
Append(face_vdofs);
501 tr_fes[j]->GetElementVDofs(el, vdofs_j, doftrans_j);
506 offsets[j],offsets[j+1], Ae);
517 offsets[i+1]-offsets[i]);
524void BlockStaticCondensation::BuildProlongation()
531 for (
int i = 0; i<nblocks; i++)
533 if (!tr_fes[i]) {
continue; }
534 const SparseMatrix *P_ = tr_fes[i]->GetConformingProlongation();
537 const SparseMatrix *R_ = tr_fes[i]->GetRestrictionMatrix();
538 P->
SetBlock(skip,skip,
const_cast<SparseMatrix*
>(P_));
539 R->
SetBlock(skip,skip,
const_cast<SparseMatrix*
>(R_));
546void BlockStaticCondensation::BuildParallelProlongation()
548 MFEM_VERIFY(parallel,
"BuildParallelProlongation: wrong code path");
549 pP =
new BlockOperator(rdof_offsets, rtdof_offsets);
550 R =
new BlockMatrix(rtdof_offsets, rdof_offsets);
554 for (
int i = 0; i<nblocks; i++)
556 if (!tr_fes[i]) {
continue; }
557 const HypreParMatrix *P_ =
558 dynamic_cast<ParFiniteElementSpace *
>(tr_fes[i])->Dof_TrueDof_Matrix();
561 const SparseMatrix *R_ = tr_fes[i]->GetRestrictionMatrix();
562 pP->
SetBlock(skip,skip,
const_cast<HypreParMatrix*
>(P_));
563 R->
SetBlock(skip,skip,
const_cast<SparseMatrix*
>(R_));
571 if (!pP) { BuildParallelProlongation(); }
582 for (
int i = 0; i<nblocks; i++)
584 if (!tr_fes[i]) {
continue; }
588 for (
int j = 0; j<nblocks; j++)
590 if (!tr_fes[j]) {
continue; }
592 if (skip_i == skip_j)
623void BlockStaticCondensation::ConformingAssemble(
int skip_zeros)
626 if (!P) { BuildProlongation(); }
653 if (S_e) { S_e->
Finalize(skip_zeros); }
663 bool conforming =
true;
664 for (
int i = 0; i<nblocks; i++)
666 if (!tr_fes[i]) {
continue; }
667 const SparseMatrix *P_ = tr_fes[i]->GetConformingProlongation();
674 if (!conforming) { ConformingAssemble(0); }
675 const int remove_zeros = 0;
683 FillEssTdofLists(ess_rtdof_list);
686 const int remove_zeros = 0;
690 delete S_e; S_e =
nullptr;
697void BlockStaticCondensation::ConvertMarkerToReducedTrueDofs(
706 int * data = tdof_marker.
GetData();
707 for (
int i = 0; i<nblocks; i++)
709 tdof_marker0.
MakeRef(&data[tdof_offsets[i]],tdof_offsets[i+1]-tdof_offsets[i]);
710 const SparseMatrix * R_ = fes[i]->GetRestrictionMatrix();
713 dof_marker0.
MakeRef(tdof_marker0);
717 dof_marker0.
SetSize(fes[i]->GetVSize());
720 dof_marker.
Append(dof_marker0);
723 int rdofs = rdof_edof.
Size();
724 Array<int> rdof_marker(rdofs);
726 for (
int i = 0; i < rdofs; i++)
728 rdof_marker[i] = dof_marker[rdof_edof[i]];
732 Array<int> rtdof_marker0;
733 Array<int> rdof_marker0;
734 int * rdata = rdof_marker.
GetData();
736 for (
int i = 0; i<nblocks; i++)
738 if (!tr_fes[i]) {
continue; }
739 rdof_marker0.MakeRef(&rdata[rdof_offsets[k]],rdof_offsets[k+1]-rdof_offsets[k]);
740 const SparseMatrix *tr_R = tr_fes[i]->GetRestrictionMatrix();
743 rtdof_marker0.MakeRef(rdof_marker0);
748 tr_R->BooleanMult(rdof_marker0, rtdof_marker0);
750 rtdof_marker.
Append(rtdof_marker0);
755void BlockStaticCondensation::FillEssTdofLists(
const Array<int> &
ess_tdof_list)
761 for (j = 0; j < rblocks; j++)
763 if (rtdof_offsets[j+1] > tdof) {
break; }
765 ess_tdofs[j]->Append(tdof-rtdof_offsets[j]);
775 ConvertMarkerToReducedTrueDofs(tdof_marker, rtdof_marker);
783 MFEM_VERIFY(!parallel,
"EliminateReducedTrueDofs::Wrong Code path");
789 offsets.
MakeRef( (P) ? rtdof_offsets : rdof_offsets);
795 int h = offsets[i+1] - offsets[i];
798 int w = offsets[j+1] - offsets[j];
809 MFEM_ASSERT(
sol.Size() == dof_offsets.
Last(),
"'sol' has incorrect size");
810 const int nrdofs = rdof_offsets.Last();
821 for (
int i = 0; i < nrdofs; i++)
823 sol_r(i) =
sol(rdof_edof[i]);
830 R->
Mult(blsol_r, sc_sol);
836 int copy_interior)
const
864 for (
int j = 0; j<rblocks; j++)
866 if (!ess_tdofs[j]->Size()) {
continue; }
870 for (
int i = 0; i < ess_tdofs[j]->Size(); i++)
872 int tdof = (*ess_tdofs[j])[i];
873 int gdof = tdof + rtdof_offsets[j];
874 B(gdof) = diag(tdof)*X(gdof);
887 const int nrdofs = rdof_offsets.Last();
888 const int nrtdofs = rtdof_offsets.
Last();
889 MFEM_VERIFY(sc_sol.
Size() == nrtdofs,
"'sc_sol' has incorrect size");
901 P->
Mult(sc_sol, sol_r);
908 pP->
Mult(sc_sol, sol_r);
912 if (rdof_offsets.Last() == dof_offsets.
Last())
924 const int NE = mesh->
GetNE();
930 for (
int iel = 0; iel < NE; iel++)
932 lsol.
SetSize(lmat[iel]->Width() + lmat[iel]->Height());
933 GetReducedElementVDofs(iel, trace_vdofs);
939 lsi.
SetSize(lmat[iel]->Height());
940 lmat[iel]->Mult(lsr,lsi);
945 GetReducedElementIndicesAndOffsets(iel,tr_idx, int_idx, idx_offs);
950 GetElementVDofs(iel, vdofs);
951 sol.SetSubVector(vdofs,lsol);
959 delete S_e; S_e =
nullptr;
963 if (P) {
delete P; } P=
nullptr;
964 if (R) {
delete R; } R=
nullptr;
969 delete pS; pS=
nullptr;
970 delete pS_e; pS_e=
nullptr;
971 for (
int i = 0; i<rblocks; i++)
975 delete pP; pP=
nullptr;
979 for (
int i=0; i<lmat.Size(); i++)
981 delete lmat[i]; lmat[i] =
nullptr;
982 delete lvec[i]; lvec[i] =
nullptr;
985 for (
int i = 0; i<tr_fes.Size(); i++)
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.
const int * ess_tdof_list
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)
real_t sol(const Vector &x)