24#ifdef MFEM_DEBUG_HYBRIDIZATION_CP
33 : fes(*fespace), c_fes(*c_fespace)
60#if defined(MFEM_USE_DOUBLE)
61 constexpr real_t mtol = 1e-12;
62#elif defined(MFEM_USE_SINGLE)
63 constexpr real_t mtol = 4e-6;
65#error "Only single and double precision are supported!"
66 constexpr real_t mtol = 1.;
69 int c_num_face_nbr_dofs = 0;
73 HYPRE_BigInt num_shared_slave_faces = 0, glob_num_shared_slave_faces = 0;
81 MPI_Allreduce(&num_shared_slave_faces, &glob_num_shared_slave_faces, 1,
82 HYPRE_MPI_BIG_INT, MPI_SUM, pmesh->
GetComm());
83 MFEM_ASSERT(glob_num_shared_slave_faces%2 == 0,
"");
84 glob_num_shared_slave_faces /= 2;
85 if (glob_num_shared_slave_faces)
91 MFEM_WARNING(
'[' << c_pfes->
GetMyRank() <<
92 "] num_shared_slave_faces = " << num_shared_slave_faces
93 <<
", glob_num_shared_slave_faces = "
94 << glob_num_shared_slave_faces
95 <<
"\n num_face_nbr_dofs = " << c_num_face_nbr_dofs
104 Ct.reset(
new SparseMatrix(num_hat_dofs, c_vsize + c_num_face_nbr_dofs));
108 const int skip_zeros = 1;
113 for (
int i = 0; i < num_faces; i++)
116 if (!FTr) {
continue; }
123 for (
int j = 0; j < s1; j++)
127 for (
int j = 0; j < s2; j++)
129 vdofs[s1+j] = o2 + j;
138 Ct->AddSubMatrix(vdofs, c_vdofs, elmat, skip_zeros);
158 MFEM_ASSERT(bdr_marker.
Size() == bdr_attr_marker.
Size(),
159 "invalid boundary marker for boundary face integrator #"
160 << k <<
", counting from zero");
161 for (
int i = 0; i < bdr_attr_marker.
Size(); i++)
163 bdr_attr_marker[i] |= bdr_marker[i];
170 if (bdr_attr_marker[bdr_attr-1] == 0) {
continue; }
173 if (!FTr) {
continue; }
179 for (
int j = 0; j < s1; j++)
200 Ct->AddSubMatrix(vdofs, c_vdofs, elmat, skip_zeros);
209 for (
int i = 0; i < num_shared_faces; i++)
212 const bool ghost_sface = (face_no >= num_faces);
217 MFEM_ASSERT(FTr->
Elem2No < 0,
"");
223 const int fill2 =
false;
228 for (
int j = 0; j < c_vdofs.
Size(); j++)
230 c_vdofs[j] += c_vsize;
236 for (
int j = 0; j < s1; j++)
241 c_bfi->AssembleFaceMatrix(*face_fe, *fe, *fe, *FTr, elmat);
244 Ct->AddSubMatrix(vdofs, c_vdofs, elmat, skip_zeros);
246 if (glob_num_shared_slave_faces)
249 Ct->Finalize(skip_zeros);
259 for (
int i = 0; i < Ct_J.
Size(); i++)
261 Ct_J[i] = J[i] < c_vsize ?
262 J[i] + c_ldof_offset :
263 c_face_nbr_glob_ldof[J[i] - c_vsize];
279 Ct->Finalize(skip_zeros);
284 MFEM_ABORT(
"TODO: algebraic definition of C");
294 ext->Init(ess_tdof_list);
301 int num_hat_dofs = 0;
304 for (
int i = 0; i < NE; i++)
307 num_hat_dofs += vdofs.
Size();
314#ifdef MFEM_DEBUG_HYBRIDIZATION_CP
317 std::ofstream C_file(
"C_matrix.txt");
325 std::ofstream P_file(
"P_matrix.txt");
343 free_tdof_marker = 1;
344 for (
int i = 0; i < ess_tdof_list.
Size(); i++)
346 free_tdof_marker[ess_tdof_list[i]] = 0;
355 free_vdofs_marker.
MakeRef(free_tdof_marker);
360 cP->
BooleanMult(free_tdof_marker, free_vdofs_marker);
367 P->
BooleanMult(1, free_tdof_marker, 0, free_vdofs_marker);
373 free_vdofs_marker.
MakeRef(free_tdof_marker);
378 cP->
BooleanMult(free_tdof_marker, free_vdofs_marker);
381 for (
int i = 0; i < NE; i++)
385 for (
int j = 0; j < vdofs.
Size(); j++)
399 for (
int i = 0; i < num_hat_dofs; i++)
414#ifdef MFEM_DEBUG_HERE
417 for (
int i = 0; i < NE; i++)
423#ifdef MFEM_DEBUG_HERE
431#ifdef MFEM_DEBUG_HERE
435 int myid = pmesh ? pmesh->GetMyRank() : 0;
438 int e_size = num_hat_dofs - (i_size + b_size);
440 <<
" [" << myid <<
"] hat dofs - \"internal\": " << i_size
441 <<
", \"boundary\": " << b_size
442 <<
", \"essential\": " << e_size <<
'\n' << std::endl;
443#undef MFEM_DEBUG_HERE
455 for (
int i = 0; i < NE; i++)
459 for (
int j = 0; j < vdofs.
Size(); j++)
463 vdof_marker[vdofs[j]] = 1;
467 for (
int tdof = 0; tdof < R->
Height(); tdof++)
469 if (free_tdof_marker[tdof]) {
continue; }
471 const int ncols = R->
RowSize(tdof);
474 for (
int j = 0; j < ncols; j++)
476 if (std::abs(vals[j]) != 0.0 && vdof_marker[cols[j]] == 0)
478 MFEM_ABORT(
"Ref != 0");
497 for (
int i = h_start; i < h_end; i++)
500 if (mark == 0) { i_dofs.
Append(i-h_start); }
501 else if (mark == -1) { b_dofs.
Append(i-h_start); }
513 for (
int i = h_start; i < h_end; i++)
516 if (mark == 0) { num_idofs++; }
517 else if (mark == -1) { b_dofs.
Append(i); }
525 ext->AssembleMatrix(el, A);
541 for (
int j = 0; j < i_dofs.
Size(); j++)
543 int j_dof = i_dofs[j];
544 for (
int i = 0; i < i_dofs.
Size(); i++)
546 A_ii(i,j) = A(i_dofs[i],j_dof);
548 for (
int i = 0; i < b_dofs.
Size(); i++)
550 A_bi(i,j) = A(b_dofs[i],j_dof);
553 for (
int j = 0; j < b_dofs.
Size(); j++)
555 int j_dof = b_dofs[j];
556 for (
int i = 0; i < i_dofs.
Size(); i++)
558 A_ib(i,j) = A(i_dofs[i],j_dof);
560 for (
int i = 0; i < b_dofs.
Size(); i++)
562 A_bb(i,j) = A(b_dofs[i],j_dof);
571 ext->AssembleElementMatrices(el_mats);
575 for (
int e = 0; e < el_mats.
SizeK(); ++e)
585 ext->AssembleBdrMatrix(bdr_el, A);
609 Ordering::DofsToVDofs<Ordering::byNODES>(e2f.
Size()/vdim, vdim, lvdofs);
610 MFEM_ASSERT(lvdofs.
Size() == A.
Height(),
"internal error");
613 for (
int i = 0; i < lvdofs.
Size(); i++)
616 bd = (bd >= 0) ? vdofs[bd] : -1-vdofs[-1-bd];
617 MFEM_ASSERT(bvdofs[i] == bd,
"internal error");
623 for (
int i = 0; i < lvdofs.
Size(); i++)
639 for (
int j = 0; j < i_dofs.
Size(); j++)
641 int j_f = e2f[i_dofs[j]];
642 if (j_f == -1) {
continue; }
643 for (
int i = 0; i < i_dofs.Size(); i++)
645 int i_f = e2f[i_dofs[i]];
646 if (i_f == -1) {
continue; }
647 A_ii(i,j) += B(i_f,j_f);
649 for (
int i = 0; i < b_dofs.
Size(); i++)
651 int i_f = e2f[b_dofs[i]];
652 if (i_f == -1) {
continue; }
653 A_bi(i,j) += B(i_f,j_f);
656 for (
int j = 0; j < b_dofs.
Size(); j++)
658 int j_f = e2f[b_dofs[j]];
659 if (j_f == -1) {
continue; }
660 for (
int i = 0; i < i_dofs.
Size(); i++)
662 int i_f = e2f[i_dofs[i]];
663 if (i_f == -1) {
continue; }
664 A_ib(i,j) += B(i_f,j_f);
666 for (
int i = 0; i < b_dofs.Size(); i++)
668 int i_f = e2f[b_dofs[i]];
669 if (i_f == -1) {
continue; }
670 A_bb(i,j) += B(i_f,j_f);
683 const int skip_zeros = 1;
700 int c_mark_start = 0;
701 for (
int el = 0; el < NE; el++)
707 real_t *A_ib_data = LU_ii.
data + i_dofs_size*i_dofs_size;
708 real_t *A_bi_data = A_ib_data + i_dofs_size*b_dofs.
Size();
710 LU_ii.
ipiv + i_dofs_size);
712 LU_ii.
Factor(i_dofs_size);
714 A_ib_data, A_bi_data, LU_bb.
data);
719 for (
int i = 0; i < b_dofs.
Size(); i++)
721 const int row = b_dofs[i];
722 const int ncols =
Ct->RowSize(row);
723 const int *cols =
Ct->GetRowColumns(row);
724 for (
int j = 0; j < ncols; j++)
726 const int c_dof = cols[j];
727 if (c_dof_marker[c_dof] < c_mark_start)
729 c_dof_marker[c_dof] = c_mark_start + c_dofs.
Size();
736 for (
int i = 0; i < b_dofs.
Size(); i++)
738 const int row = b_dofs[i];
739 const int ncols =
Ct->RowSize(row);
740 const int *cols =
Ct->GetRowColumns(row);
741 const real_t *vals =
Ct->GetRowEntries(row);
742 for (
int j = 0; j < ncols; j++)
744 const int loc_j = c_dof_marker[cols[j]] - c_mark_start;
745 Cb_t(i,loc_j) = vals[j];
757 MultAtB(Cb_t, Sb_inv_Cb_t, Hb);
760 H->AddSubMatrix(c_dofs, c_dofs, Hb, skip_zeros);
765 V->
AddSubMatrix(b_dofs, c_dofs, Sb_inv_Cb_t, skip_zeros);
769 c_mark_start += c_dofs.
Size();
770 MFEM_VERIFY(c_mark_start >= 0,
"overflow");
772 const bool fix_empty_rows =
true;
774 H->Finalize(skip_zeros, fix_empty_rows);
779 H->Finalize(skip_zeros, fix_empty_rows);
780 if (!c_pfes) {
return; }
795 MFEM_ASSERT(c_pfes,
"");
800 for (
int i = 0; i < V_J.
Size(); i++)
802 V_J[i] = J[i] < c_vsize ?
803 J[i] + c_ldof_offset :
804 c_face_nbr_glob_ldof[J[i] - c_vsize];
810 pC->GetGlobalNumCols(),
pC->GetGlobalNumRows(),
812 pC->ColPart(),
pC->RowPart());
821 pP.ConvertFrom(
P_pc.get());
857 Vector el_vals, bf_i, i_vals, b_vals;
866 Ct->Mult(lambda, bf);
872 pC ?
pC->MultTranspose(L, bf) :
Ct->Mult(L, bf);
875 Ct->Mult(lambda, bf);
881 for (
int i = 0; i < NE; i++)
885 for (
int j = 0; j < vdofs.
Size(); j++)
888 if (vdof < 0) { vdof = -1 - vdof; }
889 if (vdof_marker[vdof]) { el_vals(j) = 0.0; }
890 else { vdof_marker[vdof] =
true; }
903 LUFactors LU_ii(Af_data_ptr, Af_ipiv_ptr);
926 ext->ReduceRHS(
b, b_r);
940 Ct->MultTranspose(bf, b_r);
951 Ct->MultTranspose(bf, bl);
958 Ct->MultTranspose(bf, b_r);
967 ext->ComputeSolution(
b, sol_r, sol);
990 for (
int i = 0; i < NE; i++)
997 if (vdof >= 0) { s(vdof) = bf(j); }
998 else { s(-1-vdof) = -bf(j); }
1013 if (
ext) {
ext->Reset(); }
T Max() const
Find the maximal element in the array, using the comparison operator < for class T.
void Reserve(int capacity)
Ensures that the allocated size is at least the given size.
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 MakeRef(T *data_, int size_, bool own_data=false)
Make this Array a reference to a pointer.
void DeleteAll()
Delete the whole array.
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.
Data type dense matrix using column-major storage.
void Threshold(real_t eps)
Replace small entries, abs(a_ij) <= eps, with zero.
real_t * Data() const
Returns the matrix data array.
void SetSize(int s)
Change the size of the DenseMatrix to s x s.
void AdjustDofDirection(Array< int > &dofs)
real_t MaxMaxNorm() const
Compute the norm ||A|| = max_{ij} |A_{ij}|.
Rank 3 tensor (array of matrices)
void SubDofOrder(Geometry::Type Geom, int SDim, int Info, Array< int > &dofs) const
Get the local dofs for a given sub-manifold.
Class FiniteElementSpace - responsible for providing FEM view of the mesh, mainly managing the set of...
virtual const SparseMatrix * GetRestrictionMatrix() const
The returned SparseMatrix is owned by the FiniteElementSpace.
static void AdjustVDofs(Array< int > &vdofs)
Remove the orientation information encoded into an array of dofs Some basis function types have a rel...
int GetNBE() const
Returns number of boundary elements in the mesh.
DofTransformation * GetElementVDofs(int i, Array< int > &vdofs) const
Returns indices of degrees of freedom for the i'th element. The returned indices are offsets into an ...
virtual const FiniteElement * GetFE(int i) const
Returns pointer to the FiniteElement in the FiniteElementCollection associated with i'th element in t...
int GetNE() const
Returns number of elements in the mesh.
int GetConformingVSize() const
void GetFaceVDofs(int i, Array< int > &vdofs) const
Returns the indices of the degrees of freedom for the specified face, including the DOFs for the edge...
const FiniteElement * GetFaceElement(int i) const
Returns pointer to the FiniteElement in the FiniteElementCollection associated with i'th face in the ...
const SparseMatrix * GetConformingProlongation() const
const FiniteElementCollection * FEColl() const
Mesh * GetMesh() const
Returns the mesh.
int GetVSize() const
Return the number of vector dofs, i.e. GetNDofs() x GetVDim().
int GetVDim() const
Returns the vector dimension of the finite element space.
DofTransformation * GetBdrElementVDofs(int i, Array< int > &vdofs) const
Returns indices of degrees of freedom for i'th boundary element. The returned indices are offsets int...
Abstract class for all finite elements.
Class for grid function - Vector with associated FE space.
virtual void MakeRef(FiniteElementSpace *f, real_t *v)
Make the GridFunction reference external data on a new FiniteElementSpace.
virtual void SetSpace(FiniteElementSpace *f)
Associate a new FiniteElementSpace with the GridFunction.
void Reset()
Destroy the current hybridization matrix while preserving the computed constraint matrix and the set ...
void AssembleElementMatrices(const class DenseTensor &el_mats)
Assemble all of the element matrices given in the form of a DenseTensor.
~Hybridization()
Destructor.
void Init(const Array< int > &ess_tdof_list)
Prepare the Hybridization object for assembly.
std::unique_ptr< HypreParMatrix > pC
void EnableDeviceExecution()
Turns on device execution.
FiniteElementSpace & c_fes
std::vector< BilinearFormIntegrator * > boundary_constraint_integs
The constraint boundary face integrators.
void AssembleBdrMatrix(int bdr_el, const DenseMatrix &A)
Assemble the boundary element matrix A into the hybridized system matrix.
friend class HybridizationExtension
bool extern_bdr_constr_integs
Indicates if the boundary_constraint_integs integrators are owned externally.
std::unique_ptr< SparseMatrix > Ct
The constraint matrix.
void AssembleMatrix(int el, const DenseMatrix &A)
Assemble the element matrix A into the hybridized system matrix.
void MultAfInv(const Vector &b, const Vector &lambda, Vector &bf, int mode) const
std::unique_ptr< HypreParMatrix > P_pc
std::unique_ptr< SparseMatrix > H
The Schur complement system for the Lagrange multiplier.
void GetIBDofs(int el, Array< int > &i_dofs, Array< int > &b_dofs) const
Returns the local indices of the i-dofs and b-dofs of element el.
void ComputeH()
Construct the Schur complement system.
std::unique_ptr< class HybridizationExtension > ext
Extension for device execution.
Array< int > hat_dofs_marker
void ComputeSolution(const Vector &b, const Vector &sol_r, Vector &sol) const
Reconstruct the solution of the original system sol from solution of the hybridized system sol_r and ...
Array< int > Af_f_offsets
FiniteElementSpace & fes
The finite element space.
void Finalize()
Finalize the construction of the hybridized matrix.
Hybridization(FiniteElementSpace *fespace, FiniteElementSpace *c_fespace)
Constructor.
std::vector< Array< int > * > boundary_constraint_integs_marker
Boundary markers for constraint face integrators.
void GetBDofs(int el, int &num_idofs, Array< int > &b_dofs) const
Returns global indices of the b-dofs of element el.
void ConstructC()
Construct the constraint matrix.
std::unique_ptr< BilinearFormIntegrator > c_bfi
The constraint integrator.
void ReduceRHS(const Vector &b, Vector &b_r) const
Perform the reduction of the given right-hand side b to a right-hand side vector b_r for the hybridiz...
Wrapper for hypre's ParCSR matrix class.
void BooleanMult(int alpha, const int *x, int beta, int *y)
The "Boolean" analog of y = alpha * A * x + beta * y, where elements in the sparsity pattern of the m...
HypreParMatrix * Transpose() const
Returns the transpose of *this.
bool Factor(int m, real_t TOL=0.0) override
Compute the LU factorization of the current matrix.
void BlockFactor(int m, int n, real_t *A12, real_t *A21, real_t *A22) const
void BlockForwSolve(int m, int n, int r, const real_t *L21, real_t *B1, real_t *B2) const
void Solve(int m, int n, real_t *X) const override
void BlockBackSolve(int m, int n, int r, const real_t *U12, const real_t *X2, real_t *Y1) const
Array< int > bdr_attributes
A list of all unique boundary attributes used by the Mesh.
int GetNumFaces() const
Return the number of faces (3D), edges (2D) or vertices (1D).
bool Nonconforming() const
Return a bool indicating whether this mesh is nonconforming.
int GetBdrAttribute(int i) const
Return the attribute of boundary element i.
int GetBdrElementFaceIndex(int be_idx) const
Return the local face (codimension-1) index for the given boundary element index.
int GetNE() const
Returns number of elements.
int Dimension() const
Dimension of the reference space used within the elements.
FaceElementTransformations * GetBdrFaceTransformations(int BdrElemNo)
Builds the transformation defining the given boundary face.
void GetBdrElementAdjacentElement(int bdr_el, int &el, int &info) const
For the given boundary element, bdr_el, return its adjacent element and its info, i....
FaceElementTransformations * GetInteriorFaceTransformations(int FaceNo)
See GetFaceElementTransformations().
Geometry::Type GetElementBaseGeometry(int i) const
Pointer to an Operator of a specified type.
void ConvertFrom(OperatorHandle &A)
Convert the given OperatorHandle A to the currently set type id.
void SetType(Operator::Type tid)
Invoke Clear() and set a new type id.
void MakePtAP(OperatorHandle &A, OperatorHandle &P)
Reset the OperatorHandle to hold the product P^t A P.
void MakeSquareBlockDiag(MPI_Comm comm, HYPRE_BigInt glob_size, HYPRE_BigInt *row_starts, SparseMatrix *diag)
Reset the OperatorHandle to hold a parallel square block-diagonal matrix using the currently set type...
Operator * Ptr() const
Access the underlying Operator pointer.
void Clear()
Clear the OperatorHandle, deleting the held Operator (if owned), while leaving the type id unchanged.
Operator::Type Type() const
Get the currently set operator type id.
int Height() const
Get the height (size of output) of the Operator. Synonym with NumRows().
int Width() const
Get the width (size of input) of the Operator. Synonym with NumCols().
@ PETSC_MATIS
ID for class PetscParMatrix, MATIS format.
@ Hypre_ParCSR
ID for class HypreParMatrix.
Abstract parallel finite element space.
HYPRE_BigInt GlobalVSize() const
void ExchangeFaceNbrData()
HYPRE_BigInt GetMyDofOffset() const
HYPRE_BigInt * GetDofOffsets() const
void GetFaceNbrFaceVDofs(int i, Array< int > &vdofs) const
const Operator * GetProlongationMatrix() const override
HypreParMatrix * Dof_TrueDof_Matrix() const
The true dof-to-dof interpolation matrix.
const HYPRE_BigInt * GetFaceNbrGlobalDofMap()
int GetFaceNbrVSize() const
ParMesh * GetParMesh() const
HypreParMatrix * GetPartialConformingInterpolation()
For a non-conforming mesh, construct and return the interpolation matrix from the partially conformin...
int TrueVSize() const
Obsolete, kept for backward compatibility.
const FiniteElement * GetFaceNbrFaceFE(int i) const
Class for parallel meshes.
int GetNSharedFaces() const
Return the number of shared faces (3D), edges (2D), vertices (1D)
FaceElementTransformations * GetFaceElementTransformations(int FaceNo, int mask=31) override
int GetSharedFace(int sface) const
Return the local face index for the given shared face.
void GenerateOffsets(int N, HYPRE_BigInt loc_sizes[], Array< HYPRE_BigInt > *offsets[]) const
FaceElementTransformations * GetSharedFaceTransformations(int sf, bool fill2=true)
Get the FaceElementTransformations for the given shared face (edge 2D) using the shared face index sf...
const NCList & GetSharedList(int entity)
Helper to get shared vertices/edges/faces ('entity' == 0/1/2 resp.).
void MultTranspose(const Vector &x, Vector &y) const override
Multiply a vector with the transposed matrix. y = At * x.
int NumNonZeroElems() const override
Returns the number of the nonzero elements in the matrix.
void PrintMatlab(std::ostream &out=mfem::out) const override
Prints matrix in matlab format.
void AddSubMatrix(const Array< int > &rows, const Array< int > &cols, const DenseMatrix &subm, int skip_zeros=1)
void BooleanMult(const Array< int > &x, Array< int > &y) const
y = A * x, treating all entries as booleans (zero=false, nonzero=true).
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 Vector &x, Vector &y) const override
Matrix vector multiplication.
real_t * GetRowEntries(const int row)
Return a pointer to the entries in a row.
real_t * GetData()
Return the element data, i.e. the array A.
void Finalize(int skip_zeros=1) override
Finalize the matrix initialization, switching the storage format from LIL to CSR.
int * GetJ()
Return the array J.
int * GetI()
Return the array I.
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.
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 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)
OutStream out(std::cout)
Global stream used by the library for standard output. Initially it uses the same std::streambuf as s...
void Transpose(const Table &A, Table &At, int ncols_A_)
Transpose a Table.
HypreParMatrix * ParMult(const HypreParMatrix *A, const HypreParMatrix *B, bool own_matrix)
ComplexDenseMatrix * MultAtB(const ComplexDenseMatrix &A, const ComplexDenseMatrix &B)
Multiply the complex conjugate transpose of a matrix A with a matrix B. A^H*B.
Lists all edges/faces in the nonconforming mesh.
Array< Slave > slaves
All MeshIds corresponding to slave faces.