MFEM v4.9.0
Finite element discretization library
Loading...
Searching...
No Matches
pbilinearform.cpp
Go to the documentation of this file.
1// Copyright (c) 2010-2025, Lawrence Livermore National Security, LLC. Produced
2// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
3// LICENSE and NOTICE for details. LLNL-CODE-806117.
4//
5// This file is part of the MFEM library. For more information and source code
6// availability visit https://mfem.org.
7//
8// MFEM is free software; you can redistribute it and/or modify it under the
9// terms of the BSD-3 license. We welcome feedback and contributions, see file
10// CONTRIBUTING.md for details.
11
12#include "../config/config.hpp"
13
14#ifdef MFEM_USE_MPI
15
16#include "fem.hpp"
18
19namespace mfem
20{
21
23{
24 int nbr_size = pfes->GetFaceNbrVSize();
25
26 if (precompute_sparsity == 0 || fes->GetVDim() > 1)
27 {
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
40 const Table &lelem_ldof = fes->GetElementToDofTable(); // <-- dofs
41 const Table &nelem_ndof = pfes->face_nbr_element_dof; // <-- vdofs
42 Table elem_dof; // element + nbr-element <---> dof
43 if (nbr_size > 0)
44 {
45 // merge lelem_ldof and nelem_ndof into elem_dof
46 int s1 = lelem_ldof.Size(), s2 = nelem_ndof.Size();
47 const int *I1 = lelem_ldof.GetI(), *J1 = lelem_ldof.GetJ();
48 const int *I2 = nelem_ndof.GetI(), *J2 = nelem_ndof.GetJ();
49 const int nnz1 = I1[s1], nnz2 = I2[s2];
50
51 elem_dof.SetDims(s1 + s2, nnz1 + nnz2);
52
53 int *I = elem_dof.GetI(), *J = elem_dof.GetJ();
54 for (int i = 0; i <= s1; i++)
55 {
56 I[i] = I1[i];
57 }
58 for (int j = 0; j < nnz1; j++)
59 {
60 J[j] = J1[j];
61 }
62 for (int i = 0; i <= s2; i++)
63 {
64 I[s1+i] = I2[i] + nnz1;
65 }
66 for (int j = 0; j < nnz2; j++)
67 {
68 J[nnz1+j] = J2[j] + height;
69 }
70 }
71 // dof_elem x elem_face x face_elem x elem_dof (keep_nbr_block = true)
72 // ldof_lelem x lelem_face x face_elem x elem_dof (keep_nbr_block = false)
73 Table dof_dof;
74 {
75 Table face_dof; // face_elem x elem_dof
76 {
78 if (nbr_size > 0)
79 {
80 mfem::Mult(*face_elem, elem_dof, face_dof);
81 }
82 else
83 {
84 mfem::Mult(*face_elem, lelem_ldof, face_dof);
85 }
86 delete face_elem;
87 if (nbr_size > 0)
88 {
89 elem_dof.Clear();
90 }
91 }
92
94 {
95 Table dof_face;
96 Transpose(face_dof, dof_face, height + nbr_size);
97 mfem::Mult(dof_face, face_dof, dof_dof);
98 }
99 else
100 {
101 Table ldof_face;
102 {
103 Table face_ldof;
104 Table *face_lelem = fes->GetMesh()->GetFaceToElementTable();
105 mfem::Mult(*face_lelem, lelem_ldof, face_ldof);
106 delete face_lelem;
107 Transpose(face_ldof, ldof_face, height);
108 }
109 mfem::Mult(ldof_face, face_dof, dof_dof);
110 }
111 }
112
113 int *I = dof_dof.GetI();
114 int *J = dof_dof.GetJ();
115 int nrows = dof_dof.Size();
116 real_t *data = Memory<real_t>(I[nrows]);
117
118 mat = new SparseMatrix(I, J, data, nrows, height + nbr_size);
119 *mat = 0.0;
120
121 dof_dof.LoseData();
122}
123
125 bool steal_loc_A)
126{
127 ParFiniteElementSpace &pfespace = *ParFESpace();
128
129 // Create a block diagonal parallel matrix
131 A_diag.MakeSquareBlockDiag(pfespace.GetComm(),
132 pfespace.GlobalVSize(),
133 pfespace.GetDofOffsets(),
134 &loc_A);
135
136 // Parallel matrix assembly using P^t A P (if needed)
138 {
139 A_diag.SetOperatorOwner(false);
140 A.Reset(A_diag.As<HypreParMatrix>());
141 if (steal_loc_A)
142 {
144 }
145 }
146 else
147 {
149 P.ConvertFrom(pfespace.Dof_TrueDof_Matrix());
150 A.MakePtAP(A_diag, P);
151 }
152}
153
162
164{
165 A.Clear();
166
167 if (A_local == NULL) { return; }
168 MFEM_VERIFY(A_local->Finalized(), "the local matrix must be finalized");
169
170 OperatorHandle dA(A.Type()), Ph(A.Type()), hdA;
171
172 if (interior_face_integs.Size() == 0)
173 {
174 // construct a parallel block-diagonal matrix 'A' based on 'a'
176 pfes->GetDofOffsets(), A_local);
177 }
178 else
179 {
180 // handle the case when 'a' contains off-diagonal
181 int lvsize = pfes->GetVSize();
182 const HYPRE_BigInt *face_nbr_glob_ldof = pfes->GetFaceNbrGlobalDofMap();
183 HYPRE_BigInt ldof_offset = pfes->GetMyDofOffset();
184
185 Array<HYPRE_BigInt> glob_J(A_local->NumNonZeroElems());
186 int *J = A_local->GetJ();
187 for (int i = 0; i < glob_J.Size(); i++)
188 {
189 if (J[i] < lvsize)
190 {
191 glob_J[i] = J[i] + ldof_offset;
192 }
193 else
194 {
195 glob_J[i] = face_nbr_glob_ldof[J[i] - lvsize];
196 }
197 }
198
199 // TODO - construct dA directly in the A format
200 hdA.Reset(
201 new HypreParMatrix(pfes->GetComm(), lvsize, pfes->GlobalVSize(),
202 pfes->GlobalVSize(), A_local->GetI(), glob_J,
203 A_local->GetData(), pfes->GetDofOffsets(),
204 pfes->GetDofOffsets()));
205 // - hdA owns the new HypreParMatrix
206 // - the above constructor copies all input arrays
207 glob_J.DeleteAll();
208 dA.ConvertFrom(hdA);
209 }
210
211 // TODO - assemble the Dof_TrueDof_Matrix directly in the required format?
212 Ph.ConvertFrom(pfes->Dof_TrueDof_Matrix());
213 // TODO: When Ph.Type() == Operator::ANY_TYPE we want to use the Operator
214 // returned by pfes->GetProlongationMatrix(), however that Operator is a
215 // const Operator, so we cannot store it in OperatorHandle. We need a const
216 // version of class OperatorHandle, e.g. ConstOperatorHandle.
217
218 A.MakePtAP(dA, Ph);
219}
220
228
230{
231 ParMesh *pmesh = pfes->GetParMesh();
233 Array<int> vdofs1, vdofs2, vdofs_all;
235
236 int nfaces = pmesh->GetNSharedFaces();
237 for (int i = 0; i < nfaces; i++)
238 {
239 T = pmesh->GetSharedFaceTransformations(i);
240 int Elem2NbrNo = T->Elem2No - pmesh->GetNE();
241 pfes->GetElementVDofs(T->Elem1No, vdofs1);
242 pfes->GetFaceNbrElementVDofs(Elem2NbrNo, vdofs2);
243 vdofs1.Copy(vdofs_all);
244 for (int j = 0; j < vdofs2.Size(); j++)
245 {
246 if (vdofs2[j] >= 0)
247 {
248 vdofs2[j] += height;
249 }
250 else
251 {
252 vdofs2[j] -= height;
253 }
254 }
255 vdofs_all.Append(vdofs2);
256 for (int k = 0; k < interior_face_integs.Size(); k++)
257 {
259 AssembleFaceMatrix(*pfes->GetFE(T->Elem1No),
260 *pfes->GetFaceNbrFE(Elem2NbrNo),
261 *T, elemmat);
262 if (keep_nbr_block)
263 {
264 mat->AddSubMatrix(vdofs_all, vdofs_all, elemmat, skip_zeros);
265 }
266 else
267 {
268 mat->AddSubMatrix(vdofs1, vdofs_all, elemmat, skip_zeros);
269 }
270 }
271 }
272}
273
274void ParBilinearForm::Assemble(int skip_zeros)
275{
276 if (interior_face_integs.Size())
277 {
279 if (!ext && mat == NULL)
280 {
281 pAllocMat();
282 }
283 }
284
285 BilinearForm::Assemble(skip_zeros);
286
287 if (!ext && interior_face_integs.Size() > 0)
288 {
289 AssembleSharedFaces(skip_zeros);
290 }
291}
292
294{
295 MFEM_ASSERT(diag.Size() == fes->GetTrueVSize(),
296 "Vector for holding diagonal has wrong size!");
297 const Operator *P = fes->GetProlongationMatrix();
298 if (!ext)
299 {
300 MFEM_ASSERT(p_mat.Ptr(), "the ParBilinearForm is not assembled!");
301 p_mat->AssembleDiagonal(diag); // TODO: add support for PETSc matrices
302 return;
303 }
304 // Here, we have extension, ext.
306 {
307 ext->AssembleDiagonal(diag);
308 return;
309 }
310 // Here, we have extension, ext, and parallel/conforming prolongation, P.
311 Vector local_diag(P->Height());
312 ext->AssembleDiagonal(local_diag);
313 if (fes->Conforming())
314 {
315 P->MultTranspose(local_diag, diag);
316 return;
317 }
318 // For an AMR mesh, a convergent diagonal is assembled with |P^T| d_l,
319 // where |P^T| has the entry-wise absolute values of the conforming
320 // prolongation transpose operator.
321 const HypreParMatrix *HP = dynamic_cast<const HypreParMatrix*>(P);
322 if (HP)
323 {
324 HP->AbsMultTranspose(1.0, local_diag, 0.0, diag);
325 }
326 else
327 {
328 MFEM_ABORT("unsupported prolongation matrix type.");
329 }
330}
331
332void ParBilinearForm
333::ParallelEliminateEssentialBC(const Array<int> &bdr_attr_is_ess,
334 HypreParMatrix &A, const HypreParVector &X,
335 HypreParVector &B) const
336{
337 Array<int> dof_list;
338
339 pfes->GetEssentialTrueDofs(bdr_attr_is_ess, dof_list);
340
341 // do the parallel elimination
342 A.EliminateRowsCols(dof_list, X, B);
343}
344
346 const Array<int> &bdr_attr_is_ess, const HypreParVector &X, HypreParVector &B)
347{
348 Array<int> dof_list;
349 pfes->GetEssentialTrueDofs(bdr_attr_is_ess, dof_list);
350
351 p_mat.As<HypreParMatrix>()->EliminateRowsCols(dof_list, X, B);
352}
353
355ParallelEliminateEssentialBC(const Array<int> &bdr_attr_is_ess,
356 HypreParMatrix &A) const
357{
358 Array<int> dof_list;
359
360 pfes->GetEssentialTrueDofs(bdr_attr_is_ess, dof_list);
361
362 return A.EliminateRowsCols(dof_list);
363}
364
366 &bdr_attr_is_ess)
367{
368 Array<int> tdofs_list;
369 pfes->GetEssentialTrueDofs(bdr_attr_is_ess, tdofs_list);
370
371 ParallelEliminateTDofs(tdofs_list);
372}
373
375{
376 p_mat_e.EliminateRowsCols(p_mat, tdofs_list);
377}
378
380 const Array<int> &tdofs_list, const Vector &x, Vector &b)
381{
382 p_mat.EliminateBC(p_mat_e, tdofs_list, x, b);
383}
384
386const
387{
388 const Operator *P = pfes->GetProlongationMatrix();
389 Xaux.SetSize(P->Height());
390 Yaux.SetSize(P->Height());
391 Ytmp.SetSize(P->Width());
392
393 P->Mult(x, Xaux);
394 if (ext)
395 {
396 ext->Mult(Xaux, Yaux);
397 }
398 else
399 {
400 MFEM_VERIFY(interior_face_integs.Size() == 0,
401 "the case of interior face integrators is not"
402 " implemented");
403 mat->Mult(Xaux, Yaux);
404 }
406 y.Add(a, Ytmp);
407}
408
410 const ParGridFunction &y) const
411{
412 MFEM_ASSERT(mat != NULL, "local matrix must be assembled");
413
414 real_t loc = InnerProduct(x, y);
415 real_t glob = 0.;
416
417 MPI_Allreduce(&loc, &glob, 1, MPITypeMap<real_t>::mpi_type, MPI_SUM,
418 pfes->GetComm());
419
420 return glob;
421}
422
424 const ParGridFunction &y) const
425{
426 MFEM_ASSERT(x.ParFESpace() == pfes, "the parallel spaces must match");
427 MFEM_ASSERT(y.ParFESpace() == pfes, "the parallel spaces must match");
428
431
432 real_t res = TrueInnerProduct(*x_p, *y_p);
433
434 delete x_p;
435 delete y_p;
436
437 return res;
438}
439
441 HypreParVector &y) const
442{
443 MFEM_VERIFY(p_mat.Ptr() != NULL, "parallel matrix must be assembled");
444
446 {
447 return TrueInnerProduct((const Vector&)x, (const Vector&)y);
448 }
449
452
453 A->Mult(x, *Ax);
454
455 real_t res = mfem::InnerProduct(y, *Ax);
456
457 delete Ax;
458
459 return res;
460}
461
463 const Vector &y) const
464{
465 MFEM_VERIFY(p_mat.Ptr() != NULL, "parallel matrix must be assembled");
466
467 Vector Ax(pfes->GetTrueVSize());
468 p_mat->Mult(x, Ax);
469
470 real_t res = mfem::InnerProduct(pfes->GetComm(), y, Ax);
471
472 return res;
473}
474
476 const Array<int> &ess_tdof_list, Vector &x, Vector &b,
477 OperatorHandle &A, Vector &X, Vector &B, int copy_interior)
478{
479 const Operator &P = *pfes->GetProlongationMatrix();
481
482 if (ext)
483 {
484 if (hybridization)
485 {
486 HypreParVector true_X(pfes), true_B(pfes);
487 P.MultTranspose(b, true_B);
488 R.Mult(x, true_X);
489
490 FormSystemMatrix(ess_tdof_list, A);
491 ConstrainedOperator *A_constrained;
492 Operator::FormConstrainedSystemOperator(ess_tdof_list, A_constrained);
493 A_constrained->EliminateRHS(true_X, true_B);
494 delete A_constrained;
495 R.MultTranspose(true_B, b);
496 hybridization->ReduceRHS(true_B, B);
497 X.SetSize(B.Size());
498 X = 0.0;
499 }
500 else
501 {
502 ext->FormLinearSystem(ess_tdof_list, x, b, A, X, B, copy_interior);
503 }
504 return;
505 }
506
507 // Finish the matrix assembly and perform BC elimination, storing the
508 // eliminated part of the matrix.
509 FormSystemMatrix(ess_tdof_list, A);
510
511 // Transform the system and perform the elimination in B, based on the
512 // essential BC values from x. Restrict the BC part of x in X, and set the
513 // non-BC part to zero. Since there is no good initial guess for the Lagrange
514 // multipliers, set X = 0.0 for hybridization.
515 if (static_cond)
516 {
517 // Schur complement reduction to the exposed dofs
518 static_cond->ReduceSystem(x, b, X, B, copy_interior);
519 }
520 else if (hybridization)
521 {
522 // Reduction to the Lagrange multipliers system
523 HypreParVector true_X(pfes), true_B(pfes);
524 P.MultTranspose(b, true_B);
525 R.Mult(x, true_X);
526 ParallelEliminateTDofsInRHS(ess_tdof_list, true_X, true_B);
527 R.MultTranspose(true_B, b);
528 hybridization->ReduceRHS(true_B, B);
529 X.SetSize(B.Size());
530 X = 0.0;
531 }
532 else
533 {
534 // Variational restriction with P
535 X.SetSize(P.Width());
536 B.SetSize(X.Size());
537 P.MultTranspose(b, B);
538 R.Mult(x, X);
539 ParallelEliminateTDofsInRHS(ess_tdof_list, X, B);
540 if (!copy_interior) { X.SetSubVectorComplement(ess_tdof_list, 0.0); }
541 }
542}
543
546{
547 if (ext)
548 {
549 if (hybridization)
550 {
551 const int remove_zeros = 0;
552 Finalize(remove_zeros);
553 hybridization->GetParallelMatrix(A);
554 }
555 else
556 {
557 ext->FormSystemMatrix(ess_tdof_list, A);
558 }
559 return;
560 }
561
562 // Finish the matrix assembly and perform BC elimination, storing the
563 // eliminated part of the matrix.
564 if (static_cond)
565 {
566 if (!static_cond->HasEliminatedBC())
567 {
568 static_cond->SetEssentialTrueDofs(ess_tdof_list);
569 static_cond->Finalize();
570 static_cond->EliminateReducedTrueDofs(Matrix::DIAG_ONE);
571 }
572 static_cond->GetParallelMatrix(A);
573 }
574 else
575 {
576 if (mat)
577 {
578 const int remove_zeros = 0;
579 Finalize(remove_zeros);
580 MFEM_VERIFY(p_mat.Ptr() == NULL && p_mat_e.Ptr() == NULL,
581 "The ParBilinearForm must be updated with Update() before "
582 "re-assembling the ParBilinearForm.");
584 delete mat;
585 mat = NULL;
586 delete mat_e;
587 mat_e = NULL;
588 ParallelEliminateTDofs(ess_tdof_list);
589 }
590 if (hybridization)
591 {
592 hybridization->GetParallelMatrix(A);
593 }
594 else
595 {
596 A = p_mat;
597 }
598 }
599}
600
602 const Vector &X, const Vector &b, Vector &x)
603{
604 if (ext && !hybridization)
605 {
606 ext->RecoverFEMSolution(X, b, x);
607 return;
608 }
609
610 const Operator &P = *pfes->GetProlongationMatrix();
611
612 if (static_cond)
613 {
614 // Private dofs back solve
615 static_cond->ComputeSolution(b, X, x);
616 }
617 else if (hybridization)
618 {
619 // Primal unknowns recovery
620 HypreParVector true_X(pfes), true_B(pfes);
621 P.MultTranspose(b, true_B);
623 R.Mult(x, true_X); // get essential b.c. from x
624 hybridization->ComputeSolution(true_B, X, true_X);
625 x.SetSize(P.Height());
626 P.Mult(true_X, x);
627 }
628 else
629 {
630 // Apply conforming prolongation
632 P.Mult(X, x);
633 }
634}
635
637{
639
640 if (nfes)
641 {
642 pfes = dynamic_cast<ParFiniteElementSpace *>(nfes);
643 MFEM_VERIFY(pfes != NULL, "nfes must be a ParFiniteElementSpace!");
644 }
645
646 p_mat.Clear();
647 p_mat_e.Clear();
648}
649
651{
652 const int trial_nbr_size = trial_pfes->GetFaceNbrVSize();
653 const int test_nbr_size = test_pfes->GetFaceNbrVSize();
654
655 if (keep_nbr_block)
656 {
657 mat = new SparseMatrix(height + test_nbr_size, width + trial_nbr_size);
658 }
659 else
660 {
661 mat = new SparseMatrix(height, width + trial_nbr_size);
662 }
663}
664
666{
667 ParMesh *pmesh = trial_pfes->GetParMesh();
669 Array<int> tr_vdofs1, tr_vdofs2, tr_vdofs_all;
670 Array<int> te_vdofs1, te_vdofs2, te_vdofs_all;
672
673 int nfaces = pmesh->GetNSharedFaces();
674 for (int i = 0; i < nfaces; i++)
675 {
676 T = pmesh->GetSharedFaceTransformations(i);
677 int Elem2NbrNo = T->Elem2No - pmesh->GetNE();
678 trial_pfes->GetElementVDofs(T->Elem1No, tr_vdofs1);
679 test_pfes->GetElementVDofs(T->Elem1No, te_vdofs1);
680 trial_pfes->GetFaceNbrElementVDofs(Elem2NbrNo, tr_vdofs2);
681 test_pfes->GetFaceNbrElementVDofs(Elem2NbrNo, te_vdofs2);
682
683 tr_vdofs1.Copy(tr_vdofs_all);
684 for (int j = 0; j < tr_vdofs2.Size(); j++)
685 {
686 if (tr_vdofs2[j] >= 0)
687 {
688 tr_vdofs2[j] += width;
689 }
690 else
691 {
692 tr_vdofs2[j] -= width;
693 }
694 }
695 tr_vdofs_all.Append(tr_vdofs2);
696
697 if (keep_nbr_block)
698 {
699 te_vdofs1.Copy(te_vdofs_all);
700 for (int j = 0; j < te_vdofs2.Size(); j++)
701 {
702 if (te_vdofs2[j] >= 0)
703 {
704 te_vdofs2[j] += height;
705 }
706 else
707 {
708 te_vdofs2[j] -= height;
709 }
710 }
711 te_vdofs_all.Append(te_vdofs2);
712 }
713
714 for (int k = 0; k < interior_face_integs.Size(); k++)
715 {
717 AssembleFaceMatrix(*trial_pfes->GetFE(T->Elem1No),
718 *test_pfes->GetFE(T->Elem1No),
719 *trial_pfes->GetFaceNbrFE(Elem2NbrNo),
720 *test_pfes->GetFaceNbrFE(Elem2NbrNo),
721 *T, elemmat);
722 if (keep_nbr_block)
723 {
724 mat->AddSubMatrix(te_vdofs_all, tr_vdofs_all, elemmat, skip_zeros);
725 }
726 else
727 {
728 mat->AddSubMatrix(te_vdofs1, tr_vdofs_all, elemmat, skip_zeros);
729 }
730 }
731 }
732}
733
735{
736 if (interior_face_integs.Size())
737 {
740 if (!ext && mat == NULL)
741 {
742 pAllocMat();
743 }
744 }
745
746 MixedBilinearForm::Assemble(skip_zeros);
747
748 if (!ext && interior_face_integs.Size() > 0)
749 {
750 AssembleSharedFaces(skip_zeros);
751 }
752}
753
762
770
772 SparseMatrix *A_local)
773{
774 A.Clear();
775
776 if (A_local == NULL) { return; }
777 MFEM_VERIFY(A_local->Finalized(), "the local matrix must be finalized");
778
779 OperatorHandle dA(A.Type()), hdA;
780
781 if (interior_face_integs.Size() == 0)
782 {
783 // construct the rectangular block-diagonal matrix dA
789 A_local);
790 }
791 else
792 {
793 // handle the case when 'a' contains off-diagonal
794 const int lvrows = test_pfes->GetVSize();
795 const int lvcols = trial_pfes->GetVSize();
796 const HYPRE_BigInt *face_nbr_glob_lcol = trial_pfes->GetFaceNbrGlobalDofMap();
797 const HYPRE_BigInt lcol_offset = trial_pfes->GetMyDofOffset();
798
799 Array<HYPRE_BigInt> glob_J(A_local->NumNonZeroElems());
800 const int *J = A_local->GetJ();
801 for (int i = 0; i < glob_J.Size(); i++)
802 {
803 if (J[i] < lvcols)
804 {
805 glob_J[i] = J[i] + lcol_offset;
806 }
807 else
808 {
809 glob_J[i] = face_nbr_glob_lcol[J[i] - lvcols];
810 }
811 }
812
813 // TODO - construct dA directly in the A format
814 hdA.Reset(
816 trial_pfes->GlobalVSize(), A_local->GetI(), glob_J,
817 A_local->GetData(), test_pfes->GetDofOffsets(),
819 // - hdA owns the new HypreParMatrix
820 // - the above constructor copies all input arrays
821 glob_J.DeleteAll();
822 dA.ConvertFrom(hdA);
823 }
824
825 OperatorHandle P_test(A.Type()), P_trial(A.Type());
826
827 // TODO - construct the Dof_TrueDof_Matrix directly in the required format.
828 P_test.ConvertFrom(test_pfes->Dof_TrueDof_Matrix());
830
831 A.MakeRAP(P_test, dA, P_trial);
832}
833
834/// Compute y += a (P^t A P) x, where x and y are vectors on the true dofs
836 const real_t a) const
837{
838 if (Xaux.ParFESpace() != trial_pfes)
839 {
842 }
843
844 Xaux.Distribute(&x);
845 mat->Mult(Xaux, Yaux);
847}
848
850 const Array<int> &bdr_attr_is_ess)
851{
852 Array<int> trial_tdof_list;
853 trial_pfes->GetEssentialTrueDofs(bdr_attr_is_ess, trial_tdof_list);
854
855 ParallelEliminateTrialTDofs(trial_tdof_list);
856}
857
859 const Array<int> &trial_tdof_list)
860{
861 HypreParMatrix *temp = p_mat.As<HypreParMatrix>()->EliminateCols(
862 trial_tdof_list);
863 p_mat_e.Reset(temp, true);
864}
865
867 const Array<int> &trial_tdof_list, const Vector &x, Vector &b)
868{
869 p_mat_e.As<HypreParMatrix>()->Mult(-1.0, x, 1.0, b);
870}
871
873 const Array<int> &bdr_attr_is_ess)
874{
875 Array<int> test_tdof_list;
876 test_pfes->GetEssentialTrueDofs(bdr_attr_is_ess, test_tdof_list);
877
878 ParallelEliminateTestTDofs(test_tdof_list);
879}
880
882 const Array<int> &test_tdof_list)
883{
884 p_mat.As<HypreParMatrix>()->EliminateRows(test_tdof_list);
885}
886
888 const Array<int>
889 &trial_tdof_list,
890 const Array<int> &test_tdof_list,
892{
893 if (ext)
894 {
895 ext->FormRectangularSystemOperator(trial_tdof_list, test_tdof_list, A);
896 return;
897 }
898
899 if (mat)
900 {
901 Finalize();
903 delete mat;
904 mat = NULL;
905 delete mat_e;
906 mat_e = NULL;
907 ParallelEliminateTrialTDofs(trial_tdof_list);
908 ParallelEliminateTestTDofs(test_tdof_list);
909 }
910
911 A = p_mat;
912}
913
915 const Array<int>
916 &trial_tdof_list,
917 const Array<int> &test_tdof_list, Vector &x,
918 Vector &b, OperatorHandle &A, Vector &X,
919 Vector &B)
920{
921 if (ext)
922 {
923 ext->FormRectangularLinearSystem(trial_tdof_list, test_tdof_list,
924 x, b, A, X, B);
925 return;
926 }
927
928 FormRectangularSystemMatrix(trial_tdof_list, test_tdof_list, A);
929
930 const Operator *test_P = test_pfes->GetProlongationMatrix();
931 const SparseMatrix *trial_R = trial_pfes->GetRestrictionMatrix();
932
935 test_P->MultTranspose(b, B);
936 trial_R->Mult(x, X);
937
938 ParallelEliminateTrialTDofsInRHS(trial_tdof_list, X, B);
939 B.SetSubVector(test_tdof_list, 0.0);
940}
941
943{
944 MFEM_ASSERT(mat, "Matrix is not assembled");
945 MFEM_ASSERT(mat->Finalized(), "Matrix is not finalized");
949 delete RA;
950 return RAP;
951}
952
954{
955 // construct the rectangular block-diagonal matrix dA
956 OperatorHandle dA(A.Type());
962 mat);
963
965 OperatorHandle R_test_transpose(A.Type());
966 R_test_transpose.MakeRectangularBlockDiag(range_fes->GetComm(),
971 Rt);
972
973 // TODO - construct the Dof_TrueDof_Matrix directly in the required format.
974 OperatorHandle P_trial(A.Type());
976
977 A.MakeRAP(R_test_transpose, dA, P_trial);
978 delete Rt;
979}
980
982{
983 if (ext)
984 {
985 Array<int> empty;
986 ext->FormRectangularSystemOperator(empty, empty, A);
987 return;
988 }
989
990 mfem_error("not implemented!");
991}
992
994const
995{
996 MFEM_VERIFY(mat->Finalized(), "Local matrix needs to be finalized for "
997 "GetParBlocks");
998
1000
1002
1003 RLP->GetBlocks(blocks,
1006
1007 delete RLP;
1008}
1009
1010}
1011
1012#endif
Dynamic 2D array using row-major layout.
Definition array.hpp:430
void SetSize(int m, int n)
Set the 2D array size to m x n.
Definition array.hpp:445
int Size() const
Return the logical size of the array.
Definition array.hpp:166
void DeleteAll()
Delete the whole array.
Definition array.hpp:1033
int Append(const T &el)
Append element 'el' to array, resize if necessary.
Definition array.hpp:912
void Copy(Array &copy) const
Create a copy of the internal array to the provided copy.
Definition array.hpp:1042
virtual void Update(FiniteElementSpace *nfes=NULL)
Update the FiniteElementSpace and delete all data associated with the old one.
void Finalize(int skip_zeros=1) override
Finalizes the matrix initialization if the AssemblyLevel is AssemblyLevel::LEGACY....
void Assemble(int skip_zeros=1)
Assembles the form i.e. sums over all domain/bdr integrators.
real_t InnerProduct(const Vector &x, const Vector &y) const
Compute .
Array< BilinearFormIntegrator * > interior_face_integs
Set of interior face Integrators to be applied.
SparseMatrix * mat
Sparse matrix to be associated with the form. Owned.
std::unique_ptr< StaticCondensation > static_cond
FiniteElementSpace * fes
FE space on which the form lives. Not owned.
std::unique_ptr< BilinearFormExtension > ext
Extension for supporting Full Assembly (FA), Element Assembly (EA),Partial Assembly (PA),...
std::unique_ptr< Hybridization > hybridization
SparseMatrix * mat_e
Sparse Matrix used to store the eliminations from the b.c. Owned. .
Square Operator for imposing essential boundary conditions using only the action, Mult(),...
void EliminateRHS(const Vector &x, Vector &b) const
Eliminate "essential boundary condition" values specified in x from the given right-hand side b.
Definition operator.cpp:559
Data type dense matrix using column-major storage.
Definition densemat.hpp:24
A specialized ElementTransformation class representing a face and its two neighboring elements.
Definition eltrans.hpp:750
Class FiniteElementSpace - responsible for providing FEM view of the mesh, mainly managing the set of...
Definition fespace.hpp:208
const Table & GetElementToDofTable() const
Return a reference to the internal Table that stores the lists of scalar dofs, for each mesh element,...
Definition fespace.hpp:1280
virtual int GetTrueVSize() const
Return the number of vector true (conforming) dofs.
Definition fespace.hpp:829
virtual const Operator * GetProlongationMatrix() const
Definition fespace.hpp:696
bool Conforming() const
Definition fespace.hpp:650
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 ...
Definition fespace.cpp:304
Ordering::Type GetOrdering() const
Return the ordering method.
Definition fespace.hpp:854
Mesh * GetMesh() const
Returns the mesh.
Definition fespace.hpp:644
int GetVSize() const
Return the number of vector dofs, i.e. GetNDofs() x GetVDim().
Definition fespace.hpp:826
int GetVDim() const
Returns the vector dimension of the finite element space.
Definition fespace.hpp:819
Wrapper for hypre's ParCSR matrix class.
Definition hypre.hpp:419
void AbsMultTranspose(real_t a, const Vector &x, real_t b, Vector &y) const
Computes y = a * |At| * x + b * y, using entry-wise absolute values of the transpose of the matrix A.
Definition hypre.cpp:2025
HYPRE_Int MultTranspose(HypreParVector &x, HypreParVector &y, real_t alpha=1.0, real_t beta=0.0) const
Computes y = alpha * A^t * x + beta * y.
Definition hypre.cpp:1999
HypreParMatrix * LeftDiagMult(const SparseMatrix &D, HYPRE_BigInt *row_starts=NULL) const
Multiply the HypreParMatrix on the left by a block-diagonal parallel matrix D and return the result a...
Definition hypre.cpp:2042
void EliminateRowsCols(const Array< int > &rows_cols, const HypreParVector &X, HypreParVector &B)
Definition hypre.cpp:2399
HYPRE_Int Mult(HypreParVector &x, HypreParVector &y, real_t alpha=1.0, real_t beta=0.0) const
Computes y = alpha * A * x + beta * y.
Definition hypre.cpp:1863
void GetBlocks(Array2D< HypreParMatrix * > &blocks, bool interleaved_rows=false, bool interleaved_cols=false) const
Definition hypre.cpp:1708
Wrapper for hypre's parallel vector class.
Definition hypre.hpp:230
Class used by MFEM to store pointers to host and/or device memory.
int GetNE() const
Returns number of elements.
Definition mesh.hpp:1377
Table * GetFaceToElementTable() const
Definition mesh.cpp:7801
void Assemble(int skip_zeros=1)
void Finalize(int skip_zeros=1) override
Finalizes the matrix initialization if the AssemblyLevel is AssemblyLevel::LEGACY.
Array< BilinearFormIntegrator * > interior_face_integs
Interior face integrators.
SparseMatrix * mat
Owned.
SparseMatrix * mat_e
Owned.
std::unique_ptr< MixedBilinearFormExtension > ext
void Mult(const Vector &x, Vector &y) const override
Matrix multiplication: .
Pointer to an Operator of a specified type.
Definition handle.hpp:34
OpType * As() const
Return the Operator pointer statically cast to a specified OpType. Similar to the method Get().
Definition handle.hpp:104
void EliminateRowsCols(OperatorHandle &A, const Array< int > &ess_dof_list)
Reset the OperatorHandle to be the eliminated part of A after elimination of the essential dofs ess_d...
Definition handle.cpp:255
void SetOperatorOwner(bool own=true)
Set the ownership flag for the held Operator.
Definition handle.hpp:120
void MakeRAP(OperatorHandle &Rt, OperatorHandle &A, OperatorHandle &P)
Reset the OperatorHandle to hold the product R A P, where R = Rt^t.
Definition handle.cpp:163
void ConvertFrom(OperatorHandle &A)
Convert the given OperatorHandle A to the currently set type id.
Definition handle.cpp:203
void MakePtAP(OperatorHandle &A, OperatorHandle &P)
Reset the OperatorHandle to hold the product P^t A P.
Definition handle.cpp:124
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...
Definition handle.cpp:61
Operator * Ptr() const
Access the underlying Operator pointer.
Definition handle.hpp:87
void Clear()
Clear the OperatorHandle, deleting the held Operator (if owned), while leaving the type id unchanged.
Definition handle.hpp:124
void Reset(OpType *A, bool own_A=true)
Reset the OperatorHandle to the given OpType pointer, A.
Definition handle.hpp:145
void EliminateBC(const OperatorHandle &A_e, const Array< int > &ess_dof_list, const Vector &X, Vector &B) const
Eliminate essential dofs from the solution X into the r.h.s. B.
Definition handle.cpp:344
Operator::Type Type() const
Get the currently set operator type id.
Definition handle.hpp:99
void MakeRectangularBlockDiag(MPI_Comm comm, HYPRE_BigInt glob_num_rows, HYPRE_BigInt glob_num_cols, HYPRE_BigInt *row_starts, HYPRE_BigInt *col_starts, SparseMatrix *diag)
Reset the OperatorHandle to hold a parallel rectangular block-diagonal matrix using the currently set...
Definition handle.cpp:92
Abstract operator.
Definition operator.hpp:25
void FormRectangularLinearSystem(const Array< int > &trial_tdof_list, const Array< int > &test_tdof_list, Vector &x, Vector &b, Operator *&A, Vector &X, Vector &B)
Form a column-constrained linear system using a matrix-free approach.
Definition operator.cpp:131
void FormConstrainedSystemOperator(const Array< int > &ess_tdof_list, ConstrainedOperator *&Aout)
see FormSystemOperator()
Definition operator.cpp:197
int width
Dimension of the input / number of columns in the matrix.
Definition operator.hpp:28
int Height() const
Get the height (size of output) of the Operator. Synonym with NumRows().
Definition operator.hpp:66
int height
Dimension of the output / number of rows in the matrix.
Definition operator.hpp:27
virtual void Mult(const Vector &x, Vector &y) const =0
Operator application: y=A(x).
@ DIAG_ONE
Set the diagonal value to one.
Definition operator.hpp:50
int Width() const
Get the width (size of input) of the Operator. Synonym with NumCols().
Definition operator.hpp:72
@ Hypre_ParCSR
ID for class HypreParMatrix.
Definition operator.hpp:299
virtual void RecoverFEMSolution(const Vector &X, const Vector &b, Vector &x)
Reconstruct a solution vector x (e.g. a GridFunction) from the solution X of a constrained linear sys...
Definition operator.cpp:148
Type GetType() const
Return the type ID of the Operator class.
Definition operator.hpp:319
virtual void AssembleDiagonal(Vector &diag) const
Computes the diagonal entries into diag. Typically, this operation only makes sense for linear Operat...
Definition operator.hpp:143
virtual void MultTranspose(const Vector &x, Vector &y) const
Action of the transpose operator: y=A^t(x). The default behavior in class Operator is to generate an ...
Definition operator.hpp:100
Vector Xaux
Auxiliary vectors used in TrueAddMult(): L-, L-, and T-vector, resp.
ParFiniteElementSpace * pfes
Points to the same object as fes.
void ParallelRAP(SparseMatrix &loc_A, OperatorHandle &A, bool steal_loc_A=false)
Compute parallel RAP operator and store it in A as a HypreParMatrix.
HypreParMatrix * ParallelAssembleInternalMatrix()
Returns the matrix assembled on the true dofs, i.e. P^t A P.
void RecoverFEMSolution(const Vector &X, const Vector &b, Vector &x) override
HypreParMatrix * ParallelAssemble()
Returns the matrix assembled on the true dofs, i.e. P^t A P.
void ParallelEliminateEssentialBC(const Array< int > &bdr_attr_is_ess, HypreParMatrix &A, const HypreParVector &X, HypreParVector &B) const
Eliminate essential boundary DOFs from a parallel assembled system.
real_t ParInnerProduct(const ParGridFunction &x, const ParGridFunction &y) const
Compute .
void Assemble(int skip_zeros=1)
Assemble the local matrix.
void FormSystemMatrix(const Array< int > &ess_tdof_list, OperatorHandle &A) override
Form the linear system matrix A, see FormLinearSystem() for details.
void AssembleSharedFaces(int skip_zeros=1)
void ParallelEliminateTDofsInRHS(const Array< int > &tdofs, const Vector &x, Vector &b)
Use the stored eliminated part of the parallel system matrix for elimination of boundary conditions i...
void Update(FiniteElementSpace *nfes=NULL) override
Update the FiniteElementSpace and delete all data associated with the old one.
HypreParMatrix * ParallelEliminateTDofs(const Array< int > &tdofs_list, HypreParMatrix &A) const
Eliminate essential true DOFs from a parallel assembled matrix A.
ParFiniteElementSpace * ParFESpace() const
Return the parallel FE space associated with the ParBilinearForm.
void AssembleDiagonal(Vector &diag) const override
Assemble the diagonal of the bilinear form into diag. Note that diag is a true-dof Vector.
void FormLinearSystem(const Array< int > &ess_tdof_list, Vector &x, Vector &b, OperatorHandle &A, Vector &X, Vector &B, int copy_interior=0) override
Form the linear system A X = B, corresponding to this bilinear form and the linear form b(....
real_t TrueInnerProduct(const ParGridFunction &x, const ParGridFunction &y) const
Compute on true dofs (grid function version)
void TrueAddMult(const Vector &x, Vector &y, const real_t a=1.0) const
Compute y += a (P^t A P) x, where x and y are vectors on the true dofs.
void GetParBlocks(Array2D< HypreParMatrix * > &blocks) const
ParFiniteElementSpace * range_fes
Points to the same object as test_fes.
HypreParMatrix * ParallelAssemble() const
Returns the matrix "assembled" on the true dofs.
ParFiniteElementSpace * domain_fes
Points to the same object as trial_fes.
virtual void FormRectangularSystemMatrix(OperatorHandle &A)
Return in A a parallel (on truedofs) version of this operator.
Abstract parallel finite element space.
Definition pfespace.hpp:31
MPI_Comm GetComm() const
Definition pfespace.hpp:337
HYPRE_BigInt * GetTrueDofOffsets() const
Definition pfespace.hpp:346
void GetEssentialTrueDofs(const Array< int > &bdr_attr_is_ess, Array< int > &ess_tdof_list, int component=-1) const override
HYPRE_BigInt GlobalVSize() const
Definition pfespace.hpp:347
HYPRE_BigInt GlobalTrueVSize() const
Definition pfespace.hpp:349
int GetTrueVSize() const override
Return the number of local vector true dofs.
Definition pfespace.hpp:353
const FiniteElement * GetFaceNbrFE(int i, int ndofs=0) const
HYPRE_BigInt GetMyDofOffset() const
HYPRE_BigInt * GetDofOffsets() const
Definition pfespace.hpp:345
const Operator * GetProlongationMatrix() const override
HypreParMatrix * Dof_TrueDof_Matrix() const
The true dof-to-dof interpolation matrix.
Definition pfespace.hpp:391
void GetFaceNbrElementVDofs(int i, Array< int > &vdofs, DofTransformation &doftrans) const
const HYPRE_BigInt * GetFaceNbrGlobalDofMap()
Definition pfespace.hpp:485
const SparseMatrix * GetRestrictionMatrix() const override
Get the R matrix which restricts a local dof vector to true dof vector.
Definition pfespace.hpp:470
ParMesh * GetParMesh() const
Definition pfespace.hpp:341
int TrueVSize() const
Obsolete, kept for backward compatibility.
Definition pfespace.hpp:528
const FiniteElement * GetFE(int i) const override
Definition pfespace.cpp:632
Class for parallel grid function.
Definition pgridfunc.hpp:50
ParFiniteElementSpace * ParFESpace() const
void ParallelProject(Vector &tv) const
Returns the vector restricted to the true dofs.
void SetSpace(FiniteElementSpace *f) override
Associate a new FiniteElementSpace with the ParGridFunction.
Definition pgridfunc.cpp:91
void Distribute(const Vector *tv)
Class for parallel meshes.
Definition pmesh.hpp:34
int GetNSharedFaces() const
Return the number of shared faces (3D), edges (2D), vertices (1D)
Definition pmesh.cpp:3164
Table * GetFaceToAllElementTable() const
Definition pmesh.cpp:2849
FaceElementTransformations * GetSharedFaceTransformations(int sf, bool fill2=true)
Get the FaceElementTransformations for the given shared face (edge 2D) using the shared face index sf...
Definition pmesh.cpp:2933
void Assemble(int skip_zeros=1)
Assemble the local matrix.
ParGridFunction Xaux
Auxiliary objects used in TrueAddMult().
void FormRectangularSystemMatrix(const Array< int > &trial_tdof_list, const Array< int > &test_tdof_list, OperatorHandle &A) override
Return in A a parallel (on truedofs) version of this operator.
void ParallelEliminateTrialTDofsInRHS(const Array< int > &trial_tdof_list, const Vector &X, Vector &B)
Use the stored eliminated part of the parallel system matrix for elimination of boundary conditions i...
void ParallelEliminateTrialEssentialBC(const Array< int > &bdr_attr_is_ess)
Eliminate essential boundary trial DOFs from the parallel system matrix.
OperatorHandle p_mat
Matrix and eliminated matrix.
void TrueAddMult(const Vector &x, Vector &y, const real_t a=1.0) const
Compute y += a (P^t A P) x, where x and y are vectors on the true dofs.
void AssembleSharedFaces(int skip_zeros=1)
HypreParMatrix * ParallelAssemble()
Returns the matrix assembled on the true dofs, i.e. P_test^t A P_trial.
ParFiniteElementSpace * test_pfes
Points to the same object as test_fes.
ParFiniteElementSpace * trial_pfes
Points to the same object as trial_fes.
void ParallelEliminateTestEssentialBC(const Array< int > &bdr_attr_is_ess)
Eliminate essential boundary test DOFs from the parallel system matrix.
void FormRectangularLinearSystem(const Array< int > &trial_tdof_list, const Array< int > &test_tdof_list, Vector &x, Vector &b, OperatorHandle &A, Vector &X, Vector &B) override
Form the parallel linear system A X = B, corresponding to this mixed bilinear form and the linear for...
void ParallelEliminateTestTDofs(const Array< int > &test_tdof_list)
Eliminate essential test true DOFs from the parallel system matrix.
void ParallelEliminateTrialTDofs(const Array< int > &trial_tdof_list)
Eliminate essential trial true DOFs from the parallel system matrix.
HypreParMatrix * ParallelAssembleInternalMatrix()
Returns the matrix assembled on the true dofs, i.e. P_test^t A P_trial.
Data type sparse matrix.
Definition sparsemat.hpp:51
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.
bool Finalized() const
Returns whether or not CSR format has been finalized.
void AddSubMatrix(const Array< int > &rows, const Array< int > &cols, const DenseMatrix &subm, int skip_zeros=1)
void Mult(const Vector &x, Vector &y) const override
Matrix vector multiplication.
real_t * GetData()
Return the element data, i.e. the array A.
int * GetJ()
Return the array J.
int * GetI()
Return the array I.
Table stores the connectivity of elements of TYPE I to elements of TYPE II. For example,...
Definition table.hpp:43
void LoseData()
Releases ownership of and null-ifies the data.
Definition table.hpp:184
int * GetJ()
Definition table.hpp:128
void Clear()
Definition table.cpp:420
int Size() const
Returns the number of TYPE I elements.
Definition table.hpp:103
int * GetI()
Definition table.hpp:127
void SetDims(int rows, int nnz)
Set the rows and the number of all connections for the table.
Definition table.cpp:188
Vector data type.
Definition vector.hpp:82
void SetSubVector(const Array< int > &dofs, const real_t value)
Set the entries listed in dofs to the given value.
Definition vector.cpp:702
int Size() const
Returns the size of the vector.
Definition vector.hpp:234
void SetSize(int s)
Resize the vector to size s.
Definition vector.hpp:584
void SetSubVectorComplement(const Array< int > &dofs, const real_t val)
Set all vector entries NOT in the dofs Array to the given val.
Definition vector.cpp:854
Vector & Add(const real_t a, const Vector &Va)
(*this) += a * Va
Definition vector.cpp:326
HYPRE_Int HYPRE_BigInt
real_t b
Definition lissajous.cpp:42
real_t a
Definition lissajous.cpp:41
MemoryType GetHypreMemoryType()
The MemoryType used by MFEM when allocating arrays for Hypre objects.
Definition hypre.hpp:203
void mfem_error(const char *msg)
Definition error.cpp:154
void Mult(const Table &A, const Table &B, Table &C)
C = A * B (as boolean matrices)
Definition table.cpp:505
void Transpose(const Table &A, Table &At, int ncols_A_)
Transpose a Table.
Definition table.cpp:443
real_t InnerProduct(HypreParVector *x, HypreParVector *y)
Definition hypre.cpp:468
void RAP(const DenseMatrix &A, const DenseMatrix &P, DenseMatrix &RAP)
bool IsIdentityProlongation(const Operator *P)
Definition operator.hpp:829
void HypreStealOwnership(HypreParMatrix &A_hyp, SparseMatrix &A_diag)
Make A_hyp steal ownership of its diagonal part A_diag.
Definition hypre.cpp:2912
float real_t
Definition config.hpp:46
Helper struct to convert a C++ type to an MPI type.