MFEM  v3.2
Finite element discretization library
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Pages
bilinearform.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 // Implementation of class BilinearForm
13 
14 #include "fem.hpp"
15 #include <cmath>
16 
17 namespace mfem
18 {
19 
21 {
22  if (static_cond) { return; }
23 
24  if (precompute_sparsity == 0 || fes->GetVDim() > 1)
25  {
26  mat = new SparseMatrix(height);
27  return;
28  }
29 
30  const Table &elem_dof = fes->GetElementToDofTable();
31  Table dof_dof;
32 
33  if (fbfi.Size() > 0)
34  {
35  // the sparsity pattern is defined from the map: face->element->dof
36  Table face_dof, dof_face;
37  {
38  Table *face_elem = fes->GetMesh()->GetFaceToElementTable();
39  mfem::Mult(*face_elem, elem_dof, face_dof);
40  delete face_elem;
41  }
42  Transpose(face_dof, dof_face, height);
43  mfem::Mult(dof_face, face_dof, dof_dof);
44  }
45  else
46  {
47  // the sparsity pattern is defined from the map: element->dof
48  Table dof_elem;
49  Transpose(elem_dof, dof_elem, height);
50  mfem::Mult(dof_elem, elem_dof, dof_dof);
51  }
52 
53  dof_dof.SortRows();
54 
55  int *I = dof_dof.GetI();
56  int *J = dof_dof.GetJ();
57  double *data = new double[I[height]];
58 
59  mat = new SparseMatrix(I, J, data, height, height, true, true, true);
60  *mat = 0.0;
61 
62  dof_dof.LoseData();
63 }
64 
66  : Matrix (f->GetVSize())
67 {
68  fes = f;
69  sequence = f->GetSequence();
70  mat = mat_e = NULL;
71  extern_bfs = 0;
72  element_matrices = NULL;
73  static_cond = NULL;
74  hybridization = NULL;
76 }
77 
79  : Matrix (f->GetVSize())
80 {
81  int i;
83 
84  fes = f;
85  sequence = f->GetSequence();
86  mat_e = NULL;
87  extern_bfs = 1;
88  element_matrices = NULL;
89  static_cond = NULL;
90  hybridization = NULL;
92 
93  bfi = bf->GetDBFI();
94  dbfi.SetSize (bfi->Size());
95  for (i = 0; i < bfi->Size(); i++)
96  {
97  dbfi[i] = (*bfi)[i];
98  }
99 
100  bfi = bf->GetBBFI();
101  bbfi.SetSize (bfi->Size());
102  for (i = 0; i < bfi->Size(); i++)
103  {
104  bbfi[i] = (*bfi)[i];
105  }
106 
107  bfi = bf->GetFBFI();
108  fbfi.SetSize (bfi->Size());
109  for (i = 0; i < bfi->Size(); i++)
110  {
111  fbfi[i] = (*bfi)[i];
112  }
113 
114  bfi = bf->GetBFBFI();
115  bfbfi.SetSize (bfi->Size());
116  for (i = 0; i < bfi->Size(); i++)
117  {
118  bfbfi[i] = (*bfi)[i];
119  }
120 
121  AllocMat();
122 }
123 
125 {
126  delete static_cond;
129  {
130  bool symmetric = false; // TODO
131  bool block_diagonal = false; // TODO
132  static_cond->Init(symmetric, block_diagonal);
133  }
134  else
135  {
136  delete static_cond;
137  static_cond = NULL;
138  }
139 }
140 
142  BilinearFormIntegrator *constr_integ,
143  const Array<int> &ess_tdof_list)
144 {
145  delete hybridization;
146  hybridization = new Hybridization(fes, constr_space);
147  hybridization->SetConstraintIntegrator(constr_integ);
148  hybridization->Init(ess_tdof_list);
149 }
150 
151 double& BilinearForm::Elem (int i, int j)
152 {
153  return mat -> Elem(i,j);
154 }
155 
156 const double& BilinearForm::Elem (int i, int j) const
157 {
158  return mat -> Elem(i,j);
159 }
160 
161 void BilinearForm::Mult (const Vector & x, Vector & y) const
162 {
163  mat -> Mult (x, y);
164 }
165 
167 {
168  return mat -> Inverse();
169 }
170 
171 void BilinearForm::Finalize (int skip_zeros)
172 {
173  if (!static_cond) { mat->Finalize(skip_zeros); }
174  if (mat_e) { mat_e->Finalize(skip_zeros); }
175  if (static_cond) { static_cond->Finalize(); }
177 }
178 
180 {
181  dbfi.Append (bfi);
182 }
183 
185 {
186  bbfi.Append (bfi);
187 }
188 
190 {
191  fbfi.Append (bfi);
192 }
193 
195 {
196  bfbfi.Append (bfi);
197 }
198 
200 {
201  if (element_matrices)
202  {
204  elmat = element_matrices->GetData(i);
205  return;
206  }
207 
208  if (dbfi.Size())
209  {
210  const FiniteElement &fe = *fes->GetFE(i);
212  dbfi[0]->AssembleElementMatrix(fe, *eltrans, elmat);
213  for (int k = 1; k < dbfi.Size(); k++)
214  {
215  dbfi[k]->AssembleElementMatrix(fe, *eltrans, elemmat);
216  elmat += elemmat;
217  }
218  }
219  else
220  {
222  elmat.SetSize(vdofs.Size());
223  elmat = 0.0;
224  }
225 }
226 
228  int i, const DenseMatrix &elmat, Array<int> &vdofs, int skip_zeros)
229 {
230  fes->GetElementVDofs(i, vdofs);
231  if (static_cond)
232  {
233  static_cond->AssembleMatrix(i, elmat);
234  }
235  else
236  {
237  if (mat == NULL)
238  {
239  AllocMat();
240  }
241  mat->AddSubMatrix(vdofs, vdofs, elmat, skip_zeros);
242  if (hybridization)
243  {
244  hybridization->AssembleMatrix(i, elmat);
245  }
246  }
247 }
248 
250  int i, const DenseMatrix &elmat, Array<int> &vdofs, int skip_zeros)
251 {
252  fes->GetBdrElementVDofs(i, vdofs);
253  if (static_cond)
254  {
255  static_cond->AssembleBdrMatrix(i, elmat);
256  }
257  else
258  {
259  if (mat == NULL)
260  {
261  AllocMat();
262  }
263  mat->AddSubMatrix(vdofs, vdofs, elmat, skip_zeros);
264  if (hybridization)
265  {
266  hybridization->AssembleBdrMatrix(i, elmat);
267  }
268  }
269 }
270 
271 void BilinearForm::Assemble (int skip_zeros)
272 {
273  ElementTransformation *eltrans;
274  Mesh *mesh = fes -> GetMesh();
275  DenseMatrix elmat, *elmat_p;
276 
277  int i;
278 
279  if (mat == NULL)
280  {
281  AllocMat();
282  }
283 
284 #ifdef MFEM_USE_OPENMP
285  int free_element_matrices = 0;
286  if (!element_matrices)
287  {
289  free_element_matrices = 1;
290  }
291 #endif
292 
293  if (dbfi.Size())
294  {
295  for (i = 0; i < fes -> GetNE(); i++)
296  {
298  if (element_matrices)
299  {
300  elmat_p = &(*element_matrices)(i);
301  }
302  else
303  {
304  const FiniteElement &fe = *fes->GetFE(i);
305  eltrans = fes->GetElementTransformation(i);
306  dbfi[0]->AssembleElementMatrix(fe, *eltrans, elmat);
307  for (int k = 1; k < dbfi.Size(); k++)
308  {
309  dbfi[k]->AssembleElementMatrix(fe, *eltrans, elemmat);
310  elmat += elemmat;
311  }
312  elmat_p = &elmat;
313  }
314  if (static_cond)
315  {
316  static_cond->AssembleMatrix(i, *elmat_p);
317  }
318  else
319  {
320  mat->AddSubMatrix(vdofs, vdofs, *elmat_p, skip_zeros);
321  if (hybridization)
322  {
323  hybridization->AssembleMatrix(i, *elmat_p);
324  }
325  }
326  }
327  }
328 
329  if (bbfi.Size())
330  {
331  for (i = 0; i < fes -> GetNBE(); i++)
332  {
333  const FiniteElement &be = *fes->GetBE(i);
334  fes -> GetBdrElementVDofs (i, vdofs);
335  eltrans = fes -> GetBdrElementTransformation (i);
336  bbfi[0]->AssembleElementMatrix(be, *eltrans, elmat);
337  for (int k = 1; k < bbfi.Size(); k++)
338  {
339  bbfi[k]->AssembleElementMatrix(be, *eltrans, elemmat);
340  elmat += elemmat;
341  }
342  if (!static_cond)
343  {
344  mat->AddSubMatrix(vdofs, vdofs, elmat, skip_zeros);
345  if (hybridization)
346  {
347  hybridization->AssembleBdrMatrix(i, elmat);
348  }
349  }
350  else
351  {
352  static_cond->AssembleBdrMatrix(i, elmat);
353  }
354  }
355  }
356 
357  if (fbfi.Size())
358  {
360  Array<int> vdofs2;
361 
362  int nfaces = mesh->GetNumFaces();
363  for (i = 0; i < nfaces; i++)
364  {
365  tr = mesh -> GetInteriorFaceTransformations (i);
366  if (tr != NULL)
367  {
368  fes -> GetElementVDofs (tr -> Elem1No, vdofs);
369  fes -> GetElementVDofs (tr -> Elem2No, vdofs2);
370  vdofs.Append (vdofs2);
371  for (int k = 0; k < fbfi.Size(); k++)
372  {
373  fbfi[k] -> AssembleFaceMatrix (*fes -> GetFE (tr -> Elem1No),
374  *fes -> GetFE (tr -> Elem2No),
375  *tr, elemmat);
376  mat -> AddSubMatrix (vdofs, vdofs, elemmat, skip_zeros);
377  }
378  }
379  }
380  }
381 
382  if (bfbfi.Size())
383  {
385  const FiniteElement *fe1, *fe2;
386 
387  for (i = 0; i < fes -> GetNBE(); i++)
388  {
389  tr = mesh -> GetBdrFaceTransformations (i);
390  if (tr != NULL)
391  {
392  fes -> GetElementVDofs (tr -> Elem1No, vdofs);
393  fe1 = fes -> GetFE (tr -> Elem1No);
394  // The fe2 object is really a dummy and not used on the boundaries,
395  // but we can't dereference a NULL pointer, and we don't want to
396  // actually make a fake element.
397  fe2 = fe1;
398  for (int k = 0; k < bfbfi.Size(); k++)
399  {
400  bfbfi[k] -> AssembleFaceMatrix (*fe1, *fe2, *tr, elemmat);
401  mat -> AddSubMatrix (vdofs, vdofs, elemmat, skip_zeros);
402  }
403  }
404  }
405  }
406 
407 #ifdef MFEM_USE_OPENMP
408  if (free_element_matrices)
409  {
411  }
412 #endif
413 }
414 
416 {
417  // Do not remove zero entries to preserve the symmetric structure of the
418  // matrix which in turn will give rise to symmetric structure in the new
419  // matrix. This ensures that subsequent calls to EliminateRowCol will work
420  // correctly.
421  Finalize(0);
422  MFEM_ASSERT(mat, "the BilinearForm is not assembled")
423 
425  if (!P) { return; } // conforming mesh
426 
427  SparseMatrix *R = Transpose(*P);
428  SparseMatrix *RA = mfem::Mult(*R, *mat);
429  delete mat;
430  if (mat_e)
431  {
432  SparseMatrix *RAe = mfem::Mult(*R, *mat_e);
433  delete mat_e;
434  mat_e = RAe;
435  }
436  delete R;
437  mat = mfem::Mult(*RA, *P);
438  delete RA;
439  if (mat_e)
440  {
441  SparseMatrix *RAeP = mfem::Mult(*mat_e, *P);
442  delete mat_e;
443  mat_e = RAeP;
444  }
445 
446  height = mat->Height();
447  width = mat->Width();
448 }
449 
451  Vector &x, Vector &b,
452  SparseMatrix &A, Vector &X, Vector &B,
453  int copy_interior)
454 {
456  Array<int> ess_rtdof_list;
457 
458  // Finish the matrix assembly and perform BC elimination, storing the
459  // eliminated part of the matrix.
460  const int keep_diag = 1;
461  if (static_cond)
462  {
463  static_cond->ConvertListToReducedTrueDofs(ess_tdof_list, ess_rtdof_list);
465  {
466  static_cond->Finalize(); // finalize Schur complement (to true dofs)
467  static_cond->EliminateReducedTrueDofs(ess_rtdof_list, keep_diag);
468  static_cond->Finalize(); // finalize eliminated part
469  }
470  }
471  else if (!mat_e)
472  {
473  if (P) { ConformingAssemble(); }
474  EliminateVDofs(ess_tdof_list, keep_diag);
475  const int remove_zeros = 0;
476  Finalize(remove_zeros);
477  }
478 
479  // Transform the system and perform the elimination in B, based on the
480  // essential BC values from x. Restrict the BC part of x in X, and set the
481  // non-BC part to zero. Since there is no good initial guess for the Lagrange
482  // multipliers, set X = 0.0 for hybridization.
483  if (static_cond)
484  {
485  // Schur complement reduction to the exposed dofs
486  static_cond->ReduceRHS(b, B);
488  static_cond->GetMatrixElim().AddMult(X, B, -1.);
489  static_cond->GetMatrix().PartMult(ess_rtdof_list, X, B);
490  if (!copy_interior) { X.SetSubVectorComplement(ess_rtdof_list, 0.0); }
492  }
493  else if (!P) // conforming space
494  {
495  if (hybridization)
496  {
497  // Reduction to the Lagrange multipliers system
498  EliminateVDofsInRHS(ess_tdof_list, x, b);
499  hybridization->ReduceRHS(b, B);
500  X.SetSize(B.Size());
501  X = 0.0;
503  }
504  else
505  {
506  // A, X and B point to the same data as mat, x and b
507  EliminateVDofsInRHS(ess_tdof_list, x, b);
508  X.NewDataAndSize(x.GetData(), x.Size());
509  B.NewDataAndSize(b.GetData(), b.Size());
510  if (!copy_interior) { X.SetSubVectorComplement(ess_tdof_list, 0.0); }
511  A.MakeRef(*mat);
512  }
513  }
514  else // non-conforming space
515  {
516  if (hybridization)
517  {
518  // Reduction to the Lagrange multipliers system
520  Vector conf_b(P->Width()), conf_x(P->Width());
521  P->MultTranspose(b, conf_b);
522  R->Mult(x, conf_x);
523  EliminateVDofsInRHS(ess_tdof_list, conf_x, conf_b);
524  R->MultTranspose(conf_b, b); // store eliminated rhs in b
525  hybridization->ReduceRHS(conf_b, B);
526  X.SetSize(B.Size());
527  X = 0.0;
529  }
530  else
531  {
532  // Variational restriction with P
534  B.SetSize(P->Width());
535  P->MultTranspose(b, B);
536  X.SetSize(R->Height());
537  R->Mult(x, X);
538  EliminateVDofsInRHS(ess_tdof_list, X, B);
539  if (!copy_interior) { X.SetSubVectorComplement(ess_tdof_list, 0.0); }
540  A.MakeRef(*mat);
541  }
542  }
543 }
544 
546  const Vector &b, Vector &x)
547 {
549  if (!P) // conforming space
550  {
551  if (static_cond)
552  {
553  // Private dofs back solve
554  static_cond->ComputeSolution(b, X, x);
555  }
556  else if (hybridization)
557  {
558  // Primal unknowns recovery
559  hybridization->ComputeSolution(b, X, x);
560  }
561  else
562  {
563  // X and x point to the same data
564  }
565  }
566  else // non-conforming space
567  {
568  if (static_cond)
569  {
570  // Private dofs back solve
571  static_cond->ComputeSolution(b, X, x);
572  }
573  else if (hybridization)
574  {
575  // Primal unknowns recovery
576  Vector conf_b(P->Width()), conf_x(P->Width());
577  P->MultTranspose(b, conf_b);
579  R->Mult(x, conf_x); // get essential b.c. from x
580  hybridization->ComputeSolution(conf_b, X, conf_x);
581  x.SetSize(P->Height());
582  P->Mult(conf_x, x);
583  }
584  else
585  {
586  // Apply conforming prolongation
587  x.SetSize(P->Height());
588  P->Mult(X, x);
589  }
590  }
591 }
592 
594 {
595  if (element_matrices || dbfi.Size() == 0 || fes->GetNE() == 0)
596  {
597  return;
598  }
599 
600  int num_elements = fes->GetNE();
601  int num_dofs_per_el = fes->GetFE(0)->GetDof() * fes->GetVDim();
602 
603  element_matrices = new DenseTensor(num_dofs_per_el, num_dofs_per_el,
604  num_elements);
605 
606  DenseMatrix tmp;
608 
609 #ifdef MFEM_USE_OPENMP
610  #pragma omp parallel for private(tmp,eltrans)
611 #endif
612  for (int i = 0; i < num_elements; i++)
613  {
615  num_dofs_per_el, num_dofs_per_el);
616  const FiniteElement &fe = *fes->GetFE(i);
617 #ifdef MFEM_DEBUG
618  if (num_dofs_per_el != fe.GetDof()*fes->GetVDim())
619  mfem_error("BilinearForm::ComputeElementMatrices:"
620  " all elements must have same number of dofs");
621 #endif
622  fes->GetElementTransformation(i, &eltrans);
623 
624  dbfi[0]->AssembleElementMatrix(fe, eltrans, elmat);
625  for (int k = 1; k < dbfi.Size(); k++)
626  {
627  // note: some integrators may not be thread-safe
628  dbfi[k]->AssembleElementMatrix(fe, eltrans, tmp);
629  elmat += tmp;
630  }
631  elmat.ClearExternalData();
632  }
633 }
634 
636  Vector &sol, Vector &rhs, int d)
637 {
638  Array<int> ess_dofs, conf_ess_dofs;
639  fes->GetEssentialVDofs(bdr_attr_is_ess, ess_dofs);
640 
641  if (fes->GetVSize() == height)
642  {
643  EliminateEssentialBCFromDofs(ess_dofs, sol, rhs, d);
644  }
645  else
646  {
647  fes->GetRestrictionMatrix()->BooleanMult(ess_dofs, conf_ess_dofs);
648  EliminateEssentialBCFromDofs(conf_ess_dofs, sol, rhs, d);
649  }
650 }
651 
652 void BilinearForm::EliminateEssentialBC(Array<int> &bdr_attr_is_ess, int d)
653 {
654  Array<int> ess_dofs, conf_ess_dofs;
655  fes->GetEssentialVDofs(bdr_attr_is_ess, ess_dofs);
656 
657  if (fes->GetVSize() == height)
658  {
659  EliminateEssentialBCFromDofs(ess_dofs, d);
660  }
661  else
662  {
663  fes->GetRestrictionMatrix()->BooleanMult(ess_dofs, conf_ess_dofs);
664  EliminateEssentialBCFromDofs(conf_ess_dofs, d);
665  }
666 }
667 
669  double value)
670 {
671  Array<int> ess_dofs, conf_ess_dofs;
672  fes->GetEssentialVDofs(bdr_attr_is_ess, ess_dofs);
673 
674  if (fes->GetVSize() == height)
675  {
676  EliminateEssentialBCFromDofsDiag(ess_dofs, value);
677  }
678  else
679  {
680  fes->GetRestrictionMatrix()->BooleanMult(ess_dofs, conf_ess_dofs);
681  EliminateEssentialBCFromDofsDiag(conf_ess_dofs, value);
682  }
683 }
684 
686  Vector &sol, Vector &rhs, int d)
687 {
688  for (int i = 0; i < vdofs.Size(); i++)
689  {
690  int vdof = vdofs[i];
691  if ( vdof >= 0 )
692  {
693  mat -> EliminateRowCol (vdof, sol(vdof), rhs, d);
694  }
695  else
696  {
697  mat -> EliminateRowCol (-1-vdof, sol(-1-vdof), rhs, d);
698  }
699  }
700 }
701 
703 {
704  if (mat_e == NULL)
705  {
706  mat_e = new SparseMatrix(height);
707  }
708 
709  for (int i = 0; i < vdofs.Size(); i++)
710  {
711  int vdof = vdofs[i];
712  if ( vdof >= 0 )
713  {
714  mat -> EliminateRowCol (vdof, *mat_e, d);
715  }
716  else
717  {
718  mat -> EliminateRowCol (-1-vdof, *mat_e, d);
719  }
720  }
721 }
722 
724  Array<int> &ess_dofs, Vector &sol, Vector &rhs, int d)
725 {
726  MFEM_ASSERT(ess_dofs.Size() == height, "incorrect dof Array size");
727  MFEM_ASSERT(sol.Size() == height, "incorrect sol Vector size");
728  MFEM_ASSERT(rhs.Size() == height, "incorrect rhs Vector size");
729 
730  for (int i = 0; i < ess_dofs.Size(); i++)
731  if (ess_dofs[i] < 0)
732  {
733  mat -> EliminateRowCol (i, sol(i), rhs, d);
734  }
735 }
736 
738 {
739  MFEM_ASSERT(ess_dofs.Size() == height, "incorrect dof Array size");
740 
741  for (int i = 0; i < ess_dofs.Size(); i++)
742  if (ess_dofs[i] < 0)
743  {
744  mat -> EliminateRowCol (i, d);
745  }
746 }
747 
749  double value)
750 {
751  MFEM_ASSERT(ess_dofs.Size() == height, "incorrect dof Array size");
752 
753  for (int i = 0; i < ess_dofs.Size(); i++)
754  if (ess_dofs[i] < 0)
755  {
756  mat -> EliminateRowColDiag (i, value);
757  }
758 }
759 
761  Array<int> &vdofs, const Vector &x, Vector &b)
762 {
763  mat_e->AddMult(x, b, -1.);
764  mat->PartMult(vdofs, x, b);
765 }
766 
768 {
769  bool full_update;
770 
771  if (nfes && nfes != fes)
772  {
773  full_update = true;
774  fes = nfes;
775  }
776  else
777  {
778  // Check for different size (e.g. assembled form on non-conforming space)
779  // or different sequence number.
780  full_update = (fes->GetVSize() != Height() ||
781  sequence < fes->GetSequence());
782  }
783 
784  delete mat_e;
785  mat_e = NULL;
787  delete static_cond;
788  static_cond = NULL;
789 
790  if (full_update)
791  {
792  delete mat;
793  mat = NULL;
794  delete hybridization;
795  hybridization = NULL;
796  sequence = fes->GetSequence();
797  }
798  else
799  {
800  if (mat) { *mat = 0.0; }
801  if (hybridization) { hybridization->Reset(); }
802  }
803 
804  height = width = fes->GetVSize();
805 }
806 
808 {
809  delete mat_e;
810  delete mat;
811  delete element_matrices;
812  delete static_cond;
813  delete hybridization;
814 
815  if (!extern_bfs)
816  {
817  int k;
818  for (k=0; k < dbfi.Size(); k++) { delete dbfi[k]; }
819  for (k=0; k < bbfi.Size(); k++) { delete bbfi[k]; }
820  for (k=0; k < fbfi.Size(); k++) { delete fbfi[k]; }
821  for (k=0; k < bfbfi.Size(); k++) { delete bfbfi[k]; }
822  }
823 }
824 
825 
827  FiniteElementSpace *te_fes)
828  : Matrix(te_fes->GetVSize(), tr_fes->GetVSize())
829 {
830  trial_fes = tr_fes;
831  test_fes = te_fes;
832  mat = NULL;
833 }
834 
835 double & MixedBilinearForm::Elem (int i, int j)
836 {
837  return (*mat)(i, j);
838 }
839 
840 const double & MixedBilinearForm::Elem (int i, int j) const
841 {
842  return (*mat)(i, j);
843 }
844 
845 void MixedBilinearForm::Mult (const Vector & x, Vector & y) const
846 {
847  mat -> Mult (x, y);
848 }
849 
851  const double a) const
852 {
853  mat -> AddMult (x, y, a);
854 }
855 
857  const double a) const
858 {
859  mat -> AddMultTranspose (x, y, a);
860 }
861 
863 {
864  return mat -> Inverse ();
865 }
866 
867 void MixedBilinearForm::Finalize (int skip_zeros)
868 {
869  mat -> Finalize (skip_zeros);
870 }
871 
873 {
874  MFEM_VERIFY(trial_fes->GetOrdering() == Ordering::byNODES &&
876  "MixedBilinearForm::GetBlocks: both trial and test spaces "
877  "must use Ordering::byNODES!");
878 
879  blocks.SetSize(test_fes->GetVDim(), trial_fes->GetVDim());
880 
881  mat->GetBlocks(blocks);
882 }
883 
885 {
886  dom.Append (bfi);
887 }
888 
890 {
891  bdr.Append (bfi);
892 }
893 
895 {
896  skt.Append (bfi);
897 }
898 
899 void MixedBilinearForm::Assemble (int skip_zeros)
900 {
901  int i, k;
902  Array<int> tr_vdofs, te_vdofs;
903  ElementTransformation *eltrans;
904  DenseMatrix elemmat;
905 
906  Mesh *mesh = test_fes -> GetMesh();
907 
908  if (mat == NULL)
909  {
910  mat = new SparseMatrix(height, width);
911  }
912 
913  if (dom.Size())
914  {
915  for (i = 0; i < test_fes -> GetNE(); i++)
916  {
917  trial_fes -> GetElementVDofs (i, tr_vdofs);
918  test_fes -> GetElementVDofs (i, te_vdofs);
919  eltrans = test_fes -> GetElementTransformation (i);
920  for (k = 0; k < dom.Size(); k++)
921  {
922  dom[k] -> AssembleElementMatrix2 (*trial_fes -> GetFE(i),
923  *test_fes -> GetFE(i),
924  *eltrans, elemmat);
925  mat -> AddSubMatrix (te_vdofs, tr_vdofs, elemmat, skip_zeros);
926  }
927  }
928  }
929 
930  if (bdr.Size())
931  {
932  for (i = 0; i < test_fes -> GetNBE(); i++)
933  {
934  trial_fes -> GetBdrElementVDofs (i, tr_vdofs);
935  test_fes -> GetBdrElementVDofs (i, te_vdofs);
936  eltrans = test_fes -> GetBdrElementTransformation (i);
937  for (k = 0; k < bdr.Size(); k++)
938  {
939  bdr[k] -> AssembleElementMatrix2 (*trial_fes -> GetBE(i),
940  *test_fes -> GetBE(i),
941  *eltrans, elemmat);
942  mat -> AddSubMatrix (te_vdofs, tr_vdofs, elemmat, skip_zeros);
943  }
944  }
945  }
946 
947  if (skt.Size())
948  {
950  Array<int> te_vdofs2;
951  const FiniteElement *trial_face_fe, *test_fe1, *test_fe2;
952 
953  int nfaces = mesh->GetNumFaces();
954  for (i = 0; i < nfaces; i++)
955  {
956  ftr = mesh->GetFaceElementTransformations(i);
957  trial_fes->GetFaceVDofs(i, tr_vdofs);
958  test_fes->GetElementVDofs(ftr->Elem1No, te_vdofs);
959  trial_face_fe = trial_fes->GetFaceElement(i);
960  test_fe1 = test_fes->GetFE(ftr->Elem1No);
961  if (ftr->Elem2No >= 0)
962  {
963  test_fes->GetElementVDofs(ftr->Elem2No, te_vdofs2);
964  te_vdofs.Append(te_vdofs2);
965  test_fe2 = test_fes->GetFE(ftr->Elem2No);
966  }
967  else
968  {
969  // The test_fe2 object is really a dummy and not used on the
970  // boundaries, but we can't dereference a NULL pointer, and we don't
971  // want to actually make a fake element.
972  test_fe2 = test_fe1;
973  }
974  for (int k = 0; k < skt.Size(); k++)
975  {
976  skt[k]->AssembleFaceMatrix(*trial_face_fe, *test_fe1, *test_fe2,
977  *ftr, elemmat);
978  mat->AddSubMatrix(te_vdofs, tr_vdofs, elemmat, skip_zeros);
979  }
980  }
981  }
982 }
983 
985 {
986  Finalize();
987 
989  if (P2)
990  {
991  SparseMatrix *R = Transpose(*P2);
992  SparseMatrix *RA = mfem::Mult(*R, *mat);
993  delete R;
994  delete mat;
995  mat = RA;
996  }
997 
999  if (P1)
1000  {
1001  SparseMatrix *RAP = mfem::Mult(*mat, *P1);
1002  delete mat;
1003  mat = RAP;
1004  }
1005 
1006  height = mat->Height();
1007  width = mat->Width();
1008 }
1009 
1011  Array<int> &bdr_attr_is_ess, Vector &sol, Vector &rhs )
1012 {
1013  int i, j, k;
1014  Array<int> tr_vdofs, cols_marker (trial_fes -> GetVSize());
1015 
1016  cols_marker = 0;
1017  for (i = 0; i < trial_fes -> GetNBE(); i++)
1018  if (bdr_attr_is_ess[trial_fes -> GetBdrAttribute (i)-1])
1019  {
1020  trial_fes -> GetBdrElementVDofs (i, tr_vdofs);
1021  for (j = 0; j < tr_vdofs.Size(); j++)
1022  {
1023  if ( (k = tr_vdofs[j]) < 0 )
1024  {
1025  k = -1-k;
1026  }
1027  cols_marker[k] = 1;
1028  }
1029  }
1030  mat -> EliminateCols (cols_marker, &sol, &rhs);
1031 }
1032 
1034  Array<int> &marked_vdofs, Vector &sol, Vector &rhs)
1035 {
1036  mat -> EliminateCols (marked_vdofs, &sol, &rhs);
1037 }
1038 
1040 {
1041  int i, j, k;
1042  Array<int> te_vdofs;
1043 
1044  for (i = 0; i < test_fes -> GetNBE(); i++)
1045  if (bdr_attr_is_ess[test_fes -> GetBdrAttribute (i)-1])
1046  {
1047  test_fes -> GetBdrElementVDofs (i, te_vdofs);
1048  for (j = 0; j < te_vdofs.Size(); j++)
1049  {
1050  if ( (k = te_vdofs[j]) < 0 )
1051  {
1052  k = -1-k;
1053  }
1054  mat -> EliminateRow (k);
1055  }
1056  }
1057 }
1058 
1060 {
1061  delete mat;
1062  mat = NULL;
1063  height = test_fes->GetVSize();
1064  width = trial_fes->GetVSize();
1065 }
1066 
1068 {
1069  int i;
1070 
1071  if (mat) { delete mat; }
1072  for (i = 0; i < dom.Size(); i++) { delete dom[i]; }
1073  for (i = 0; i < bdr.Size(); i++) { delete bdr[i]; }
1074  for (i = 0; i < skt.Size(); i++) { delete skt[i]; }
1075 }
1076 
1077 
1079 {
1080  Array<int> dom_vdofs, ran_vdofs;
1082  const FiniteElement *dom_fe, *ran_fe;
1083  DenseMatrix totelmat, elmat;
1084 
1085  if (mat == NULL)
1086  {
1087  mat = new SparseMatrix(height, width);
1088  }
1089 
1090  if (dom.Size() > 0)
1091  {
1092  for (int i = 0; i < test_fes->GetNE(); i++)
1093  {
1094  trial_fes->GetElementVDofs(i, dom_vdofs);
1095  test_fes->GetElementVDofs(i, ran_vdofs);
1097  dom_fe = trial_fes->GetFE(i);
1098  ran_fe = test_fes->GetFE(i);
1099 
1100  dom[0]->AssembleElementMatrix2(*dom_fe, *ran_fe, *T, totelmat);
1101  for (int j = 1; j < dom.Size(); j++)
1102  {
1103  dom[j]->AssembleElementMatrix2(*dom_fe, *ran_fe, *T, elmat);
1104  totelmat += elmat;
1105  }
1106  mat->SetSubMatrix(ran_vdofs, dom_vdofs, totelmat, skip_zeros);
1107  }
1108  }
1109 
1110  if (skt.Size())
1111  {
1112  const int nfaces = test_fes->GetMesh()->GetNumFaces();
1113  for (int i = 0; i < nfaces; i++)
1114  {
1115  trial_fes->GetFaceVDofs(i, dom_vdofs);
1116  test_fes->GetFaceVDofs(i, ran_vdofs);
1118  dom_fe = trial_fes->GetFaceElement(i);
1119  ran_fe = test_fes->GetFaceElement(i);
1120 
1121  skt[0]->AssembleElementMatrix2(*dom_fe, *ran_fe, *T, totelmat);
1122  for (int j = 1; j < skt.Size(); j++)
1123  {
1124  skt[j]->AssembleElementMatrix2(*dom_fe, *ran_fe, *T, elmat);
1125  totelmat += elmat;
1126  }
1127  mat->SetSubMatrix(ran_vdofs, dom_vdofs, totelmat, skip_zeros);
1128  }
1129  }
1130 }
1131 
1132 }
Abstract class for Finite Elements.
Definition: fe.hpp:44
void EliminateEssentialBCFromDofs(Array< int > &ess_dofs, Vector &sol, Vector &rhs, int d=0)
Ordering::Type GetOrdering() const
Return the ordering method.
Definition: fespace.hpp:173
int Size() const
Logical size of the array.
Definition: array.hpp:109
int GetVSize() const
Definition: fespace.hpp:161
Array< BilinearFormIntegrator * > * GetBBFI()
int * GetJ()
Definition: table.hpp:108
virtual void Mult(const Vector &x, Vector &y) const
Matrix vector multiplication.
void NewDataAndSize(double *d, int s)
Definition: vector.hpp:74
virtual void AddMult(const Vector &x, Vector &y, const double a=1.0) const
Array< BilinearFormIntegrator * > skt
virtual MatrixInverse * Inverse() const
Returns a pointer to (approximation) of the matrix inverse.
void SetConstraintIntegrator(BilinearFormIntegrator *c_integ)
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.
bool ReducesTrueVSize() const
Definition: staticcond.cpp:118
void ReduceRHS(const Vector &b, Vector &sc_b) const
Definition: staticcond.cpp:309
Array< BilinearFormIntegrator * > * GetDBFI()
void MakeRef(const SparseMatrix &master)
Definition: sparsemat.cpp:186
void SortRows()
Sort the column (TYPE II) indices in each row.
Definition: table.cpp:188
void SetSize(int s)
Resize the vector if the new size is different.
Definition: vector.hpp:263
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:132
Array< BilinearFormIntegrator * > dbfi
Set of Domain Integrators to be applied.
virtual void GetEssentialVDofs(const Array< int > &bdr_attr_is_ess, Array< int > &ess_vdofs) const
Definition: fespace.cpp:237
Array< BilinearFormIntegrator * > * GetBFBFI()
void BooleanMult(const Array< int > &x, Array< int > &y) const
y = A * x, but treat all elements as booleans (zero=false, nonzero=true).
Definition: sparsemat.cpp:595
void Mult(const Table &A, const Table &B, Table &C)
C = A * B (as boolean matrices)
Definition: table.cpp:451
int Width() const
Get the width (size of input) of the Operator. Synonym with NumCols.
Definition: operator.hpp:41
void RecoverFEMSolution(const Vector &X, const Vector &b, Vector &x)
Data type dense matrix using column-major storage.
Definition: densemat.hpp:22
void AddMult(const Vector &x, Vector &y, const double a=1.0) const
y += A * x (default) or y += a * A * x
Definition: sparsemat.cpp:445
int Size() const
Returns the size of the vector.
Definition: vector.hpp:86
Abstract data type for matrix inverse.
Definition: matrix.hpp:58
void LoseData()
Call this if data has been stolen.
Definition: table.hpp:141
const FiniteElement * GetFaceElement(int i) const
Definition: fespace.cpp:1359
virtual void Finalize(int skip_zeros=1)
Finalizes the matrix initialization.
void ComputeSolution(const Vector &b, const Vector &sc_sol, Vector &sol) const
Definition: staticcond.cpp:452
Array< BilinearFormIntegrator * > * GetFBFI()
double * GetData() const
Definition: vector.hpp:90
MixedBilinearForm(FiniteElementSpace *tr_fes, FiniteElementSpace *te_fes)
FaceElementTransformations * GetFaceElementTransformations(int FaceNo, int mask=31)
Definition: mesh.cpp:603
void Reset()
Destroy the current hybridization matrix while preserving the computed constraint matrix and the set ...
void FormLinearSystem(Array< int > &ess_tdof_list, Vector &x, Vector &b, SparseMatrix &A, Vector &X, Vector &B, int copy_interior=0)
void GetBlocks(Array2D< SparseMatrix * > &blocks) const
Definition: sparsemat.cpp:778
void EnableHybridization(FiniteElementSpace *constr_space, BilinearFormIntegrator *constr_integ, const Array< int > &ess_tdof_list)
int GetNumFaces() const
Return the number of faces (3D), edges (2D) or vertices (1D).
Definition: mesh.cpp:3039
void EliminateEssentialBCFromTrialDofs(Array< int > &marked_vdofs, Vector &sol, Vector &rhs)
Array< BilinearFormIntegrator * > bdr
void AddDomainIntegrator(BilinearFormIntegrator *bfi)
int GetNE() const
Returns number of elements in the mesh.
Definition: fespace.hpp:182
void EliminateVDofs(Array< int > &vdofs, Vector &sol, Vector &rhs, int d=0)
Eliminate the given vdofs. NOTE: here, vdofs is a list of DOFs.
void SetSize(int m, int n)
Definition: array.hpp:264
void Finalize()
Finalize the construction of the hybridized matrix.
void AssembleBdrMatrix(int bdr_el, const DenseMatrix &A)
Assemble the boundary element matrix A into the hybridized system matrix.
const SparseMatrix * GetConformingRestriction()
Definition: fespace.cpp:676
virtual void AddMultTranspose(const Vector &x, Vector &y, const double a=1.0) const
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
SparseMatrix & GetMatrix()
Return the serial hybridized matrix.
StaticCondensation * static_cond
int Append(const T &el)
Append element to array, resize if necessary.
Definition: array.hpp:376
Mesh * GetMesh() const
Returns the mesh.
Definition: fespace.hpp:136
SparseMatrix * mat
Sparse matrix to be associated with the form.
void GetFaceTransformation(int i, IsoparametricTransformation *FTr)
Definition: mesh.cpp:344
void ComputeSolution(const Vector &b, const Vector &sol_r, Vector &sol) const
Abstract data type matrix.
Definition: matrix.hpp:27
HypreParMatrix * RAP(HypreParMatrix *A, HypreParMatrix *P)
Returns the matrix P^t * A * P.
Definition: hypre.cpp:1365
void Assemble(int skip_zeros=1)
void Transpose(const Table &A, Table &At, int _ncols_A)
Transpose a Table.
Definition: table.cpp:391
double * GetData(int k)
Definition: densemat.hpp:624
virtual void Update(FiniteElementSpace *nfes=NULL)
void EliminateTrialDofs(Array< int > &bdr_attr_is_ess, Vector &sol, Vector &rhs)
const SparseMatrix * GetConformingProlongation()
Definition: fespace.cpp:669
int GetVDim() const
Returns vector dimension.
Definition: fespace.hpp:151
virtual void Finalize(int skip_zeros=1)
Definition: sparsemat.cpp:706
virtual const SparseMatrix * GetRestrictionMatrix()
Definition: fespace.hpp:147
void AddTraceFaceIntegrator(BilinearFormIntegrator *bfi)
void AddSubMatrix(const Array< int > &rows, const Array< int > &cols, const DenseMatrix &subm, int skip_zeros=1)
Definition: sparsemat.cpp:1759
void GetBlocks(Array2D< SparseMatrix * > &blocks) const
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
void SetSubMatrix(const Array< int > &rows, const Array< int > &cols, const DenseMatrix &subm, int skip_zeros=1)
Definition: sparsemat.cpp:1835
int SizeI() const
Definition: densemat.hpp:593
void ComputeElementMatrix(int i, DenseMatrix &elmat)
void EliminateEssentialBCDiag(Array< int > &bdr_attr_is_ess, double value)
Perform elimination and set the diagonal entry to the given value.
SparseMatrix * mat_e
Matrix used to eliminate b.c.
ElementTransformation * GetElementTransformation(int i) const
Returns ElementTransformation for the i&#39;th element.
Definition: fespace.hpp:203
Abstract base class BilinearFormIntegrator.
Definition: bilininteg.hpp:22
void AssembleElementMatrix(int i, const DenseMatrix &elmat, Array< int > &vdofs, int skip_zeros=1)
void AssembleMatrix(int el, const DenseMatrix &A)
Assemble the element matrix A into the hybridized system matrix.
int GetDof() const
Returns the degrees of freedom in the FE space.
Definition: fe.hpp:88
virtual void Mult(const Vector &x, Vector &y) const
Matrix vector multiplication.
Definition: sparsemat.cpp:439
Array< BilinearFormIntegrator * > bfbfi
Set of boundary face Integrators to be applied.
Array< BilinearFormIntegrator * > bbfi
Set of Boundary Integrators to be applied.
DenseTensor * element_matrices
void Finalize()
Finalize the construction of the Schur complement matrix.
Definition: staticcond.cpp:235
void mfem_error(const char *msg)
Definition: error.cpp:23
void ClearExternalData()
Definition: densemat.hpp:65
virtual double & Elem(int i, int j)
Returns reference to a_{ij}.
Array< BilinearFormIntegrator * > dom
void AssembleBdrMatrix(int el, const DenseMatrix &elmat)
Definition: staticcond.cpp:227
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
Table * GetFaceToElementTable() const
Definition: mesh.cpp:3531
FiniteElementSpace * test_fes
int SizeJ() const
Definition: densemat.hpp:594
virtual void EliminateTestDofs(Array< int > &bdr_attr_is_ess)
void EliminateVDofsInRHS(Array< int > &vdofs, const Vector &x, Vector &b)
virtual void Finalize(int skip_zeros=1)
Finalizes the matrix initialization.
void AssembleMatrix(int el, const DenseMatrix &elmat)
Definition: staticcond.cpp:189
bool HasEliminatedBC() const
Definition: staticcond.hpp:131
void AddBoundaryIntegrator(BilinearFormIntegrator *bfi)
Adds new Boundary Integrator.
void AddInteriorFaceIntegrator(BilinearFormIntegrator *bfi)
Adds new interior Face Integrator.
void MultTranspose(const Vector &x, Vector &y) const
Multiply a vector with the transposed matrix. y = At * x.
Definition: sparsemat.cpp:514
FiniteElementSpace * fes
FE space on which the form lives.
void AddDomainIntegrator(BilinearFormIntegrator *bfi)
Adds new Domain Integrator.
void ComputeElementMatrices()
Compute and store internally all element matrices.
const FiniteElement * GetFE(int i) const
Returns pointer to the FiniteElement associated with i&#39;th element.
Definition: fespace.cpp:1113
void AssembleBdrElementMatrix(int i, const DenseMatrix &elmat, Array< int > &vdofs, int skip_zeros=1)
DenseMatrix elemmat
void GetFaceVDofs(int i, Array< int > &vdofs) const
Returns indexes of degrees of freedom for i&#39;th face element (2D and 3D).
Definition: fespace.cpp:144
FiniteElementSpace * trial_fes
virtual double & Elem(int i, int j)
Returns reference to a_{ij}.
virtual ~BilinearForm()
Destroys bilinear form.
Vector data type.
Definition: vector.hpp:33
void AddBoundaryIntegrator(BilinearFormIntegrator *bfi)
SparseMatrix & GetMatrix()
Return the serial Schur complement matrix.
Definition: staticcond.hpp:141
virtual MatrixInverse * Inverse() const
Returns a pointer to (an approximation) of the matrix inverse.
Hybridization * hybridization
void ReduceRHS(const Vector &b, Vector &b_r) const
int * GetI()
Definition: table.hpp:107
const Table & GetElementToDofTable() const
Definition: fespace.hpp:275
void ReduceSolution(const Vector &sol, Vector &sc_sol) const
Definition: staticcond.cpp:388
SparseMatrix & GetMatrixElim()
Return the eliminated part of the serial Schur complement matrix.
Definition: staticcond.hpp:144
void Init(const Array< int > &ess_tdof_list)
Prepare the Hybridization object for assembly.
const FiniteElement * GetBE(int i) const
Returns pointer to the FiniteElement for the i&#39;th boundary element.
Definition: fespace.cpp:1333
void GetBdrElementVDofs(int i, Array< int > &vdofs) const
Returns indexes of degrees of freedom for i&#39;th boundary element.
Definition: fespace.cpp:138
Array< int > vdofs
void SetSize(int s)
Change the size of the DenseMatrix to s x s.
Definition: densemat.hpp:71
void FreeElementMatrices()
Free the memory used by the element matrices.
long GetSequence() const
Return update counter (see Mesh::sequence)
Definition: fespace.hpp:357
void EliminateEssentialBCFromDofsDiag(Array< int > &ess_dofs, double value)
Perform elimination and set the diagonal entry to the given value.
void Init(bool symmetric, bool block_diagonal)
Definition: staticcond.cpp:134
virtual void Assemble(int skip_zeros=1)
Rank 3 tensor (array of matrices)
Definition: densemat.hpp:569
void ConvertListToReducedTrueDofs(const Array< int > &ess_tdof_list, Array< int > &ess_rtdof_list) const
Definition: staticcond.hpp:169
void EliminateEssentialBC(Array< int > &bdr_attr_is_ess, Vector &sol, Vector &rhs, int d=0)
virtual void Mult(const Vector &x, Vector &y) const
Operator application.
void EnableStaticCondensation()
void AddBdrFaceIntegrator(BilinearFormIntegrator *bfi)
Adds new boundary Face Integrator.
void PartMult(const Array< int > &rows, const Vector &x, Vector &y) const
Definition: sparsemat.cpp:559