MFEM  v3.1
Finite element discretization library
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Pages
pbilinearform.cpp
Go to the documentation of this file.
1 // Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
2 // the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
3 // reserved. See file COPYRIGHT for details.
4 //
5 // This file is part of the MFEM library. For more information and source code
6 // availability see http://mfem.org.
7 //
8 // MFEM is free software; you can redistribute it and/or modify it under the
9 // terms of the GNU Lesser General Public License (as published by the Free
10 // Software Foundation) version 2.1 dated February 1999.
11 
12 #include "../config/config.hpp"
13 
14 #ifdef MFEM_USE_MPI
15 
16 #include "fem.hpp"
17 #include "../general/sort_pairs.hpp"
18 
19 namespace mfem
20 {
21 
23 {
24  int nbr_size = pfes->GetFaceNbrVSize();
25 
26  if (precompute_sparsity == 0 || fes->GetVDim() > 1)
27  {
28  if (keep_nbr_block)
29  {
30  mat = new SparseMatrix(height + nbr_size, width + nbr_size);
31  }
32  else
33  {
34  mat = new SparseMatrix(height, width + nbr_size);
35  }
36  return;
37  }
38 
39  // the sparsity pattern is defined from the map: face->element->dof
41  const Table &lelem_ldof = fes->GetElementToDofTable(); // <-- dofs
42  const Table &nelem_ndof = pfes->face_nbr_element_dof; // <-- vdofs
43  Table elem_dof; // element + nbr-element <---> dof
44  if (nbr_size > 0)
45  {
46  // merge lelem_ldof and nelem_ndof into elem_dof
47  int s1 = lelem_ldof.Size(), s2 = nelem_ndof.Size();
48  const int *I1 = lelem_ldof.GetI(), *J1 = lelem_ldof.GetJ();
49  const int *I2 = nelem_ndof.GetI(), *J2 = nelem_ndof.GetJ();
50  const int nnz1 = I1[s1], nnz2 = I2[s2];
51 
52  elem_dof.SetDims(s1 + s2, nnz1 + nnz2);
53 
54  int *I = elem_dof.GetI(), *J = elem_dof.GetJ();
55  for (int i = 0; i <= s1; i++)
56  {
57  I[i] = I1[i];
58  }
59  for (int j = 0; j < nnz1; j++)
60  {
61  J[j] = J1[j];
62  }
63  for (int i = 0; i <= s2; i++)
64  {
65  I[s1+i] = I2[i] + nnz1;
66  }
67  for (int j = 0; j < nnz2; j++)
68  {
69  J[nnz1+j] = J2[j] + height;
70  }
71  }
72  // dof_elem x elem_face x face_elem x elem_dof (keep_nbr_block = true)
73  // ldof_lelem x lelem_face x face_elem x elem_dof (keep_nbr_block = false)
74  Table dof_dof;
75  {
76  Table face_dof; // face_elem x elem_dof
77  {
78  Table *face_elem = pfes->GetParMesh()->GetFaceToAllElementTable();
79  if (nbr_size > 0)
80  {
81  mfem::Mult(*face_elem, elem_dof, face_dof);
82  }
83  else
84  {
85  mfem::Mult(*face_elem, lelem_ldof, face_dof);
86  }
87  delete face_elem;
88  if (nbr_size > 0)
89  {
90  elem_dof.Clear();
91  }
92  }
93 
94  if (keep_nbr_block)
95  {
96  Table dof_face;
97  Transpose(face_dof, dof_face, height + nbr_size);
98  mfem::Mult(dof_face, face_dof, dof_dof);
99  }
100  else
101  {
102  Table ldof_face;
103  {
104  Table face_ldof;
105  Table *face_lelem = fes->GetMesh()->GetFaceToElementTable();
106  mfem::Mult(*face_lelem, lelem_ldof, face_ldof);
107  delete face_lelem;
108  Transpose(face_ldof, ldof_face, height);
109  }
110  mfem::Mult(ldof_face, face_dof, dof_dof);
111  }
112  }
113 
114  int *I = dof_dof.GetI();
115  int *J = dof_dof.GetJ();
116  int nrows = dof_dof.Size();
117  double *data = new double[I[nrows]];
118 
119  mat = new SparseMatrix(I, J, data, nrows, height + nbr_size);
120  *mat = 0.0;
121 
122  dof_dof.LoseData();
123 }
124 
126 {
127  if (m == NULL) { return NULL; }
128 
129  MFEM_VERIFY(m->Finalized(), "local matrix needs to be finalized for "
130  "ParallelAssemble");
131 
132  HypreParMatrix *A;
133  if (fbfi.Size() == 0)
134  {
135  // construct a parallel block-diagonal wrapper matrix A based on m
136  A = new HypreParMatrix(pfes->GetComm(),
137  pfes->GlobalVSize(), pfes->GetDofOffsets(), m);
138  }
139  else
140  {
141  // handle the case when 'm' contains offdiagonal
142  int lvsize = pfes->GetVSize();
143  const HYPRE_Int *face_nbr_glob_ldof = pfes->GetFaceNbrGlobalDofMap();
144  HYPRE_Int ldof_offset = pfes->GetMyDofOffset();
145 
146  Array<HYPRE_Int> glob_J(m->NumNonZeroElems());
147  int *J = m->GetJ();
148  for (int i = 0; i < glob_J.Size(); i++)
149  if (J[i] < lvsize)
150  {
151  glob_J[i] = J[i] + ldof_offset;
152  }
153  else
154  {
155  glob_J[i] = face_nbr_glob_ldof[J[i] - lvsize];
156  }
157 
158  A = new HypreParMatrix(pfes->GetComm(), lvsize, pfes->GlobalVSize(),
159  pfes->GlobalVSize(), m->GetI(), glob_J,
160  m->GetData(), pfes->GetDofOffsets(),
161  pfes->GetDofOffsets());
162  }
163 
165 
166  delete A;
167 
168  return rap;
169 }
170 
172 {
173  ParMesh *pmesh = pfes->GetParMesh();
175  Array<int> vdofs1, vdofs2, vdofs_all;
177 
178  int nfaces = pmesh->GetNSharedFaces();
179  for (int i = 0; i < nfaces; i++)
180  {
181  T = pmesh->GetSharedFaceTransformations(i);
182  pfes->GetElementVDofs(T->Elem1No, vdofs1);
183  pfes->GetFaceNbrElementVDofs(T->Elem2No, vdofs2);
184  vdofs1.Copy(vdofs_all);
185  for (int j = 0; j < vdofs2.Size(); j++)
186  {
187  vdofs2[j] += height;
188  }
189  vdofs_all.Append(vdofs2);
190  for (int k = 0; k < fbfi.Size(); k++)
191  {
192  fbfi[k]->AssembleFaceMatrix(*pfes->GetFE(T->Elem1No),
193  *pfes->GetFaceNbrFE(T->Elem2No),
194  *T, elemmat);
195  if (keep_nbr_block)
196  {
197  mat->AddSubMatrix(vdofs_all, vdofs_all, elemmat, skip_zeros);
198  }
199  else
200  {
201  mat->AddSubMatrix(vdofs1, vdofs_all, elemmat, skip_zeros);
202  }
203  }
204  }
205 }
206 
207 void ParBilinearForm::Assemble(int skip_zeros)
208 {
209  if (mat == NULL && fbfi.Size() > 0)
210  {
212  pAllocMat();
213  }
214 
215  BilinearForm::Assemble(skip_zeros);
216 
217  if (fbfi.Size() > 0)
218  {
219  AssembleSharedFaces(skip_zeros);
220  }
221 }
222 
223 void ParBilinearForm
225  HypreParMatrix &A, const HypreParVector &X,
226  HypreParVector &B) const
227 {
228  Array<int> dof_list;
229 
230  pfes->GetEssentialTrueDofs(bdr_attr_is_ess, dof_list);
231 
232  // do the parallel elimination
233  A.EliminateRowsCols(dof_list, X, B);
234 }
235 
238  HypreParMatrix &A) const
239 {
240  Array<int> dof_list;
241 
242  pfes->GetEssentialTrueDofs(bdr_attr_is_ess, dof_list);
243 
244  return A.EliminateRowsCols(dof_list);
245 }
246 
247 void ParBilinearForm::TrueAddMult(const Vector &x, Vector &y, const double a)
248 const
249 {
250  MFEM_VERIFY(fbfi.Size() == 0, "the case of interior face integrators is not"
251  " implemented");
252 
253  if (X.ParFESpace() != pfes)
254  {
255  X.Update(pfes);
256  Y.Update(pfes);
257  }
258 
259  X.Distribute(&x);
260  mat->Mult(X, Y);
261  pfes->Dof_TrueDof_Matrix()->MultTranspose(a, Y, 1.0, y);
262 }
263 
265  Array<int> &ess_tdof_list, Vector &x, Vector &b,
266  HypreParMatrix &A, Vector &X, Vector &B, int copy_interior)
267 {
269  const SparseMatrix &R = *pfes->GetRestrictionMatrix();
270  Array<int> ess_rtdof_list;
271 
272  // Finish the matrix assembly and perform BC elimination, storing the
273  // eliminated part of the matrix.
274  if (static_cond)
275  {
276  static_cond->ConvertListToReducedTrueDofs(ess_tdof_list, ess_rtdof_list);
278  {
280  static_cond->EliminateReducedTrueDofs(ess_rtdof_list, 0);
281  }
282  }
283  else if (mat)
284  {
285  Finalize();
287  delete mat;
288  mat = NULL;
289  delete mat_e;
290  mat_e = NULL;
291  p_mat_e = p_mat->EliminateRowsCols(ess_tdof_list);
292  }
293 
294  // Transform the system and perform the elimination in B, based on the
295  // essential BC values from x. Restrict the BC part of x in X, and set the
296  // non-BC part to zero. Since there is no good initial guess for the Lagrange
297  // multipliers, set X = 0.0 for hybridization.
298  if (static_cond)
299  {
300  // Schur complement reduction to the exposed dofs
301  static_cond->ReduceRHS(b, B);
305  ess_rtdof_list, X, B);
306  if (!copy_interior) { X.SetSubVectorComplement(ess_rtdof_list, 0.0); }
308  }
309  else if (hybridization)
310  {
311  // Reduction to the Lagrange multipliers system
312  HypreParVector true_X(pfes), true_B(pfes);
313  P.MultTranspose(b, true_B);
314  R.Mult(x, true_X);
315  EliminateBC(*p_mat, *p_mat_e, ess_tdof_list, true_X, true_B);
316  R.MultTranspose(true_B, b);
317  hybridization->ReduceRHS(true_B, B);
318  X.SetSize(B.Size());
319  X = 0.0;
321  }
322  else
323  {
324  // Variational restriction with P
325  X.SetSize(pfes->TrueVSize());
326  B.SetSize(X.Size());
327  P.MultTranspose(b, B);
328  R.Mult(x, X);
329  EliminateBC(*p_mat, *p_mat_e, ess_tdof_list, X, B);
330  if (!copy_interior) { X.SetSubVectorComplement(ess_tdof_list, 0.0); }
331  A.MakeRef(*p_mat);
332  }
333 }
334 
336  const Vector &X, const Vector &b, Vector &x)
337 {
339 
340  if (static_cond)
341  {
342  // Private dofs back solve
343  static_cond->ComputeSolution(b, X, x);
344  }
345  else if (hybridization)
346  {
347  // Primal unknowns recovery
348  HypreParVector true_X(pfes), true_B(pfes);
349  P.MultTranspose(b, true_B);
350  const SparseMatrix &R = *pfes->GetRestrictionMatrix();
351  R.Mult(x, true_X); // get essential b.c. from x
352  hybridization->ComputeSolution(true_B, X, true_X);
353  x.SetSize(P.Height());
354  P.Mult(true_X, x);
355  }
356  else
357  {
358  // Apply conforming prolongation
359  x.SetSize(P.Height());
360  P.Mult(X, x);
361  }
362 }
363 
365 {
366  BilinearForm::Update(nfes);
367 
368  if (nfes)
369  {
370  pfes = dynamic_cast<ParFiniteElementSpace *>(nfes);
371  MFEM_VERIFY(pfes != NULL, "nfes must be a ParFiniteElementSpace!");
372  }
373 
374  delete p_mat;
375  delete p_mat_e;
376  p_mat = p_mat_e = NULL;
377 }
378 
379 
381 {
382  MFEM_ASSERT(mat, "matrix is not assembled");
383  MFEM_ASSERT(mat->Finalized(), "matrix is not finalized");
387  delete RA;
388  return RAP;
389 }
390 
392 const
393 {
394  MFEM_VERIFY(mat->Finalized(), "local matrix needs to be finalized for "
395  "GetParBlocks");
396 
398 
399  blocks.SetSize(range_fes->GetVDim(), domain_fes->GetVDim());
400 
401  RLP->GetBlocks(blocks,
404 
405  delete RLP;
406 }
407 
409 {
410  // construct the block-diagonal matrix A
411  HypreParMatrix *A =
417  mat);
418 
421 
422  delete A;
423 
424  return rap;
425 }
426 
429  const double a) const
430 {
431  if (X.ParFESpace() != trial_pfes)
432  {
434  Y.Update(test_pfes);
435  }
436 
437  X.Distribute(&x);
438  mat->Mult(X, Y);
440 }
441 
442 }
443 
444 #endif
HypreParMatrix * p_mat_e
int Size() const
Logical size of the array.
Definition: array.hpp:109
void EliminateRowsCols(const Array< int > &rows_cols, const HypreParVector &X, HypreParVector &B)
Definition: hypre.cpp:1213
int GetVSize() const
Definition: fespace.hpp:164
virtual int NumNonZeroElems() const
Returns the number of the nonzero elements in the matrix.
Definition: sparsemat.cpp:879
int * GetJ()
Definition: table.hpp:108
Array< BilinearFormIntegrator * > fbfi
Set of interior face Integrators to be applied.
void Assemble(int skip_zeros=1)
Assembles the form i.e. sums over all domain/bdr integrators.
void ReduceRHS(const Vector &b, Vector &sc_b) const
Definition: staticcond.cpp:309
void MakeRef(const HypreParMatrix &master)
Make this HypreParMatrix a reference to &#39;master&#39;.
Definition: hypre.cpp:726
HypreParMatrix * LeftDiagMult(const SparseMatrix &D, HYPRE_Int *row_starts=NULL) const
Definition: hypre.cpp:969
void SetSize(int s)
Resizes the vector if the new size is different.
Definition: vector.hpp:259
HYPRE_Int MultTranspose(HypreParVector &x, HypreParVector &y, double alpha=1.0, double beta=0.0)
Computes y = alpha * A^t * x + beta * y.
Definition: hypre.cpp:963
void GetElementVDofs(int i, Array< int > &vdofs) const
Returns indexes of degrees of freedom in array dofs for i&#39;th element.
Definition: fespace.cpp:161
void Mult(const Table &A, const Table &B, Table &C)
C = A * B (as boolean matrices)
Definition: table.cpp:445
HypreParMatrix & GetParallelMatrix()
Return the parallel hybridized matrix.
int GetNSharedFaces() const
Return the number of shared faces (3D), edges (2D), vertices (1D)
Definition: pmesh.cpp:1409
void SetDims(int rows, int nnz)
Definition: table.cpp:132
void Copy(Array &copy) const
Create a copy of the current array.
Definition: array.hpp:160
HYPRE_Int * GetDofOffsets()
Definition: pfespace.hpp:151
Data type dense matrix using column-major storage.
Definition: densemat.hpp:22
int Size() const
Returns the size of the vector.
Definition: vector.hpp:84
void TrueAddMult(const Vector &x, Vector &y, const double a=1.0) const
Compute y += a (P^t A P) x, where x and y are vectors on the true dofs.
void LoseData()
Call this if data has been stolen.
Definition: table.hpp:138
Abstract parallel finite element space.
Definition: pfespace.hpp:28
virtual const SparseMatrix * GetRestrictionMatrix()
Get the R matrix which restricts a local dof vector to true dof vector.
Definition: pfespace.hpp:215
void AssembleSharedFaces(int skip_zeros=1)
ParFiniteElementSpace * ParFESpace()
Definition: pgridfunc.hpp:61
void ComputeSolution(const Vector &b, const Vector &sc_sol, Vector &sol) const
Definition: staticcond.cpp:452
const HYPRE_Int * GetFaceNbrGlobalDofMap()
Definition: pfespace.hpp:223
HYPRE_Int Mult(HypreParVector &x, HypreParVector &y, double alpha=1.0, double beta=0.0)
Computes y = alpha * A * x + beta * y.
Definition: hypre.cpp:903
HYPRE_Int GetMyDofOffset() const
Definition: pfespace.cpp:637
HypreParMatrix * ParallelAssemble()
Returns the matrix assembled on the true dofs, i.e. P^t A P.
virtual void Update(FiniteElementSpace *nfes=NULL)
HYPRE_Int * GetTrueDofOffsets()
Definition: pfespace.hpp:152
HypreParMatrix * p_mat
void EliminateBC(HypreParMatrix &A, HypreParMatrix &Ae, const Array< int > &ess_dof_list, const Vector &X, Vector &B)
Definition: hypre.cpp:1368
HypreParMatrix * ParallelAssemble()
Returns the matrix assembled on the true dofs, i.e. P^t A P.
void GetFaceNbrElementVDofs(int i, Array< int > &vdofs) const
Definition: pfespace.cpp:867
void SetSize(int m, int n)
Definition: array.hpp:256
ParFiniteElementSpace * pfes
const FiniteElement * GetFaceNbrFE(int i) const
Definition: pfespace.cpp:873
Data type sparse matrix.
Definition: sparsemat.hpp:38
int Height() const
Get the height (size of output) of the Operator. Synonym with NumRows.
Definition: operator.hpp:35
StaticCondensation * static_cond
int Append(const T &el)
Append element to array, resize if necessary.
Definition: array.hpp:368
Mesh * GetMesh() const
Returns the mesh.
Definition: fespace.hpp:140
void Clear()
Definition: table.cpp:340
SparseMatrix * mat
Sparse matrix to be associated with the form.
void ComputeSolution(const Vector &b, const Vector &sol_r, Vector &sol) const
HypreParMatrix * RAP(HypreParMatrix *A, HypreParMatrix *P)
Returns the matrix P^t * A * P.
Definition: hypre.cpp:1318
HypreParMatrix & GetParallelMatrix()
Return the parallel Schur complement matrix.
Definition: staticcond.hpp:148
void Assemble(int skip_zeros=1)
Assemble the local matrix.
void Transpose(const Table &A, Table &At, int _ncols_A)
Transpose a Table.
Definition: table.cpp:385
virtual void Update(FiniteElementSpace *nfes=NULL)
ParFiniteElementSpace * test_pfes
int Size() const
Returns the number of TYPE I elements.
Definition: table.hpp:86
int GetVDim() const
Returns vector dimension.
Definition: fespace.hpp:154
double * GetData() const
Return element data.
Definition: sparsemat.hpp:116
void AddSubMatrix(const Array< int > &rows, const Array< int > &cols, const DenseMatrix &subm, int skip_zeros=1)
Definition: sparsemat.cpp:1733
int * GetI() const
Return the array I.
Definition: sparsemat.hpp:112
void SetSubVectorComplement(const Array< int > &dofs, const double val)
Set all vector entries NOT in the &#39;dofs&#39; array to the given &#39;val&#39;.
Definition: vector.cpp:575
HypreParMatrix * Dof_TrueDof_Matrix()
The true dof-to-dof interpolation matrix.
Definition: pfespace.cpp:411
bool Finalized() const
Definition: sparsemat.hpp:256
int GetOrdering() const
Return the ordering method.
Definition: fespace.hpp:176
HypreParMatrix * ParallelAssemble() const
Returns the matrix &quot;assembled&quot; on the true dofs.
SparseMatrix * mat_e
Wrapper for hypre&#39;s parallel vector class.
Definition: hypre.hpp:58
ParFiniteElementSpace * domain_fes
Abstract finite element space.
Definition: fespace.hpp:62
virtual void Mult(const Vector &x, Vector &y) const
Matrix vector multiplication.
Definition: sparsemat.cpp:417
virtual void GetEssentialTrueDofs(const Array< int > &bdr_attr_is_ess, Array< int > &ess_tdof_list)
Definition: pfespace.cpp:545
void Finalize()
Finalize the construction of the Schur complement matrix.
Definition: staticcond.cpp:235
void Distribute(const Vector *tv)
Definition: pgridfunc.cpp:79
void EliminateReducedTrueDofs(const Array< int > &ess_rtdof_list, int keep_diagonal)
Eliminate the given reduced true dofs from the Schur complement matrix S.
Definition: staticcond.cpp:286
void RecoverFEMSolution(const Vector &X, const Vector &b, Vector &x)
HypreParMatrix & GetParallelMatrixElim()
Return the eliminated part of the parallel Schur complement matrix.
Definition: staticcond.hpp:151
Table * GetFaceToElementTable() const
Definition: mesh.cpp:4247
virtual void Finalize(int skip_zeros=1)
Finalizes the matrix initialization.
ParFiniteElementSpace * range_fes
bool HasEliminatedBC() const
Definition: staticcond.hpp:131
void FormLinearSystem(Array< int > &ess_tdof_list, Vector &x, Vector &b, HypreParMatrix &A, Vector &X, Vector &B, int copy_interior=0)
void MultTranspose(const Vector &x, Vector &y) const
Multiply a vector with the transposed matrix. y = At * x.
Definition: sparsemat.cpp:492
FiniteElementSpace * fes
FE space on which the form lives.
void ParallelEliminateEssentialBC(const Array< int > &bdr_attr_is_ess, HypreParMatrix &A, const HypreParVector &X, HypreParVector &B) const
const FiniteElement * GetFE(int i) const
Returns pointer to the FiniteElement associated with i&#39;th element.
Definition: fespace.cpp:1199
DenseMatrix elemmat
ParFiniteElementSpace * trial_pfes
int GetFaceNbrVSize() const
Definition: pfespace.hpp:220
Vector data type.
Definition: vector.hpp:33
void GetParBlocks(Array2D< HypreParMatrix * > &blocks) const
Hybridization * hybridization
void ReduceRHS(const Vector &b, Vector &b_r) const
int * GetI()
Definition: table.hpp:107
const Table & GetElementToDofTable() const
Definition: fespace.hpp:278
void ReduceSolution(const Vector &sol, Vector &sc_sol) const
Definition: staticcond.cpp:388
Table * GetFaceToAllElementTable() const
Definition: pmesh.cpp:1303
FaceElementTransformations * GetSharedFaceTransformations(int)
Definition: pmesh.cpp:1361
Wrapper for hypre&#39;s ParCSR matrix class.
Definition: hypre.hpp:143
void TrueAddMult(const Vector &x, Vector &y, const double a=1.0) const
Compute y += a (P^t A P) x, where x and y are vectors on the true dofs.
int * GetJ() const
Return the array J.
Definition: sparsemat.hpp:114
Class for parallel meshes.
Definition: pmesh.hpp:28
void ConvertListToReducedTrueDofs(const Array< int > &ess_tdof_list, Array< int > &ess_rtdof_list) const
Definition: staticcond.hpp:169