MFEM v4.10.0
Finite element discretization library
Loading...
Searching...
No Matches
bilinearform.cpp
Go to the documentation of this file.
1// Copyright (c) 2010-2026, 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// Implementation of class BilinearForm
13
14#include "fem.hpp"
15#include "../general/device.hpp"
16#include "../mesh/nurbs.hpp"
17#include <cmath>
18
19namespace mfem
20{
21
23{
24 if (static_cond) { return; }
25
26 if (precompute_sparsity == 0 || fes->GetVDim() > 1)
27 {
28 mat = new SparseMatrix(height);
29 return;
30 }
31
32 const Table &elem_dof = fes->GetElementToDofTable();
33 Table dof_dof;
34
35 if (interior_face_integs.Size() > 0)
36 {
37 // the sparsity pattern is defined from the map: face->element->dof
38 Table face_dof, dof_face;
39 {
40 Table *face_elem = fes->GetMesh()->GetFaceToElementTable();
41 mfem::Mult(*face_elem, elem_dof, face_dof);
42 delete face_elem;
43 }
44 Transpose(face_dof, dof_face, height);
45 mfem::Mult(dof_face, face_dof, dof_dof);
46 }
47 else
48 {
49 // the sparsity pattern is defined from the map: element->dof
50 Table dof_elem;
51 Transpose(elem_dof, dof_elem, height);
52 mfem::Mult(dof_elem, elem_dof, dof_dof);
53 }
54
55 dof_dof.SortRows();
56
57 int *I = dof_dof.GetI();
58 int *J = dof_dof.GetJ();
59 real_t *data = Memory<real_t>(I[height]);
60
61 mat = new SparseMatrix(I, J, data, height, height, true, true, true);
62 *mat = 0.0;
63
64 dof_dof.LoseData();
65}
66
68 : Matrix (f->GetVSize())
69{
70 fes = f;
72 mat = mat_e = NULL;
73 extern_bfs = 0;
76
78 batch = 1;
79}
80
108
110{
111 if (ext)
112 {
113 MFEM_ABORT("the assembly level has already been set!");
114 }
115 assembly = assembly_level;
116 switch (assembly)
117 {
119 break;
121 SetDiagonalPolicy( DIAG_ONE ); // Only diagonal policy supported on device
122 ext.reset(new FABilinearFormExtension(this));
123 break;
125 ext.reset(new EABilinearFormExtension(this));
126 break;
128 ext.reset(new PABilinearFormExtension(this));
129 break;
131 ext.reset(new MFBilinearFormExtension(this));
132 break;
133 default:
134 MFEM_ABORT("BilinearForm: unknown assembly level");
135 }
136}
137
139{
141 {
142 static_cond.reset();
143 MFEM_WARNING("Static condensation not supported for this assembly level");
144 return;
145 }
147 if (static_cond->ReducesTrueVSize())
148 {
149 bool symmetric = false; // TODO
150 bool block_diagonal = false; // TODO
151 static_cond->Init(symmetric, block_diagonal);
152 }
153 else
154 {
155 static_cond.reset();
156 }
157}
158
160 BilinearFormIntegrator *constr_integ,
162{
164 {
165 delete constr_integ;
166 hybridization.reset();
167 MFEM_WARNING("Hybridization not supported for this assembly level");
168 return;
169 }
170 hybridization.reset(new Hybridization(fes, constr_space));
172 {
173 hybridization->EnableDeviceExecution();
174 }
175 hybridization->SetConstraintIntegrator(constr_integ);
177}
178
179void BilinearForm::UseSparsity(int *I, int *J, bool isSorted)
180{
181 if (static_cond) { return; }
182
183 if (mat)
184 {
185 if (mat->Finalized() && mat->GetI() == I && mat->GetJ() == J)
186 {
187 return; // mat is already using the given sparsity
188 }
189 delete mat;
190 }
191 height = width = fes->GetVSize();
192 mat = new SparseMatrix(I, J, NULL, height, width, false, true, isSorted);
193}
194
196{
197 MFEM_ASSERT(A.Height() == fes->GetVSize() && A.Width() == fes->GetVSize(),
198 "invalid matrix A dimensions: "
199 << A.Height() << " x " << A.Width());
200 MFEM_ASSERT(A.Finalized(), "matrix A must be Finalized");
201
202 UseSparsity(A.GetI(), A.GetJ(), A.ColumnsAreSorted());
203}
204
206{
207 return mat -> Elem(i,j);
208}
209
210const real_t& BilinearForm::Elem (int i, int j) const
211{
212 return mat -> Elem(i,j);
213}
214
216{
217 return mat -> Inverse();
218}
219
220void BilinearForm::Finalize (int skip_zeros)
221{
223 {
224 if (!static_cond) { mat->Finalize(skip_zeros); }
225 if (mat_e) { mat_e->Finalize(skip_zeros); }
226 if (static_cond) { static_cond->Finalize(); }
227 }
228 if (hybridization) { hybridization->Finalize(); }
229}
230
232{
233 domain_integs.Append(bfi);
234 domain_integs_marker.Append(NULL); // NULL marker means apply everywhere
235}
236
238 Array<int> &elem_marker)
239{
240 domain_integs.Append(bfi);
241 domain_integs_marker.Append(&elem_marker);
242}
243
245{
246 boundary_integs.Append (bfi);
247 boundary_integs_marker.Append(NULL); // NULL marker means apply everywhere
248}
249
251 Array<int> &bdr_marker)
252{
253 boundary_integs.Append (bfi);
254 boundary_integs_marker.Append(&bdr_marker);
255}
256
261
263{
264 boundary_face_integs.Append(bfi);
265 // NULL marker means apply everywhere
266 boundary_face_integs_marker.Append(NULL);
267}
268
270 Array<int> &bdr_marker)
271{
272 boundary_face_integs.Append(bfi);
273 boundary_face_integs_marker.Append(&bdr_marker);
274}
275
277{
279 {
280 elmat.SetSize(element_matrices->SizeI(), element_matrices->SizeJ());
281 elmat = element_matrices->GetData(i);
282 return;
283 }
284
285 const FiniteElement &fe = *fes->GetFE(i);
286
287 if (domain_integs.Size())
288 {
290 domain_integs[0]->AssembleElementMatrix(fe, *eltrans, elmat);
291 for (int k = 1; k < domain_integs.Size(); k++)
292 {
293 domain_integs[k]->AssembleElementMatrix(fe, *eltrans, elemmat);
294 elmat += elemmat;
295 }
296 }
297 else
298 {
299 const int ndof = fe.GetDof() * fes->GetVDim();
300 elmat.SetSize(ndof);
301 elmat = 0.0;
302 }
303}
304
306{
307 const FiniteElement &be = *fes->GetBE(i);
308
309 if (boundary_integs.Size())
310 {
312 boundary_integs[0]->AssembleElementMatrix(be, *eltrans, elmat);
313 for (int k = 1; k < boundary_integs.Size(); k++)
314 {
315 boundary_integs[k]->AssembleElementMatrix(be, *eltrans, elemmat);
316 elmat += elemmat;
317 }
318 }
319 else
320 {
321 const int ndof = be.GetDof() * fes->GetVDim();
322 elmat.SetSize(ndof);
323 elmat = 0.0;
324 }
325}
326
328{
330 Mesh *mesh = fes -> GetMesh();
331 tr = mesh -> GetFaceElementTransformations (i);
332
333 const FiniteElement *fe1, *fe2;
334 fe1 = fes->GetFE(tr->Elem1No);
335 if (tr->Elem2No >= 0)
336 {
337 fe2 = fes->GetFE(tr->Elem2No);
338 }
339 else
340 {
341 // The fe2 object is really a dummy and not used on the
342 // boundaries, but we can't dereference a NULL pointer, and we don't
343 // want to actually make a fake element.
344 fe2 = fe1;
345 }
346
347 if (interior_face_integs.Size())
348 {
349 interior_face_integs[0] -> AssembleFaceMatrix (*fe1, *fe2, *tr, elmat);
350 for (int k = 1; k < interior_face_integs.Size(); k++)
351 {
352 interior_face_integs[k] -> AssembleFaceMatrix (*fe1, *fe2, *tr, elemmat);
353 elmat += elemmat;
354 }
355 }
356 else
357 {
358 int ndof = fe1->GetDof() * fes->GetVDim();
359 if (tr->Elem2No >= 0)
360 {
361 ndof += fe2->GetDof() * fes->GetVDim();
362 }
363
364 elmat.SetSize(ndof);
365 elmat = 0.0;
366 }
367}
368
370{
372 Mesh *mesh = fes -> GetMesh();
373 tr = mesh -> GetBdrFaceTransformations (i);
374
375 const FiniteElement *fe1, *fe2;
376
377 fe1 = fes -> GetFE (tr -> Elem1No);
378 // The fe2 object is really a dummy and not used on the boundaries,
379 // but we can't dereference a NULL pointer, and we don't want to
380 // actually make a fake element.
381 fe2 = fe1;
382
383 if (boundary_face_integs.Size())
384 {
385 boundary_face_integs[0] -> AssembleFaceMatrix (*fe1, *fe2, *tr, elmat);
386 for (int k = 1; k < boundary_face_integs.Size(); k++)
387 {
388 boundary_face_integs[k] -> AssembleFaceMatrix (*fe1, *fe2, *tr, elemmat);
389 elmat += elemmat;
390 }
391 }
392 else
393 {
394 int ndof = fe1->GetDof() * fes->GetVDim();
395 elmat.SetSize(ndof);
396 elmat = 0.0;
397 }
398}
399
401 int i, const DenseMatrix &elmat, int skip_zeros)
402{
403 AssembleElementMatrix(i, elmat, vdofs, skip_zeros);
404}
405
407 int i, const DenseMatrix &elmat, Array<int> &vdofs_, int skip_zeros)
408{
409 fes->GetElementVDofs(i, vdofs_);
410 if (static_cond)
411 {
412 static_cond->AssembleMatrix(i, elmat);
413 }
414 else
415 {
416 if (mat == NULL)
417 {
418 AllocMat();
419 }
420 mat->AddSubMatrix(vdofs_, vdofs_, elmat, skip_zeros);
421 if (hybridization)
422 {
423 hybridization->AssembleMatrix(i, elmat);
424 }
425 }
426}
427
429 int i, const DenseMatrix &elmat, int skip_zeros)
430{
431 AssembleBdrElementMatrix(i, elmat, vdofs, skip_zeros);
432}
433
435 int i, const DenseMatrix &elmat, Array<int> &vdofs_, int skip_zeros)
436{
437 fes->GetBdrElementVDofs(i, vdofs_);
438 if (static_cond)
439 {
440 static_cond->AssembleBdrMatrix(i, elmat);
441 }
442 else
443 {
444 if (mat == NULL)
445 {
446 AllocMat();
447 }
448 mat->AddSubMatrix(vdofs_, vdofs_, elmat, skip_zeros);
449 if (hybridization)
450 {
451 hybridization->AssembleBdrMatrix(i, elmat);
452 }
453 }
454}
455
456void BilinearForm::Assemble(int skip_zeros)
457{
458 if (ext)
459 {
460 ext->Assemble();
461 if (hybridization)
462 {
463 hybridization->AssembleElementMatrices(GetElementMatrices());
464 }
465 return;
466 }
467
468 ElementTransformation *eltrans;
469 Mesh *mesh = fes -> GetMesh();
470 DenseMatrix elmat, *elmat_p;
471
472 if (mat == NULL)
473 {
474 AllocMat();
475 }
476
477#ifdef MFEM_USE_LEGACY_OPENMP
478 int free_element_matrices = 0;
479 if (!element_matrices)
480 {
482 free_element_matrices = 1;
483 }
484#endif
485
486 if (domain_integs.Size())
487 {
488 for (int k = 0; k < domain_integs.Size(); k++)
489 {
490 if (domain_integs_marker[k] != NULL)
491 {
492 MFEM_VERIFY(domain_integs_marker[k]->Size() ==
493 (mesh->attributes.Size() ? mesh->attributes.Max() : 0),
494 "invalid element marker for domain integrator #"
495 << k << ", counting from zero");
496 }
497
498 if (domain_integs[k]->Patchwise())
499 {
500 MFEM_VERIFY(fes->GetNURBSext(), "Patchwise integration requires a "
501 << "NURBS FE space");
502 }
503 }
504
505 DofTransformation doftrans;
506 // Element-wise integration
507 for (int i = 0; i < fes -> GetNE(); i++)
508 {
509 // Set both doftrans (potentially needed to assemble the element
510 // matrix) and vdofs, which is also needed when the element matrices
511 // are pre-assembled.
512 fes->GetElementVDofs(i, vdofs, doftrans);
514 {
515 elmat_p = &(*element_matrices)(i);
516 }
517 else
518 {
519 const int elem_attr = fes->GetMesh()->GetAttribute(i);
520 eltrans = fes->GetElementTransformation(i);
521
522 elmat.SetSize(0);
523 for (int k = 0; k < domain_integs.Size(); k++)
524 {
525 if (domain_integs_marker[k]) { domain_integs_marker[k]->HostRead(); }
526 if ((domain_integs_marker[k] == NULL ||
527 (*(domain_integs_marker[k]))[elem_attr-1] == 1)
528 && !domain_integs[k]->Patchwise())
529 {
530 domain_integs[k]->AssembleElementMatrix(*fes->GetFE(i),
531 *eltrans, elemmat);
532 if (elmat.Size() == 0)
533 {
534 elmat = elemmat;
535 }
536 else
537 {
538 elmat += elemmat;
539 }
540 }
541 }
542 if (elmat.Size() == 0)
543 {
544 continue;
545 }
546 else
547 {
548 elmat_p = &elmat;
549 }
550 doftrans.TransformDual(elmat);
551 elmat_p = &elmat;
552 }
553 if (static_cond)
554 {
555 static_cond->AssembleMatrix(i, *elmat_p);
556 }
557 else
558 {
559 mat->AddSubMatrix(vdofs, vdofs, *elmat_p, skip_zeros);
560 if (hybridization)
561 {
562 hybridization->AssembleMatrix(i, *elmat_p);
563 }
564 }
565 }
566
567 // Patch-wise integration
568 if (fes->GetNURBSext())
569 {
570 for (int p=0; p<mesh->NURBSext->GetNP(); ++p)
571 {
572 bool vdofsSet = false;
573 for (int k = 0; k < domain_integs.Size(); k++)
574 {
575 if (domain_integs[k]->Patchwise())
576 {
577 if (!vdofsSet)
578 {
580 vdofsSet = true;
581 }
582
583 SparseMatrix* spmat = nullptr;
584 domain_integs[k]->AssemblePatchMatrix(p, *fes, spmat);
585 Array<int> cols;
586 Vector srow;
587
588 for (int r=0; r<spmat->Height(); ++r)
589 {
590 spmat->GetRow(r, cols, srow);
591 for (int i=0; i<cols.Size(); ++i)
592 {
593 cols[i] = vdofs[cols[i]];
594 }
595 mat->AddRow(vdofs[r], cols, srow);
596 }
597
598 delete spmat;
599 }
600 }
601 }
602 }
603 }
604
605 if (boundary_integs.Size())
606 {
607 // Which boundary attributes need to be processed?
608 Array<int> bdr_attr_marker(mesh->bdr_attributes.Size() ?
609 mesh->bdr_attributes.Max() : 0);
610 bdr_attr_marker = 0;
611 for (int k = 0; k < boundary_integs.Size(); k++)
612 {
613 if (boundary_integs_marker[k] == NULL)
614 {
615 bdr_attr_marker = 1;
616 break;
617 }
618 Array<int> &bdr_marker = *boundary_integs_marker[k];
619 MFEM_ASSERT(bdr_marker.Size() == bdr_attr_marker.Size(),
620 "invalid boundary marker for boundary integrator #"
621 << k << ", counting from zero");
622 for (int i = 0; i < bdr_attr_marker.Size(); i++)
623 {
624 bdr_attr_marker[i] |= bdr_marker[i];
625 }
626 }
627
628 DofTransformation doftrans;
629 for (int i = 0; i < fes -> GetNBE(); i++)
630 {
631 const int bdr_attr = mesh->GetBdrAttribute(i);
632 if (bdr_attr_marker[bdr_attr-1] == 0) { continue; }
633
634 const FiniteElement &be = *fes->GetBE(i);
635 fes -> GetBdrElementVDofs (i, vdofs, doftrans);
636 eltrans = fes -> GetBdrElementTransformation (i);
637 int k = 0;
638 for (; k < boundary_integs.Size(); k++)
639 {
640 if (boundary_integs_marker[k] &&
641 (*boundary_integs_marker[k])[bdr_attr-1] == 0) { continue; }
642
643 boundary_integs[k]->AssembleElementMatrix(be, *eltrans, elmat);
644 k++;
645 break;
646 }
647 for (; k < boundary_integs.Size(); k++)
648 {
649 if (boundary_integs_marker[k] &&
650 (*boundary_integs_marker[k])[bdr_attr-1] == 0) { continue; }
651
652 boundary_integs[k]->AssembleElementMatrix(be, *eltrans, elemmat);
653 elmat += elemmat;
654 }
655 doftrans.TransformDual(elmat);
656 elmat_p = &elmat;
657 if (!static_cond)
658 {
659 mat->AddSubMatrix(vdofs, vdofs, *elmat_p, skip_zeros);
660 if (hybridization)
661 {
662 hybridization->AssembleBdrMatrix(i, *elmat_p);
663 }
664 }
665 else
666 {
667 static_cond->AssembleBdrMatrix(i, *elmat_p);
668 }
669 }
670 }
671
672 if (interior_face_integs.Size())
673 {
675 Array<int> vdofs2;
676
677 int nfaces = mesh->GetNumFaces();
678 for (int i = 0; i < nfaces; i++)
679 {
680 tr = mesh -> GetInteriorFaceTransformations (i);
681 if (tr != NULL)
682 {
683 fes -> GetElementVDofs (tr -> Elem1No, vdofs);
684 fes -> GetElementVDofs (tr -> Elem2No, vdofs2);
685 vdofs.Append (vdofs2);
686 for (int k = 0; k < interior_face_integs.Size(); k++)
687 {
689 AssembleFaceMatrix(*fes->GetFE(tr->Elem1No),
690 *fes->GetFE(tr->Elem2No),
691 *tr, elemmat);
692 mat -> AddSubMatrix (vdofs, vdofs, elemmat, skip_zeros);
693 }
694 }
695 }
696 }
697
698 if (boundary_face_integs.Size())
699 {
701 const FiniteElement *fe1, *fe2;
702
703 // Which boundary attributes need to be processed?
704 Array<int> bdr_attr_marker(mesh->bdr_attributes.Size() ?
705 mesh->bdr_attributes.Max() : 0);
706 bdr_attr_marker = 0;
707 for (int k = 0; k < boundary_face_integs.Size(); k++)
708 {
709 if (boundary_face_integs_marker[k] == NULL)
710 {
711 bdr_attr_marker = 1;
712 break;
713 }
714 Array<int> &bdr_marker = *boundary_face_integs_marker[k];
715 MFEM_ASSERT(bdr_marker.Size() == bdr_attr_marker.Size(),
716 "invalid boundary marker for boundary face integrator #"
717 << k << ", counting from zero");
718 for (int i = 0; i < bdr_attr_marker.Size(); i++)
719 {
720 bdr_attr_marker[i] |= bdr_marker[i];
721 }
722 }
723
724 for (int i = 0; i < fes -> GetNBE(); i++)
725 {
726 const int bdr_attr = mesh->GetBdrAttribute(i);
727 if (bdr_attr_marker[bdr_attr-1] == 0) { continue; }
728
729 tr = mesh -> GetBdrFaceTransformations (i);
730 if (tr != NULL)
731 {
733 fes -> GetElementVDofs (tr -> Elem1No, vdofs, doftrans);
734 fe1 = fes -> GetFE (tr -> Elem1No);
735 // The fe2 object is really a dummy and not used on the boundaries,
736 // but we can't dereference a NULL pointer, and we don't want to
737 // actually make a fake element.
738 fe2 = fe1;
739 for (int k = 0; k < boundary_face_integs.Size(); k++)
740 {
742 (*boundary_face_integs_marker[k])[bdr_attr-1] == 0)
743 { continue; }
744
745 boundary_face_integs[k] -> AssembleFaceMatrix (*fe1, *fe2, *tr,
746 elemmat);
747 doftrans.TransformDual(elemmat);
748 mat -> AddSubMatrix (vdofs, vdofs, elemmat, skip_zeros);
749 }
750 }
751 }
752 }
753
754#ifdef MFEM_USE_LEGACY_OPENMP
755 if (free_element_matrices)
756 {
758 }
759#endif
760}
761
763{
764 // Do not remove zero entries to preserve the symmetric structure of the
765 // matrix which in turn will give rise to symmetric structure in the new
766 // matrix. This ensures that subsequent calls to EliminateRowCol will work
767 // correctly.
768 Finalize(0);
769 MFEM_ASSERT(mat, "the BilinearForm is not assembled");
770
772 if (!P) { return; } // conforming mesh
773
774 SparseMatrix *R = Transpose(*P);
775 SparseMatrix *RA = mfem::Mult(*R, *mat);
776 delete mat;
777 if (mat_e)
778 {
779 SparseMatrix *RAe = mfem::Mult(*R, *mat_e);
780 delete mat_e;
781 mat_e = RAe;
782 }
783 delete R;
784 mat = mfem::Mult(*RA, *P);
785 delete RA;
786 if (mat_e)
787 {
788 SparseMatrix *RAeP = mfem::Mult(*mat_e, *P);
789 delete mat_e;
790 mat_e = RAeP;
791 }
792
793 height = mat->Height();
794 width = mat->Width();
795}
796
798{
799 MFEM_ASSERT(diag.Size() == fes->GetTrueVSize(),
800 "Vector for holding diagonal has wrong size!");
802 if (!ext)
803 {
804 MFEM_ASSERT(mat, "the BilinearForm is not assembled!");
805 MFEM_ASSERT(cP == nullptr || mat->Height() == cP->Width(),
806 "BilinearForm::ConformingAssemble() is not called!");
807 mat->GetDiag(diag);
808 return;
809 }
810 // Here, we have extension, ext.
811 if (!cP)
812 {
813 ext->AssembleDiagonal(diag);
814 return;
815 }
816 // Here, we have extension, ext, and conforming prolongation, cP.
817
818 // For an AMR mesh, a convergent diagonal is assembled with |P^T| d_l,
819 // where |P^T| has the entry-wise absolute values of the conforming
820 // prolongation transpose operator.
821 Vector local_diag(cP->Height());
822 ext->AssembleDiagonal(local_diag);
823 cP->AbsMultTranspose(local_diag, diag);
824}
825
827 Vector &b, OperatorHandle &A, Vector &X,
828 Vector &B, int copy_interior)
829{
832 if (ext)
833 {
834 if (hybridization)
835 {
837
838 std::unique_ptr<ConstrainedOperator> A_constrained([&]()
839 {
840 Operator *op;
842 return dynamic_cast<ConstrainedOperator*>(op);
843 }());
844 MFEM_ASSERT(A_constrained != nullptr, "");
845
846 Vector conf_b, conf_x;
847 if (P)
848 {
849 // Nonconforming
850 conf_b.SetSize(P->Width());
851 conf_x.SetSize(P->Width());
852 P->MultTranspose(b, conf_b);
853 R->Mult(x, conf_x);
854 }
855 else
856 {
857 // Conforming
858 conf_b.MakeRef(b, 0, b.Size());
859 conf_x.MakeRef(x, 0, x.Size());
860 }
861
862 A_constrained->EliminateRHS(conf_x, conf_b);
863
864 if (P)
865 {
866 R->MultTranspose(conf_b, b); // store eliminated rhs in b
867 }
868
869 hybridization->ReduceRHS(conf_b, B);
870 X.SetSize(B.Size());
871 X = 0.0;
872 }
873 else
874 {
875 ext->FormLinearSystem(ess_tdof_list, x, b, A, X, B, copy_interior);
876 }
877 return;
878 }
880
881 // Transform the system and perform the elimination in B, based on the
882 // essential BC values from x. Restrict the BC part of x in X, and set the
883 // non-BC part to zero. Since there is no good initial guess for the Lagrange
884 // multipliers, set X = 0.0 for hybridization.
885 if (static_cond)
886 {
887 // Schur complement reduction to the exposed dofs
888 static_cond->ReduceSystem(x, b, X, B, copy_interior);
889 }
890 else if (!P) // conforming space
891 {
892 if (hybridization)
893 {
894 // Reduction to the Lagrange multipliers system
896 hybridization->ReduceRHS(b, B);
897 X.SetSize(B.Size());
898 X = 0.0;
899 }
900 else
901 {
902 // A, X and B point to the same data as mat, x and b
904 X.MakeRef(x, 0, x.Size());
905 B.MakeRef(b, 0, b.Size());
906 if (!copy_interior) { X.SetSubVectorComplement(ess_tdof_list, 0.0); }
907 }
908 }
909 else // non-conforming space
910 {
911 if (hybridization)
912 {
913 // Reduction to the Lagrange multipliers system
914 Vector conf_b(P->Width()), conf_x(P->Width());
915 P->MultTranspose(b, conf_b);
916 R->Mult(x, conf_x);
917 EliminateVDofsInRHS(ess_tdof_list, conf_x, conf_b);
918 R->MultTranspose(conf_b, b); // store eliminated rhs in b
919 hybridization->ReduceRHS(conf_b, B);
920 X.SetSize(B.Size());
921 X = 0.0;
922 }
923 else
924 {
925 // Variational restriction with P
926 B.SetSize(P->Width());
927 P->MultTranspose(b, B);
928 X.SetSize(R->Height());
929 R->Mult(x, X);
931 if (!copy_interior) { X.SetSubVectorComplement(ess_tdof_list, 0.0); }
932 }
933 }
934}
935
938{
939 if (ext)
940 {
941 if (hybridization)
942 {
943 const int remove_zeros = 0;
944 Finalize(remove_zeros);
945 A.Reset(&hybridization->GetMatrix(), false);
946 }
947 else
948 {
949 ext->FormSystemMatrix(ess_tdof_list, A);
950 }
951 return;
952 }
953
954 // Finish the matrix assembly and perform BC elimination, storing the
955 // eliminated part of the matrix.
956 if (static_cond)
957 {
958 if (!static_cond->HasEliminatedBC())
959 {
960 static_cond->SetEssentialTrueDofs(ess_tdof_list);
961 static_cond->Finalize(); // finalize Schur complement (to true dofs)
962 static_cond->EliminateReducedTrueDofs(diag_policy);
963 static_cond->Finalize(); // finalize eliminated part
964 }
965 A.Reset(&static_cond->GetMatrix(), false);
966 }
967 else
968 {
969 if (!mat_e)
970 {
972 if (P) { ConformingAssemble(); }
974 const int remove_zeros = 0;
975 Finalize(remove_zeros);
976 }
977 if (hybridization)
978 {
979 A.Reset(&hybridization->GetMatrix(), false);
980 }
981 else
982 {
983 A.Reset(mat, false);
984 }
985 }
986}
987
989 const Vector &b, Vector &x)
990{
991 if (ext && !hybridization)
992 {
993 ext->RecoverFEMSolution(X, b, x);
994 return;
995 }
996
998 if (!P) // conforming space
999 {
1000 if (static_cond)
1001 {
1002 // Private dofs back solve
1003 static_cond->ComputeSolution(b, X, x);
1004 }
1005 else if (hybridization)
1006 {
1007 // Primal unknowns recovery
1008 hybridization->ComputeSolution(b, X, x);
1009 }
1010 else
1011 {
1012 // X and x point to the same data
1013
1014 // If the validity flags of X's Memory were changed (e.g. if it was
1015 // moved to device memory) then we need to tell x about that.
1016 x.SyncMemory(X);
1017 }
1018 }
1019 else // non-conforming space
1020 {
1021 if (static_cond)
1022 {
1023 // Private dofs back solve
1024 static_cond->ComputeSolution(b, X, x);
1025 }
1026 else if (hybridization)
1027 {
1028 // Primal unknowns recovery
1029 Vector conf_b(P->Width()), conf_x(P->Width());
1030 P->MultTranspose(b, conf_b);
1032 R->Mult(x, conf_x); // get essential b.c. from x
1033 hybridization->ComputeSolution(conf_b, X, conf_x);
1034 x.SetSize(P->Height());
1035 P->Mult(conf_x, x);
1036 }
1037 else
1038 {
1039 // Apply conforming prolongation
1040 x.SetSize(P->Height());
1041 P->Mult(X, x);
1042 }
1043 }
1044}
1045
1047{
1048 if (element_matrices) { return; }
1049
1050 if (auto *ea_ext = dynamic_cast<EABilinearFormExtension*>(ext.get()))
1051 {
1052 element_matrices.reset(new DenseTensor);
1053 ea_ext->GetElementMatrices(*element_matrices, ElementDofOrdering::NATIVE, true);
1054 return;
1055 }
1056
1057 if (domain_integs.Size() == 0 || fes->GetNE() == 0)
1058 {
1059 element_matrices.reset(new DenseTensor);
1060 return;
1061 }
1062
1063 int num_elements = fes->GetNE();
1064 int num_dofs_per_el = fes->GetTypicalFE()->GetDof() * fes->GetVDim();
1065
1066 element_matrices.reset(new DenseTensor(num_dofs_per_el, num_dofs_per_el,
1067 num_elements));
1068
1069 DenseMatrix tmp;
1071
1072#ifdef MFEM_USE_LEGACY_OPENMP
1073 #pragma omp parallel for private(tmp,eltrans)
1074#endif
1075 for (int i = 0; i < num_elements; i++)
1076 {
1077 DenseMatrix elmat(element_matrices->GetData(i),
1078 num_dofs_per_el, num_dofs_per_el);
1079 const FiniteElement &fe = *fes->GetFE(i);
1080#ifdef MFEM_DEBUG
1081 if (num_dofs_per_el != fe.GetDof()*fes->GetVDim())
1082 mfem_error("BilinearForm::ComputeElementMatrices:"
1083 " all elements must have same number of dofs");
1084#endif
1085 fes->GetElementTransformation(i, &eltrans);
1086
1087 domain_integs[0]->AssembleElementMatrix(fe, eltrans, elmat);
1088 for (int k = 1; k < domain_integs.Size(); k++)
1089 {
1090 // note: some integrators may not be thread-safe
1091 domain_integs[k]->AssembleElementMatrix(fe, eltrans, tmp);
1092 elmat += tmp;
1093 }
1094 elmat.ClearExternalData();
1095 }
1096}
1097
1099{
1100 ComputeElementMatrices(); // Won't recompute if element_matrices exists
1101 return *element_matrices;
1102}
1103
1105 const Vector &sol, Vector &rhs,
1106 DiagonalPolicy dpolicy)
1107{
1108 Array<int> ess_dofs, conf_ess_dofs;
1109 fes->GetEssentialVDofs(bdr_attr_is_ess, ess_dofs);
1110
1111 if (fes->GetVSize() == height)
1112 {
1113 EliminateEssentialBCFromDofs(ess_dofs, sol, rhs, dpolicy);
1114 }
1115 else
1116 {
1117 fes->GetRestrictionMatrix()->BooleanMult(ess_dofs, conf_ess_dofs);
1118 EliminateEssentialBCFromDofs(conf_ess_dofs, sol, rhs, dpolicy);
1119 }
1120}
1121
1123 DiagonalPolicy dpolicy)
1124{
1125 Array<int> ess_dofs, conf_ess_dofs;
1126 fes->GetEssentialVDofs(bdr_attr_is_ess, ess_dofs);
1127
1128 if (fes->GetVSize() == height)
1129 {
1130 EliminateEssentialBCFromDofs(ess_dofs, dpolicy);
1131 }
1132 else
1133 {
1134 fes->GetRestrictionMatrix()->BooleanMult(ess_dofs, conf_ess_dofs);
1135 EliminateEssentialBCFromDofs(conf_ess_dofs, dpolicy);
1136 }
1137}
1140 real_t value)
1141{
1142 Array<int> ess_dofs, conf_ess_dofs;
1143 fes->GetEssentialVDofs(bdr_attr_is_ess, ess_dofs);
1144
1145 if (fes->GetVSize() == height)
1146 {
1147 EliminateEssentialBCFromDofsDiag(ess_dofs, value);
1148 }
1149 else
1150 {
1151 fes->GetRestrictionMatrix()->BooleanMult(ess_dofs, conf_ess_dofs);
1152 EliminateEssentialBCFromDofsDiag(conf_ess_dofs, value);
1153 }
1154}
1155
1157 const Vector &sol, Vector &rhs,
1158 DiagonalPolicy dpolicy)
1159{
1160 vdofs_.HostRead();
1161 for (int i = 0; i < vdofs_.Size(); i++)
1162 {
1163 int vdof = vdofs_[i];
1164 if ( vdof >= 0 )
1165 {
1166 mat -> EliminateRowCol (vdof, sol(vdof), rhs, dpolicy);
1167 }
1168 else
1169 {
1170 mat -> EliminateRowCol (-1-vdof, sol(-1-vdof), rhs, dpolicy);
1171 }
1172 }
1173}
1174
1176 DiagonalPolicy dpolicy)
1177{
1178 if (mat_e == NULL)
1179 {
1180 mat_e = new SparseMatrix(height);
1181 }
1182
1183 vdofs_.HostRead();
1184 for (int i = 0; i < vdofs_.Size(); i++)
1185 {
1186 int vdof = vdofs_[i];
1187 if ( vdof >= 0 )
1188 {
1189 mat -> EliminateRowCol (vdof, *mat_e, dpolicy);
1190 }
1191 else
1192 {
1193 mat -> EliminateRowCol (-1-vdof, *mat_e, dpolicy);
1194 }
1195 }
1196}
1197
1199 const Array<int> &ess_dofs, const Vector &sol, Vector &rhs,
1200 DiagonalPolicy dpolicy)
1201{
1202 MFEM_ASSERT(ess_dofs.Size() == height, "incorrect dof Array size");
1203 MFEM_ASSERT(sol.Size() == height, "incorrect sol Vector size");
1204 MFEM_ASSERT(rhs.Size() == height, "incorrect rhs Vector size");
1205
1206 for (int i = 0; i < ess_dofs.Size(); i++)
1207 if (ess_dofs[i] < 0)
1208 {
1209 mat -> EliminateRowCol (i, sol(i), rhs, dpolicy);
1210 }
1211}
1212
1214 DiagonalPolicy dpolicy)
1215{
1216 MFEM_ASSERT(ess_dofs.Size() == height,
1217 "incorrect dof Array size: " << ess_dofs.Size() << ' ' << height);
1218
1219 for (int i = 0; i < ess_dofs.Size(); i++)
1220 if (ess_dofs[i] < 0)
1221 {
1222 mat -> EliminateRowCol (i, dpolicy);
1223 }
1224}
1225
1227 real_t value)
1228{
1229 MFEM_ASSERT(ess_dofs.Size() == height,
1230 "incorrect dof Array size: " << ess_dofs.Size() << ' ' << height);
1231
1232 for (int i = 0; i < ess_dofs.Size(); i++)
1233 if (ess_dofs[i] < 0)
1234 {
1235 mat -> EliminateRowColDiag (i, value);
1236 }
1237}
1238
1240 const Array<int> &vdofs_, const Vector &x, Vector &b)
1241{
1242 mat_e->AddMult(x, b, -1.);
1243 mat->PartMult(vdofs_, x, b);
1244}
1245
1246void BilinearForm::Mult(const Vector &x, Vector &y) const
1247{
1248 if (ext)
1249 {
1250 ext->Mult(x, y);
1251 }
1252 else
1253 {
1254 mat->Mult(x, y);
1255 }
1256}
1257
1258void BilinearForm::AddMult(const Vector &x, Vector &y, const real_t a) const
1259{
1260 if (ext)
1261 {
1262 ext->AddMult(x, y, a);
1263 }
1264 else
1265 {
1266 mat->AddMult(x, y, a);
1267 }
1268}
1269
1271 const real_t a) const
1272{
1273 if (ext)
1274 {
1275 ext->AddMultTranspose(x, y, a);
1276 }
1277 else
1278 {
1279 mat->AddMultTranspose(x, y, a);
1280 }
1281}
1282
1284{
1285 if (ext)
1286 {
1287 ext->MultTranspose(x, y);
1288 }
1289 else
1290 {
1291 y = 0.0;
1292 AddMultTranspose (x, y);
1293 }
1294}
1295
1297{
1298 bool full_update;
1299
1300 if (nfes && nfes != fes)
1301 {
1302 full_update = true;
1303 fes = nfes;
1304 }
1305 else
1306 {
1307 // Check for different size (e.g. assembled form on non-conforming space)
1308 // or different sequence number.
1309 full_update = (fes->GetVSize() != Height() ||
1310 sequence < fes->GetSequence());
1311 }
1312
1313 delete mat_e;
1314 mat_e = NULL;
1316 static_cond.reset();
1317
1318 if (full_update)
1319 {
1320 delete mat;
1321 mat = NULL;
1322 hybridization.reset();
1324 }
1325 else
1326 {
1327 if (mat) { *mat = 0.0; }
1328 if (hybridization) { hybridization->Reset(); }
1329 }
1330
1331 height = width = fes->GetVSize();
1332
1333 if (ext) { ext->Update(); }
1334}
1335
1337{
1338 diag_policy = policy;
1339}
1340
1342{
1343 delete mat_e;
1344 delete mat;
1345
1346 if (!extern_bfs)
1347 {
1348 int k;
1349 for (k=0; k < domain_integs.Size(); k++) { delete domain_integs[k]; }
1350 for (k=0; k < boundary_integs.Size(); k++) { delete boundary_integs[k]; }
1351 for (k=0; k < interior_face_integs.Size(); k++)
1352 { delete interior_face_integs[k]; }
1353 for (k=0; k < boundary_face_integs.Size(); k++)
1354 { delete boundary_face_integs[k]; }
1355 }
1356}
1357
1358
1359MixedBilinearForm::MixedBilinearForm (FiniteElementSpace *tr_fes,
1360 FiniteElementSpace *te_fes)
1361 : Matrix(te_fes->GetVSize(), tr_fes->GetVSize())
1362{
1363 trial_fes = tr_fes;
1364 test_fes = te_fes;
1365 mat = NULL;
1366 mat_e = NULL;
1367 extern_bfs = 0;
1369 ext = NULL;
1370}
1371
1372MixedBilinearForm::MixedBilinearForm (FiniteElementSpace *tr_fes,
1373 FiniteElementSpace *te_fes,
1374 MixedBilinearForm * mbf)
1375 : Matrix(te_fes->GetVSize(), tr_fes->GetVSize())
1376{
1377 trial_fes = tr_fes;
1378 test_fes = te_fes;
1379 mat = NULL;
1380 mat_e = NULL;
1381 extern_bfs = 1;
1382
1383 // Copy the pointers to the integrators
1386
1389
1391
1394
1396 ext = NULL;
1397}
1398
1400{
1401 if (ext)
1402 {
1403 MFEM_ABORT("the assembly level has already been set!");
1404 }
1405 assembly = assembly_level;
1406 switch (assembly)
1407 {
1409 break;
1411 // ext.reset(new FAMixedBilinearFormExtension(this));
1412 // Use the original BilinearForm implementation for now
1413 break;
1415 MFEM_ABORT("Element assembly not supported yet... stay tuned!");
1416 // ext.reset(new EAMixedBilinearFormExtension(this));
1417 break;
1419 ext.reset(new PAMixedBilinearFormExtension(this));
1420 break;
1422 MFEM_ABORT("Matrix-free action not supported yet... stay tuned!");
1423 // ext.reset(new MFMixedBilinearFormExtension(this));
1424 break;
1425 default:
1426 MFEM_ABORT("Unknown assembly level");
1427 }
1428}
1429
1431{
1432 return (*mat)(i, j);
1433}
1434
1435const real_t & MixedBilinearForm::Elem (int i, int j) const
1436{
1437 return (*mat)(i, j);
1438}
1439
1440void MixedBilinearForm::Mult(const Vector & x, Vector & y) const
1441{
1442 y = 0.0;
1443 AddMult(x, y);
1444}
1445
1447 const real_t a) const
1448{
1449 if (ext)
1450 {
1451 ext->AddMult(x, y, a);
1452 }
1453 else
1454 {
1455 mat->AddMult(x, y, a);
1456 }
1457}
1458
1460{
1461 y = 0.0;
1462 AddMultTranspose(x, y);
1463}
1464
1466 const real_t a) const
1467{
1468 if (ext)
1469 {
1470 ext->AddMultTranspose(x, y, a);
1471 }
1472 else
1473 {
1474 mat->AddMultTranspose(x, y, a);
1475 }
1476}
1477
1479{
1481 {
1482 MFEM_WARNING("MixedBilinearForm::Inverse not possible with this "
1483 "assembly level!");
1484 return NULL;
1485 }
1486 else
1487 {
1488 return mat -> Inverse ();
1489 }
1490}
1491
1492void MixedBilinearForm::Finalize (int skip_zeros)
1493{
1495 {
1496 mat -> Finalize (skip_zeros);
1497 }
1498}
1499
1501{
1502 MFEM_VERIFY(trial_fes->GetOrdering() == Ordering::byNODES &&
1504 "MixedBilinearForm::GetBlocks: both trial and test spaces "
1505 "must use Ordering::byNODES!");
1506
1507 blocks.SetSize(test_fes->GetVDim(), trial_fes->GetVDim());
1508
1509 mat->GetBlocks(blocks);
1510}
1511
1513{
1514 domain_integs.Append(bfi);
1515 domain_integs_marker.Append(NULL); // NULL marker means apply everywhere
1516}
1517
1519 Array<int> &elem_marker)
1520{
1521 domain_integs.Append(bfi);
1522 domain_integs_marker.Append(&elem_marker);
1523}
1524
1526{
1527 boundary_integs.Append(bfi);
1528 boundary_integs_marker.Append(NULL); // NULL marker means apply everywhere
1529}
1530
1532 Array<int> &bdr_marker)
1533{
1534 boundary_integs.Append(bfi);
1535 boundary_integs_marker.Append(&bdr_marker);
1536}
1537
1542
1544{
1545 boundary_face_integs.Append(bfi);
1546 boundary_face_integs_marker.Append(NULL); // NULL marker means apply everywhere
1547}
1548
1550 Array<int> &bdr_marker)
1551{
1552 boundary_face_integs.Append(bfi);
1553 boundary_face_integs_marker.Append(&bdr_marker);
1554}
1555
1560
1562{
1563 boundary_trace_face_integs.Append(bfi);
1564 // NULL marker means apply everywhere
1566}
1567
1574
1576{
1577 if (ext)
1578 {
1579 ext->Assemble();
1580 return;
1581 }
1582
1583 ElementTransformation *eltrans;
1584 DenseMatrix elmat;
1585
1586 Mesh *mesh = test_fes -> GetMesh();
1587
1588 if (mat == NULL)
1589 {
1590 mat = new SparseMatrix(height, width);
1591 }
1592
1593 if (domain_integs.Size())
1594 {
1595 for (int k = 0; k < domain_integs.Size(); k++)
1596 {
1597 if (domain_integs_marker[k] != NULL)
1598 {
1599 MFEM_VERIFY(domain_integs_marker[k]->Size() ==
1600 (mesh->attributes.Size() ? mesh->attributes.Max() : 0),
1601 "invalid element marker for domain integrator #"
1602 << k << ", counting from zero");
1603 }
1604 }
1605
1606 DofTransformation dom_dof_trans, ran_dof_trans;
1607 for (int i = 0; i < test_fes -> GetNE(); i++)
1608 {
1609 const int elem_attr = mesh->GetAttribute(i);
1610 trial_fes->GetElementVDofs (i, trial_vdofs, dom_dof_trans);
1611 test_fes->GetElementVDofs (i, test_vdofs, ran_dof_trans);
1612 eltrans = test_fes -> GetElementTransformation (i);
1613
1615 elmat = 0.0;
1616 for (int k = 0; k < domain_integs.Size(); k++)
1617 {
1618 if (domain_integs_marker[k] == NULL ||
1619 (*(domain_integs_marker[k]))[elem_attr-1] == 1)
1620 {
1621 domain_integs[k] -> AssembleElementMatrix2 (*trial_fes -> GetFE(i),
1622 *test_fes -> GetFE(i),
1623 *eltrans, elemmat);
1624 elmat += elemmat;
1625 }
1626 }
1627 TransformDual(ran_dof_trans, dom_dof_trans, elmat);
1628 mat -> AddSubMatrix (test_vdofs, trial_vdofs, elmat, skip_zeros);
1629 }
1630 }
1631
1632 if (boundary_integs.Size())
1633 {
1634 // Which boundary attributes need to be processed?
1635 Array<int> bdr_attr_marker(mesh->bdr_attributes.Size() ?
1636 mesh->bdr_attributes.Max() : 0);
1637 bdr_attr_marker = 0;
1638 for (int k = 0; k < boundary_integs.Size(); k++)
1639 {
1640 if (boundary_integs_marker[k] == NULL)
1641 {
1642 bdr_attr_marker = 1;
1643 break;
1644 }
1645 Array<int> &bdr_marker = *boundary_integs_marker[k];
1646 MFEM_ASSERT(bdr_marker.Size() == bdr_attr_marker.Size(),
1647 "invalid boundary marker for boundary integrator #"
1648 << k << ", counting from zero");
1649 for (int i = 0; i < bdr_attr_marker.Size(); i++)
1650 {
1651 bdr_attr_marker[i] |= bdr_marker[i];
1652 }
1653 }
1654
1655 DofTransformation dom_dof_trans, ran_dof_trans;
1656 for (int i = 0; i < test_fes -> GetNBE(); i++)
1657 {
1658 const int bdr_attr = mesh->GetBdrAttribute(i);
1659 if (bdr_attr_marker[bdr_attr-1] == 0) { continue; }
1660
1661 trial_fes->GetBdrElementVDofs (i, trial_vdofs, dom_dof_trans);
1662 test_fes->GetBdrElementVDofs (i, test_vdofs, ran_dof_trans);
1663 eltrans = test_fes -> GetBdrElementTransformation (i);
1664
1666 elmat = 0.0;
1667 for (int k = 0; k < boundary_integs.Size(); k++)
1668 {
1669 if (boundary_integs_marker[k] &&
1670 (*boundary_integs_marker[k])[bdr_attr-1] == 0) { continue; }
1671
1672 boundary_integs[k]->AssembleElementMatrix2 (*trial_fes -> GetBE(i),
1673 *test_fes -> GetBE(i),
1674 *eltrans, elemmat);
1675 elmat += elemmat;
1676 }
1677 TransformDual(ran_dof_trans, dom_dof_trans, elmat);
1678 mat -> AddSubMatrix (test_vdofs, trial_vdofs, elmat, skip_zeros);
1679 }
1680 }
1681
1682 if (interior_face_integs.Size())
1683 {
1685 Array<int> trial_vdofs2, test_vdofs2;
1686 const FiniteElement *trial_fe1, *trial_fe2, *test_fe1, *test_fe2;
1687
1688 int nfaces = mesh->GetNumFaces();
1689 for (int i = 0; i < nfaces; i++)
1690 {
1691 ftr = mesh->GetInteriorFaceTransformations(i);
1692 if (ftr != NULL)
1693 {
1696 trial_fe1 = trial_fes->GetFE(ftr->Elem1No);
1697 test_fe1 = test_fes->GetFE(ftr->Elem1No);
1698 if (ftr->Elem2No >= 0)
1699 {
1700 trial_fes->GetElementVDofs(ftr->Elem2No, trial_vdofs2);
1701 test_fes->GetElementVDofs(ftr->Elem2No, test_vdofs2);
1702 trial_vdofs.Append(trial_vdofs2);
1703 test_vdofs.Append(test_vdofs2);
1704 trial_fe2 = trial_fes->GetFE(ftr->Elem2No);
1705 test_fe2 = test_fes->GetFE(ftr->Elem2No);
1706 }
1707 else
1708 {
1709 // The test_fe2 object is really a dummy and not used on the
1710 // boundaries, but we can't dereference a NULL pointer, and we don't
1711 // want to actually make a fake element.
1712 trial_fe2 = trial_fe1;
1713 test_fe2 = test_fe1;
1714 }
1715 for (int k = 0; k < interior_face_integs.Size(); k++)
1716 {
1717 interior_face_integs[k]->AssembleFaceMatrix(*trial_fe1, *test_fe1, *trial_fe2,
1718 *test_fe2,
1719 *ftr, elemmat);
1721 }
1722 }
1723 }
1724 }
1725
1726 if (boundary_face_integs.Size())
1727 {
1729 Array<int> tr_vdofs2, te_vdofs2;
1730 const FiniteElement *trial_fe1, *trial_fe2, *test_fe1, *test_fe2;
1731
1732 // Which boundary attributes need to be processed?
1733 Array<int> bdr_attr_marker(mesh->bdr_attributes.Size() ?
1734 mesh->bdr_attributes.Max() : 0);
1735 bdr_attr_marker = 0;
1736 for (int k = 0; k < boundary_face_integs.Size(); k++)
1737 {
1738 if (boundary_face_integs_marker[k] == NULL)
1739 {
1740 bdr_attr_marker = 1;
1741 break;
1742 }
1743 Array<int> &bdr_marker = *boundary_face_integs_marker[k];
1744 MFEM_ASSERT(bdr_marker.Size() == bdr_attr_marker.Size(),
1745 "invalid boundary marker for boundary face integrator #"
1746 << k << ", counting from zero");
1747 for (int i = 0; i < bdr_attr_marker.Size(); i++)
1748 {
1749 bdr_attr_marker[i] |= bdr_marker[i];
1750 }
1751 }
1752
1753 DofTransformation dom_dof_trans, ran_dof_trans;
1754 for (int i = 0; i < trial_fes -> GetNBE(); i++)
1755 {
1756 const int bdr_attr = mesh->GetBdrAttribute(i);
1757 if (bdr_attr_marker[bdr_attr-1] == 0) { continue; }
1758
1759 ftr = mesh -> GetBdrFaceTransformations (i);
1760 if (ftr != NULL)
1761 {
1762 trial_fes->GetElementVDofs(ftr->Elem1No, trial_vdofs, dom_dof_trans);
1763 test_fes->GetElementVDofs(ftr->Elem1No, test_vdofs, ran_dof_trans);
1764 trial_fe1 = trial_fes->GetFE(ftr->Elem1No);
1765 test_fe1 = test_fes->GetFE(ftr->Elem1No);
1766 // The test_fe2 object is really a dummy and not used on the
1767 // boundaries, but we can't dereference a NULL pointer, and we don't
1768 // want to actually make a fake element.
1769 trial_fe2 = trial_fe1;
1770 test_fe2 = test_fe1;
1771 for (int k = 0; k < boundary_face_integs.Size(); k++)
1772 {
1774 (*boundary_face_integs_marker[k])[bdr_attr-1] == 0) { continue; }
1775
1776 boundary_face_integs[k]->AssembleFaceMatrix(*trial_fe1, *test_fe1, *trial_fe2,
1777 *test_fe2,
1778 *ftr, elemmat);
1779 TransformDual(ran_dof_trans, dom_dof_trans, elemmat);
1781 }
1782 }
1783 }
1784 }
1785
1786 if (trace_face_integs.Size())
1787 {
1789 Array<int> test_vdofs2;
1790 const FiniteElement *trial_face_fe, *test_fe1, *test_fe2;
1791
1792 int nfaces = mesh->GetNumFaces();
1793 for (int i = 0; i < nfaces; i++)
1794 {
1795 ftr = mesh->GetFaceElementTransformations(i);
1798 trial_face_fe = trial_fes->GetFaceElement(i);
1799 test_fe1 = test_fes->GetFE(ftr->Elem1No);
1800 if (ftr->Elem2No >= 0)
1801 {
1802 test_fes->GetElementVDofs(ftr->Elem2No, test_vdofs2);
1803 test_vdofs.Append(test_vdofs2);
1804 test_fe2 = test_fes->GetFE(ftr->Elem2No);
1805 }
1806 else
1807 {
1808 // The test_fe2 object is really a dummy and not used on the
1809 // boundaries, but we can't dereference a NULL pointer, and we don't
1810 // want to actually make a fake element.
1811 test_fe2 = test_fe1;
1812 }
1813 for (int k = 0; k < trace_face_integs.Size(); k++)
1814 {
1815 trace_face_integs[k]->AssembleFaceMatrix(*trial_face_fe, *test_fe1,
1816 *test_fe2, *ftr, elemmat);
1818 }
1819 }
1820 }
1821
1822 if (boundary_trace_face_integs.Size())
1823 {
1825 Array<int> te_vdofs2;
1826 const FiniteElement *trial_face_fe, *test_fe1, *test_fe2;
1827
1828 // Which boundary attributes need to be processed?
1829 Array<int> bdr_attr_marker(mesh->bdr_attributes.Size() ?
1830 mesh->bdr_attributes.Max() : 0);
1831 bdr_attr_marker = 0;
1832 for (int k = 0; k < boundary_trace_face_integs.Size(); k++)
1833 {
1834 if (boundary_trace_face_integs_marker[k] == NULL)
1835 {
1836 bdr_attr_marker = 1;
1837 break;
1838 }
1840 MFEM_ASSERT(bdr_marker.Size() == bdr_attr_marker.Size(),
1841 "invalid boundary marker for boundary trace face"
1842 "integrator #" << k << ", counting from zero");
1843 for (int i = 0; i < bdr_attr_marker.Size(); i++)
1844 {
1845 bdr_attr_marker[i] |= bdr_marker[i];
1846 }
1847 }
1848
1849 for (int i = 0; i < trial_fes -> GetNBE(); i++)
1850 {
1851 const int bdr_attr = mesh->GetBdrAttribute(i);
1852 if (bdr_attr_marker[bdr_attr-1] == 0) { continue; }
1853
1854 ftr = mesh->GetBdrFaceTransformations(i);
1855 if (ftr)
1856 {
1857 const int iface = mesh->GetBdrElementFaceIndex(i);
1860 trial_face_fe = trial_fes->GetFaceElement(iface);
1861 test_fe1 = test_fes->GetFE(ftr->Elem1No);
1862 // The test_fe2 object is really a dummy and not used on the
1863 // boundaries, but we can't dereference a NULL pointer, and we don't
1864 // want to actually make a fake element.
1865 test_fe2 = test_fe1;
1866 for (int k = 0; k < boundary_trace_face_integs.Size(); k++)
1867 {
1869 (*boundary_trace_face_integs_marker[k])[bdr_attr-1] == 0)
1870 { continue; }
1871
1872 boundary_trace_face_integs[k]->AssembleFaceMatrix(*trial_face_fe,
1873 *test_fe1,
1874 *test_fe2,
1875 *ftr, elemmat);
1877 }
1878 }
1879 }
1880 }
1881}
1882
1884 Vector &diag) const
1885{
1886 if (ext)
1887 {
1888 MFEM_ASSERT(diag.Size() == test_fes->GetTrueVSize(),
1889 "Vector for holding diagonal has wrong size!");
1890 MFEM_ASSERT(D.Size() == trial_fes->GetTrueVSize(),
1891 "Vector for holding diagonal has wrong size!");
1892 const Operator *P_trial = trial_fes->GetProlongationMatrix();
1893 const Operator *P_test = test_fes->GetProlongationMatrix();
1894 if (!IsIdentityProlongation(P_trial))
1895 {
1896 Vector local_D(P_trial->Height());
1897 P_trial->Mult(D, local_D);
1898
1899 if (!IsIdentityProlongation(P_test))
1900 {
1901 Vector local_diag(P_test->Height());
1902 ext->AssembleDiagonal_ADAt(local_D, local_diag);
1903 P_test->MultTranspose(local_diag, diag);
1904 }
1905 else
1906 {
1907 ext->AssembleDiagonal_ADAt(local_D, diag);
1908 }
1909 }
1910 else
1911 {
1912 if (!IsIdentityProlongation(P_test))
1913 {
1914 Vector local_diag(P_test->Height());
1915 ext->AssembleDiagonal_ADAt(D, local_diag);
1916 P_test->MultTranspose(local_diag, diag);
1917 }
1918 else
1919 {
1920 ext->AssembleDiagonal_ADAt(D, diag);
1921 }
1922 }
1923 }
1924 else
1925 {
1926 MFEM_ABORT("Not implemented. Maybe assemble your bilinear form into a "
1927 "matrix and use SparseMatrix functions?");
1928 }
1929}
1930
1932{
1934 {
1935 MFEM_WARNING("Conforming assemble not supported for this assembly level!");
1936 return;
1937 }
1938
1939 Finalize();
1940
1942 if (P2)
1943 {
1944 SparseMatrix *R = Transpose(*P2);
1945 SparseMatrix *RA = mfem::Mult(*R, *mat);
1946 delete R;
1947 delete mat;
1948 mat = RA;
1949 }
1950
1952 if (P1)
1953 {
1954 SparseMatrix *RAP = mfem::Mult(*mat, *P1);
1955 delete mat;
1956 mat = RAP;
1957 }
1958
1959 height = mat->Height();
1960 width = mat->Width();
1961}
1962
1963
1965{
1966 const FiniteElement &trial_fe = *trial_fes->GetFE(i);
1967 const FiniteElement &test_fe = *test_fes->GetFE(i);
1968
1969 if (domain_integs.Size())
1970 {
1972 domain_integs[0]->AssembleElementMatrix2(trial_fe, test_fe, *eltrans,
1973 elmat);
1974 for (int k = 1; k < domain_integs.Size(); k++)
1975 {
1976 domain_integs[k]->AssembleElementMatrix2(trial_fe, test_fe, *eltrans,
1977 elemmat);
1978 elmat += elemmat;
1979 }
1980 }
1981 else
1982 {
1983 const int tr_dofs = trial_fe.GetDof() * trial_fes->GetVDim();
1984 const int te_dofs = test_fe.GetDof() * test_fes->GetVDim();
1985
1986 elmat.SetSize(te_dofs, tr_dofs);
1987 elmat = 0.0;
1988 }
1989}
1990
1992{
1993 const FiniteElement &trial_be = *trial_fes->GetBE(i);
1994 const FiniteElement &test_be = *test_fes->GetBE(i);
1995
1996 if (boundary_integs.Size())
1997 {
1999 boundary_integs[0]->AssembleElementMatrix2(trial_be, test_be, *eltrans,
2000 elmat);
2001 for (int k = 1; k < boundary_integs.Size(); k++)
2002 {
2003 boundary_integs[k]->AssembleElementMatrix2(trial_be, test_be, *eltrans,
2004 elemmat);
2005 elmat += elemmat;
2006 }
2007 }
2008 else
2009 {
2010 const int tr_dofs = trial_be.GetDof() * trial_fes->GetVDim();
2011 const int te_dofs = test_be.GetDof() * test_fes->GetVDim();
2012
2013 elmat.SetSize(te_dofs, tr_dofs);
2014 elmat = 0.0;
2015 }
2016}
2017
2019{
2021 Mesh *mesh = test_fes -> GetMesh();
2022 ftr = mesh->GetFaceElementTransformations(i);
2023 MFEM_ASSERT(ftr, "No associated face transformations.");
2024
2025 const FiniteElement *trial_fe1, *trial_fe2, *test_fe1, *test_fe2;
2026
2027 trial_fe1 = trial_fes->GetFE(ftr->Elem1No);
2028 test_fe1 = test_fes->GetFE(ftr->Elem1No);
2029 if (ftr->Elem2No >= 0)
2030 {
2031 trial_fe2 = trial_fes->GetFE(ftr->Elem2No);
2032 test_fe2 = test_fes->GetFE(ftr->Elem2No);
2033 }
2034 else
2035 {
2036 // The test_fe2 object is really a dummy and not used on the
2037 // boundaries, but we can't dereference a NULL pointer, and we don't
2038 // want to actually make a fake element.
2039 trial_fe2 = trial_fe1;
2040 test_fe2 = test_fe1;
2041 }
2042
2043 if (interior_face_integs.Size())
2044 {
2045 interior_face_integs[0]->AssembleFaceMatrix(*trial_fe1, *test_fe1, *trial_fe2,
2046 *test_fe2,
2047 *ftr, elmat);
2048 for (int k = 1; k < interior_face_integs.Size(); k++)
2049 {
2050 interior_face_integs[k]->AssembleFaceMatrix(*trial_fe1, *test_fe1, *trial_fe2,
2051 *test_fe2,
2052 *ftr, elemmat);
2053 elmat += elemmat;
2054 }
2055 }
2056 else
2057 {
2058 int tr_dofs = trial_fe1->GetDof() * trial_fes->GetVDim();
2059 int te_dofs = test_fe1->GetDof() * test_fes->GetVDim();
2060 if (ftr->Elem2No >= 0)
2061 {
2062 tr_dofs += trial_fe2->GetDof() * trial_fes->GetVDim();
2063 te_dofs += test_fe2->GetDof() * test_fes->GetVDim();
2064 }
2065
2066 elmat.SetSize(te_dofs, tr_dofs);
2067 elmat = 0.0;
2068 }
2069}
2070
2072{
2074 Mesh *mesh = test_fes -> GetMesh();
2075 ftr = mesh->GetBdrFaceTransformations(i);
2076 MFEM_ASSERT(ftr, "No associated boundary face.");
2077
2078 const FiniteElement *trial_fe1, *trial_fe2, *test_fe1, *test_fe2;
2079
2080 trial_fe1 = trial_fes->GetFE(ftr->Elem1No);
2081 test_fe1 = test_fes->GetFE(ftr->Elem1No);
2082 // The test_fe2 object is really a dummy and not used on the
2083 // boundaries, but we can't dereference a NULL pointer, and we don't
2084 // want to actually make a fake element.
2085 trial_fe2 = trial_fe1;
2086 test_fe2 = test_fe1;
2087
2088 if (boundary_face_integs.Size())
2089 {
2090 boundary_face_integs[0]->AssembleFaceMatrix(*trial_fe1, *test_fe1, *trial_fe2,
2091 *test_fe2,
2092 *ftr, elmat);
2093 for (int k = 1; k < boundary_face_integs.Size(); k++)
2094 {
2095 boundary_face_integs[k]->AssembleFaceMatrix(*trial_fe1, *test_fe1, *trial_fe2,
2096 *test_fe2,
2097 *ftr, elemmat);
2098 elmat += elemmat;
2099 }
2100 }
2101 else
2102 {
2103 const int tr_dofs = trial_fe1->GetDof() * trial_fes->GetVDim();
2104 const int te_dofs = test_fe1->GetDof() * test_fes->GetVDim();
2105
2106 elmat.SetSize(te_dofs, tr_dofs);
2107 elmat = 0.0;
2108 }
2109}
2110
2112{
2114 Mesh *mesh = test_fes -> GetMesh();
2115 ftr = mesh->GetFaceElementTransformations(i);
2116 MFEM_ASSERT(ftr, "No associated face transformation.");
2117
2118 const FiniteElement *trial_face_fe, *test_fe1, *test_fe2;
2119
2120 trial_face_fe = trial_fes->GetFaceElement(i);
2121 test_fe1 = test_fes->GetFE(ftr->Elem1No);
2122 if (ftr->Elem2No >= 0)
2123 {
2124 test_fe2 = test_fes->GetFE(ftr->Elem2No);
2125 }
2126 else
2127 {
2128 // The test_fe2 object is really a dummy and not used on the
2129 // boundaries, but we can't dereference a NULL pointer, and we don't
2130 // want to actually make a fake element.
2131 test_fe2 = test_fe1;
2132 }
2133
2134 if (trace_face_integs.Size())
2135 {
2136 trace_face_integs[0]->AssembleFaceMatrix(*trial_face_fe, *test_fe1, *test_fe2,
2137 *ftr, elmat);
2138 for (int k = 1; k < trace_face_integs.Size(); k++)
2139 {
2140 trace_face_integs[k]->AssembleFaceMatrix(*trial_face_fe, *test_fe1, *test_fe2,
2141 *ftr, elemmat);
2142 elmat += elemmat;
2143 }
2144 }
2145 else
2146 {
2147 const int tr_face_dofs = trial_face_fe->GetDof() * trial_fes->GetVDim();
2148 int te_dofs = test_fe1->GetDof() * test_fes->GetVDim();
2149 if (ftr->Elem2No >= 0)
2150 {
2151 te_dofs += test_fe2->GetDof() * test_fes->GetVDim();
2152 }
2153
2154 elmat.SetSize(te_dofs, tr_face_dofs);
2155 elmat = 0.0;
2156 }
2157}
2158
2160 DenseMatrix &elmat) const
2161{
2163 Mesh *mesh = test_fes -> GetMesh();
2164 ftr = mesh->GetBdrFaceTransformations(i);
2165 MFEM_ASSERT(ftr, "No associated boundary face.");
2166
2167 const FiniteElement *trial_face_fe, *test_fe1, *test_fe2;
2168 int iface = mesh->GetBdrElementFaceIndex(i);
2169 trial_face_fe = trial_fes->GetFaceElement(iface);
2170 test_fe1 = test_fes->GetFE(ftr->Elem1No);
2171 // The test_fe2 object is really a dummy and not used on the
2172 // boundaries, but we can't dereference a NULL pointer, and we don't
2173 // want to actually make a fake element.
2174 test_fe2 = test_fe1;
2175
2176 if (boundary_trace_face_integs.Size())
2177 {
2178 boundary_trace_face_integs[0]->AssembleFaceMatrix(*trial_face_fe, *test_fe1,
2179 *test_fe2,
2180 *ftr, elmat);
2181 for (int k = 1; k < boundary_trace_face_integs.Size(); k++)
2182 {
2183 boundary_trace_face_integs[k]->AssembleFaceMatrix(*trial_face_fe, *test_fe1,
2184 *test_fe2,
2185 *ftr, elemmat);
2186 elmat += elemmat;
2187 }
2188 }
2189 else
2190 {
2191 const int tr_face_dofs = trial_face_fe->GetDof() * trial_fes->GetVDim();
2192 int te_dofs = test_fe1->GetDof() * test_fes->GetVDim();
2193
2194 elmat.SetSize(te_dofs, tr_face_dofs);
2195 elmat = 0.0;
2196 }
2197}
2198
2200 int i, const DenseMatrix &elmat, int skip_zeros)
2201{
2202 AssembleElementMatrix(i, elmat, trial_vdofs, test_vdofs, skip_zeros);
2203}
2204
2206 int i, const DenseMatrix &elmat, Array<int> &trial_vdofs_,
2207 Array<int> &test_vdofs_, int skip_zeros)
2208{
2209 trial_fes->GetElementVDofs(i, trial_vdofs_);
2210 test_fes->GetElementVDofs(i, test_vdofs_);
2211 if (mat == NULL)
2212 {
2213 mat = new SparseMatrix(height, width);
2214 }
2215 mat->AddSubMatrix(test_vdofs_, trial_vdofs_, elmat, skip_zeros);
2216}
2217
2219 int i, const DenseMatrix &elmat, int skip_zeros)
2220{
2221 AssembleBdrElementMatrix(i, elmat, trial_vdofs, test_vdofs, skip_zeros);
2222}
2223
2225 int i, const DenseMatrix &elmat, Array<int> &trial_vdofs_,
2226 Array<int> &test_vdofs_, int skip_zeros)
2227{
2228 trial_fes->GetBdrElementVDofs(i, trial_vdofs_);
2229 test_fes->GetBdrElementVDofs(i, test_vdofs_);
2230 if (mat == NULL)
2231 {
2232 mat = new SparseMatrix(height, width);
2233 }
2234 mat->AddSubMatrix(test_vdofs_, trial_vdofs_, elmat, skip_zeros);
2235}
2236
2238 const Array<int> &bdr_attr_is_ess, const Vector &sol, Vector &rhs )
2239{
2240 Array<int> trial_ess_dofs;
2241 trial_fes->GetEssentialVDofs(bdr_attr_is_ess, trial_ess_dofs);
2242 mat->EliminateCols(trial_ess_dofs, &sol, &rhs);
2243}
2244
2246 &bdr_attr_is_ess)
2247{
2248 Array<int> trial_ess_dofs;
2249 trial_fes->GetEssentialVDofs(bdr_attr_is_ess, trial_ess_dofs);
2250 mat->EliminateCols(trial_ess_dofs);
2251}
2252
2254 const Vector &sol, Vector &rhs)
2255{
2256 Array<int> trial_vdofs_marker;
2258 trial_vdofs_marker);
2259 mat->EliminateCols(trial_vdofs_marker, &sol, &rhs);
2260}
2261
2263{
2264 if (mat_e == NULL)
2265 {
2266 mat_e = new SparseMatrix(mat->Height(), mat->Width());
2267 }
2268
2269 Array<int> trial_vdofs_marker;
2271 trial_vdofs_marker);
2272 mat->EliminateCols(trial_vdofs_marker, *mat_e);
2273 mat_e->Finalize();
2274}
2275
2277 const Vector &x, Vector &b)
2278{
2279 mat_e->AddMult(x, b, -1.);
2280}
2281
2283 const Array<int> &marked_vdofs, const Vector &sol, Vector &rhs)
2284{
2285 mat->EliminateCols(marked_vdofs, &sol, &rhs);
2286}
2287
2289 &bdr_attr_is_ess)
2290{
2291 int i, j, k;
2292 Array<int> te_vdofs;
2293
2294 for (i = 0; i < test_fes -> GetNBE(); i++)
2295 if (bdr_attr_is_ess[test_fes -> GetBdrAttribute (i)-1])
2296 {
2297 test_fes -> GetBdrElementVDofs (i, te_vdofs);
2298 for (j = 0; j < te_vdofs.Size(); j++)
2299 {
2300 if ( (k = te_vdofs[j]) < 0 )
2301 {
2302 k = -1-k;
2303 }
2304 mat -> EliminateRow (k);
2305 }
2306 }
2307}
2308
2310{
2311 for (int i=0; i<test_vdofs_.Size(); ++i)
2312 {
2313 mat->EliminateRow(test_vdofs_[i]);
2314 }
2315}
2316
2318 const Array<int> &trial_tdof_list,
2319 const Array<int> &test_tdof_list,
2320 OperatorHandle &A)
2321
2322{
2323 if (ext)
2324 {
2325 ext->FormRectangularSystemOperator(trial_tdof_list, test_tdof_list, A);
2326 return;
2327 }
2328
2331
2332 mat->Finalize();
2333
2334 if (test_P && trial_P)
2335 {
2336 SparseMatrix *m = RAP(*test_P, *mat, *trial_P);
2337 delete mat;
2338 mat = m;
2339 }
2340 else if (test_P)
2341 {
2342 SparseMatrix *m = TransposeMult(*test_P, *mat);
2343 delete mat;
2344 mat = m;
2345 }
2346 else if (trial_P)
2347 {
2348 SparseMatrix *m = mfem::Mult(*mat, *trial_P);
2349 delete mat;
2350 mat = m;
2351 }
2352
2353 EliminateTrialVDofs(trial_tdof_list);
2354 EliminateTestVDofs(test_tdof_list);
2355
2356 A.Reset(mat, false);
2357}
2358
2360 const Array<int> &trial_tdof_list,
2361 const Array<int> &test_tdof_list,
2362 Vector &x, Vector &b,
2363 OperatorHandle &A,
2364 Vector &X, Vector &B)
2365{
2366 if (ext)
2367 {
2368 ext->FormRectangularLinearSystem(trial_tdof_list, test_tdof_list,
2369 x, b, A, X, B);
2370 return;
2371 }
2372
2373 const Operator *Pi = this->GetProlongation();
2374 const Operator *Po = this->GetOutputProlongation();
2375 const Operator *Ri = this->GetRestriction();
2376 InitTVectors(Po, Ri, Pi, x, b, X, B);
2377
2378 if (!mat_e)
2379 {
2380 FormRectangularSystemMatrix(trial_tdof_list, test_tdof_list,
2381 A); // Set A = mat_e
2382 }
2383 // Eliminate essential BCs with B -= Ab xb
2384 EliminateTrialVDofsInRHS(trial_tdof_list, X, B);
2385
2386 B.SetSubVector(test_tdof_list, 0.0);
2387}
2388
2390{
2391 delete mat;
2392 mat = NULL;
2393 delete mat_e;
2394 mat_e = NULL;
2397 if (ext) { ext->Update(); }
2398}
2399
2401{
2402 if (mat) { delete mat; }
2403 if (mat_e) { delete mat_e; }
2404 if (!extern_bfs)
2405 {
2406 int i;
2407 for (i = 0; i < domain_integs.Size(); i++) { delete domain_integs[i]; }
2408 for (i = 0; i < boundary_integs.Size(); i++)
2409 { delete boundary_integs[i]; }
2410 for (i = 0; i < interior_face_integs.Size(); i++)
2411 { delete interior_face_integs[i]; }
2412 for (i = 0; i < boundary_face_integs.Size(); i++)
2413 { delete boundary_face_integs[i]; }
2414 for (i = 0; i < trace_face_integs.Size(); i++)
2415 { delete trace_face_integs[i]; }
2416 for (i = 0; i < boundary_trace_face_integs.Size(); i++)
2417 { delete boundary_trace_face_integs[i]; }
2418 }
2419}
2420
2422{
2423 if (ext)
2424 {
2425 MFEM_ABORT("the assembly level has already been set!");
2426 }
2427 assembly = assembly_level;
2428 switch (assembly)
2429 {
2432 // Use the original implementation for now
2433 break;
2435 MFEM_ABORT("Element assembly not supported yet... stay tuned!");
2436 break;
2438 ext.reset(new PADiscreteLinearOperatorExtension(this));
2439 break;
2441 MFEM_ABORT("Matrix-free action not supported yet... stay tuned!");
2442 break;
2443 default:
2444 MFEM_ABORT("Unknown assembly level");
2445 }
2446}
2447
2449{
2450 if (ext)
2451 {
2452 ext->Assemble();
2453 return;
2454 }
2455
2456 ElementTransformation *eltrans;
2457 DenseMatrix elmat;
2458
2459 Mesh *mesh = test_fes->GetMesh();
2460
2461 if (mat == NULL)
2462 {
2463 mat = new SparseMatrix(height, width);
2464 }
2465
2466 if (domain_integs.Size())
2467 {
2468 for (int k = 0; k < domain_integs.Size(); k++)
2469 {
2470 if (domain_integs_marker[k] != NULL)
2471 {
2472 MFEM_VERIFY(domain_integs_marker[k]->Size() ==
2473 (mesh->attributes.Size() ? mesh->attributes.Max() : 0),
2474 "invalid element marker for domain integrator #"
2475 << k << ", counting from zero");
2476 }
2477 }
2478
2479 DofTransformation dom_dof_trans;
2480 DofTransformation ran_dof_trans;
2481 for (int i = 0; i < test_fes->GetNE(); i++)
2482 {
2483 const int elem_attr = mesh->GetAttribute(i);
2484 trial_fes->GetElementVDofs(i, trial_vdofs, dom_dof_trans);
2485 test_fes->GetElementVDofs(i, test_vdofs, ran_dof_trans);
2486 eltrans = test_fes->GetElementTransformation(i);
2487
2489 elmat = 0.0;
2490 for (int k = 0; k < domain_integs.Size(); k++)
2491 {
2492 if (domain_integs_marker[k] == NULL ||
2493 (*(domain_integs_marker[k]))[elem_attr-1] == 1)
2494 {
2495 domain_integs[k]->AssembleElementMatrix2(*trial_fes->GetFE(i),
2496 *test_fes->GetFE(i),
2497 *eltrans, elemmat);
2498 elmat += elemmat;
2499 }
2500 }
2501 TransformPrimal(ran_dof_trans, dom_dof_trans, elemmat);
2503 }
2504 }
2505
2506 if (trace_face_integs.Size())
2507 {
2508 const int nfaces = test_fes->GetMesh()->GetNumFaces();
2509 for (int i = 0; i < nfaces; i++)
2510 {
2513 eltrans = test_fes->GetMesh()->GetFaceTransformation(i);
2514
2516 elmat = 0.0;
2517 for (int k = 0; k < trace_face_integs.Size(); k++)
2518 {
2519 trace_face_integs[k]->AssembleElementMatrix2(*trial_fes->GetFaceElement(i),
2521 *eltrans, elemmat);
2522 elmat += elemmat;
2523 }
2524 mat->SetSubMatrix(test_vdofs, trial_vdofs, elmat, skip_zeros);
2525 }
2526 }
2527}
2528
2529}
Dynamic 2D array using row-major layout.
Definition array.hpp:459
void SetSize(int m, int n)
Set the 2D array size to m x n.
Definition array.hpp:474
T Max() const
Find the maximal element in the array, using the comparison operator < for class T.
Definition array.cpp:69
const T * HostRead() const
Shortcut for mfem::Read(a.GetMemory(), a.Size(), false).
Definition array.hpp:414
int Size() const
Return the logical size of the array.
Definition array.hpp:192
int Append(const T &el)
Append element 'el' to array, resize if necessary.
Definition array.hpp:941
Abstract base class BilinearFormIntegrator.
A "square matrix" operator for the associated FE space and BLFIntegrators The sum of all the BLFInteg...
void AssembleDiagonal(Vector &diag) const override
Assemble the diagonal of the bilinear form into diag. Note that diag is a tdof Vector.
void SetAssemblyLevel(AssemblyLevel assembly_level)
Set the desired assembly level.
void SetDiagonalPolicy(DiagonalPolicy policy)
Sets Operator::DiagonalPolicy used upon construction of the linear system. Policies include:
Array< BilinearFormIntegrator * > domain_integs
Set of Domain Integrators to be applied.
Array< Array< int > * > domain_integs_marker
Entries are not owned.
void EnableStaticCondensation()
Enable the use of static condensation. For details see the description for class StaticCondensation i...
void AssembleBdrElementMatrix(int i, const DenseMatrix &elmat, int skip_zeros=1)
Assemble the given boundary element matrix.
Array< Array< int > * > boundary_face_integs_marker
Entries are not owned.
void UseSparsity(int *I, int *J, bool isSorted)
Use the given CSR sparsity pattern to allocate the internal SparseMatrix.
void EliminateVDofsInRHS(const Array< int > &vdofs, const Vector &x, Vector &b)
Use the stored eliminated part of the matrix (see EliminateVDofs(const Array<int> &,...
void AddDomainIntegrator(BilinearFormIntegrator *bfi)
Adds new Domain Integrator. Assumes ownership of bfi.
void ComputeElementMatrices()
Compute and store internally all element matrices.
Array< BilinearFormIntegrator * > boundary_face_integs
Set of boundary face Integrators to be applied.
virtual void Update(FiniteElementSpace *nfes=NULL)
Update the FiniteElementSpace and delete all data associated with the old one.
void AddMultTranspose(const Vector &x, Vector &y, const real_t a=1.0) const override
Add the matrix transpose vector multiplication: .
void ComputeFaceMatrix(int i, DenseMatrix &elmat) const
Compute the face matrix of the given face element.
void EliminateVDofs(const Array< int > &vdofs, const Vector &sol, Vector &rhs, DiagonalPolicy dpolicy=DIAG_ONE)
Eliminate the given vdofs. NOTE: here, vdofs is a list of DOFs.
void FreeElementMatrices()
Free the memory used by the element matrices.
void Finalize(int skip_zeros=1) override
Finalizes the matrix initialization if the AssemblyLevel is AssemblyLevel::LEGACY....
virtual ~BilinearForm()
Deletes internal matrices, bilinear integrators, and the BilinearFormExtension.
BilinearForm()
may be used in the construction of derived classes
void EliminateEssentialBCFromDofsDiag(const Array< int > &ess_dofs, real_t value)
Perform elimination and set the diagonal entry to the given value.
DiagonalPolicy diag_policy
This data member allows one to specify what should be done to the diagonal matrix entries and corresp...
void ComputeBdrFaceMatrix(int i, DenseMatrix &elmat) const
Compute the boundary face matrix of the given boundary element.
void AddBoundaryIntegrator(BilinearFormIntegrator *bfi)
Adds new Boundary Integrator. Assumes ownership of bfi.
void AllocMat()
Allocate appropriate SparseMatrix and assign it to mat.
void AddMult(const Vector &x, Vector &y, const real_t a=1.0) const override
Add the matrix vector multiple to a vector: .
void Assemble(int skip_zeros=1)
Assembles the form i.e. sums over all domain/bdr integrators.
void EnableHybridization(FiniteElementSpace *constr_space, BilinearFormIntegrator *constr_integ, const Array< int > &ess_tdof_list)
Enable hybridization.
real_t & Elem(int i, int j) override
Returns a reference to: .
int extern_bfs
Indicates the BilinearFormIntegrators stored in domain_integs, boundary_integs, interior_face_integs,...
void AddBdrFaceIntegrator(BilinearFormIntegrator *bfi)
Adds new boundary Face Integrator. Assumes ownership of bfi.
void AssembleElementMatrix(int i, const DenseMatrix &elmat, int skip_zeros=1)
Assemble the given element matrix.
Array< Array< int > * > boundary_integs_marker
Entries are not owned.
long sequence
Indicates the Mesh::sequence corresponding to the current state of the BilinearForm.
Array< BilinearFormIntegrator * > interior_face_integs
Set of interior face Integrators to be applied.
void EliminateEssentialBCFromDofs(const Array< int > &ess_dofs, const Vector &sol, Vector &rhs, DiagonalPolicy dpolicy=DIAG_ONE)
Similar to EliminateVDofs(const Array<int> &, const Vector &, Vector &,...
SparseMatrix * mat
Sparse matrix to be associated with the form. Owned.
AssemblyLevel assembly
The AssemblyLevel of the form (AssemblyLevel::LEGACY, AssemblyLevel::FULL, AssemblyLevel::ELEMENT,...
void MultTranspose(const Vector &x, Vector &y) const override
Matrix transpose vector multiplication: .
std::unique_ptr< StaticCondensation > static_cond
const DenseTensor & GetElementMatrices()
Return a DenseTensor containing the assembled element matrices.
void RecoverFEMSolution(const Vector &X, const Vector &b, Vector &x) override
Recover the solution of a linear system formed with FormLinearSystem().
std::unique_ptr< DenseTensor > element_matrices
FiniteElementSpace * fes
FE space on which the form lives. Not owned.
int batch
Element batch size used in the form action (1, 8, num_elems, etc.)
virtual void FormLinearSystem(const Array< int > &ess_tdof_list, Vector &x, Vector &b, OperatorHandle &A, Vector &X, Vector &B, int copy_interior=0)
Form the linear system A X = B, corresponding to this bilinear form and the linear form b(....
void ComputeElementMatrix(int i, DenseMatrix &elmat) const
Compute the element matrix of the given element.
int Size() const
Get the size of the BilinearForm as a square matrix.
void Mult(const Vector &x, Vector &y) const override
Matrix vector multiplication: .
std::unique_ptr< BilinearFormExtension > ext
Extension for supporting Full Assembly (FA), Element Assembly (EA),Partial Assembly (PA),...
MatrixInverse * Inverse() const override
Returns a pointer to (approximation) of the matrix inverse: (currently returns NULL)
void EliminateEssentialBC(const Array< int > &bdr_attr_is_ess, const Vector &sol, Vector &rhs, DiagonalPolicy dpolicy=DIAG_ONE)
Eliminate essential boundary DOFs from the system.
void ConformingAssemble()
For partially conforming trial and/or test FE spaces, complete the assembly process by performing wh...
Array< BilinearFormIntegrator * > boundary_integs
Set of Boundary Integrators to be applied.
std::unique_ptr< Hybridization > hybridization
void EliminateEssentialBCDiag(const Array< int > &bdr_attr_is_ess, real_t value)
Perform elimination and set the diagonal entry to the given value.
virtual void FormSystemMatrix(const Array< int > &ess_tdof_list, OperatorHandle &A)
Form the linear system matrix A, see FormLinearSystem() for details.
void ComputeBdrElementMatrix(int i, DenseMatrix &elmat) const
Compute the boundary element matrix of the given boundary element.
SparseMatrix * mat_e
Sparse Matrix used to store the eliminations from the b.c. Owned. .
void AddInteriorFaceIntegrator(BilinearFormIntegrator *bfi)
Adds new interior Face Integrator. Assumes ownership of bfi.
Square Operator for imposing essential boundary conditions using only the action, Mult(),...
Data type dense matrix using column-major storage.
Definition densemat.hpp:24
real_t * GetData() const
Returns the matrix data array. Warning: this method casts away constness.
Definition densemat.hpp:135
void SetSize(int s)
Change the size of the DenseMatrix to s x s.
Definition densemat.hpp:125
void ClearExternalData()
Definition densemat.hpp:112
int Size() const
For backward compatibility define Size to be synonym of Width()
Definition densemat.hpp:119
Rank 3 tensor (array of matrices)
virtual void Assemble(int skip_zeros=1)
Construct the internal matrix representation of the discrete linear operator.
void SetAssemblyLevel(AssemblyLevel assembly_level)
Set the desired assembly level. The default is AssemblyLevel::FULL.
void TransformDual(real_t *v) const
Definition doftrans.cpp:77
Data and methods for element-assembled bilinear forms.
Data and methods for fully-assembled bilinear forms.
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:210
const SparseMatrix * GetConformingRestriction() const
The returned SparseMatrix is owned by the FiniteElementSpace.
Definition fespace.cpp:1429
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:1278
const FiniteElement * GetBE(int i) const
Returns pointer to the FiniteElement in the FiniteElementCollection associated with i'th boundary fac...
Definition fespace.cpp:3906
virtual int GetTrueVSize() const
Return the number of vector true (conforming) dofs.
Definition fespace.hpp:827
ElementTransformation * GetElementTransformation(int i) const
Definition fespace.hpp:903
virtual const SparseMatrix * GetRestrictionMatrix() const
The returned SparseMatrix is owned by the FiniteElementSpace.
Definition fespace.hpp:714
static void ListToMarker(const Array< int > &list, int marker_size, Array< int > &marker, int mark_val=-1)
Convert an array of indices (list) to a Boolean marker array where all indices in the list are marked...
Definition fespace.cpp:775
const NURBSExtension * GetNURBSext() const
Definition fespace.hpp:641
virtual const Operator * GetProlongationMatrix() const
Definition fespace.hpp:691
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:299
virtual const FiniteElement * GetFE(int i) const
Returns pointer to the FiniteElement in the FiniteElementCollection associated with i'th element in t...
Definition fespace.cpp:3860
Ordering::Type GetOrdering() const
Return the ordering method.
Definition fespace.hpp:852
ElementTransformation * GetBdrElementTransformation(int i) const
Returns ElementTransformation for the i-th boundary element.
Definition fespace.hpp:912
int GetNE() const
Returns number of elements in the mesh.
Definition fespace.hpp:867
void GetFaceVDofs(int i, Array< int > &vdofs) const
Returns the indices of the degrees of freedom for the specified face, including the DOFs for the edge...
Definition fespace.cpp:326
const FiniteElement * GetFaceElement(int i) const
Returns pointer to the FiniteElement in the FiniteElementCollection associated with i'th face in the ...
Definition fespace.cpp:3949
const SparseMatrix * GetConformingProlongation() const
Definition fespace.cpp:1422
Mesh * GetMesh() const
Returns the mesh.
Definition fespace.hpp:639
int GetVSize() const
Return the number of vector dofs, i.e. GetNDofs() x GetVDim().
Definition fespace.hpp:824
int GetVDim() const
Returns the vector dimension of the finite element space.
Definition fespace.hpp:817
const FiniteElement * GetTypicalFE() const
Return GetFE(0) if the local mesh is not empty; otherwise return a typical FE based on the Geometry t...
Definition fespace.cpp:3896
DofTransformation * GetBdrElementVDofs(int i, Array< int > &vdofs) const
Returns indices of degrees of freedom for i'th boundary element. The returned indices are offsets int...
Definition fespace.cpp:314
virtual void GetEssentialVDofs(const Array< int > &bdr_attr_is_ess, Array< int > &ess_vdofs, int component=-1) const
Mark degrees of freedom associated with boundary elements with the specified boundary attributes (mar...
Definition fespace.cpp:550
void GetPatchVDofs(int i, Array< int > &vdofs) const
Returns indices of degrees of freedom in vdofs for NURBS patch i.
Definition fespace.cpp:320
Abstract class for all finite elements.
Definition fe_base.hpp:294
int GetDof() const
Returns the number of degrees of freedom in the finite element.
Definition fe_base.hpp:410
Auxiliary class Hybridization, used to implement BilinearForm hybridization.
A standard isoparametric element transformation.
Definition eltrans.hpp:629
Data and methods for matrix-free bilinear forms.
Abstract data type for matrix inverse.
Definition matrix.hpp:63
Abstract data type matrix.
Definition matrix.hpp:28
Class used by MFEM to store pointers to host and/or device memory.
Mesh data type.
Definition mesh.hpp:67
virtual FaceElementTransformations * GetFaceElementTransformations(int FaceNo, int mask=31)
Definition mesh.cpp:1179
Array< int > bdr_attributes
A list of all unique boundary attributes used by the Mesh.
Definition mesh.hpp:309
NURBSExtension * NURBSext
Optional NURBS mesh extension.
Definition mesh.hpp:317
int GetNumFaces() const
Return the number of faces (3D), edges (2D) or vertices (1D).
Definition mesh.cpp:7302
int GetAttribute(int i) const
Return the attribute of element i.
Definition mesh.hpp:1497
int GetBdrAttribute(int i) const
Return the attribute of boundary element i.
Definition mesh.hpp:1503
int GetBdrElementFaceIndex(int be_idx) const
Return the local face (codimension-1) index for the given boundary element index.
Definition mesh.hpp:1702
ElementTransformation * GetFaceTransformation(int FaceNo)
Returns a pointer to the transformation defining the given face element.
Definition mesh.cpp:610
FaceElementTransformations * GetBdrFaceTransformations(int BdrElemNo)
Builds the transformation defining the given boundary face.
Definition mesh.cpp:1298
FaceElementTransformations * GetInteriorFaceTransformations(int FaceNo)
See GetFaceElementTransformations().
Definition mesh.cpp:1278
Table * GetFaceToElementTable() const
Definition mesh.cpp:8284
Array< int > attributes
A list of all unique element attributes used by the Mesh.
Definition mesh.hpp:307
void AddBdrFaceIntegrator(BilinearFormIntegrator *bfi)
Adds a boundary face integrator. Assumes ownership of bfi.
void ConformingAssemble()
For partially conforming trial and/or test FE spaces, complete the assembly process by performing wh...
void AssembleBdrElementMatrix(int i, const DenseMatrix &elmat, int skip_zeros=1)
Assemble the given boundary element matrix.
void AddMult(const Vector &x, Vector &y, const real_t a=1.0) const override
Add the matrix vector multiple to a vector: .
void AddMultTranspose(const Vector &x, Vector &y, const real_t a=1.0) const override
Add the matrix transpose vector multiplication: .
Array< BilinearFormIntegrator * > boundary_face_integs
Boundary face integrators.
void EliminateTrialVDofsInRHS(const Array< int > &vdofs, const Vector &x, Vector &b)
Use the stored eliminated part of the matrix (see EliminateTrialVDofs(const Array<int> &)) to modify ...
void Assemble(int skip_zeros=1)
real_t & Elem(int i, int j) override
Returns a reference to: .
void Finalize(int skip_zeros=1) override
Finalizes the matrix initialization if the AssemblyLevel is AssemblyLevel::LEGACY.
void AddBoundaryIntegrator(BilinearFormIntegrator *bfi)
Adds a boundary integrator. Assumes ownership of bfi.
void AddInteriorFaceIntegrator(BilinearFormIntegrator *bfi)
Adds an interior face integrator. Assumes ownership of bfi.
virtual void FormRectangularSystemMatrix(const Array< int > &trial_tdof_list, const Array< int > &test_tdof_list, OperatorHandle &A)
Return in A that is column-constrained.
void ComputeFaceMatrix(int i, DenseMatrix &elmat) const
Compute the face matrix of the given face element.
void ComputeBdrTraceFaceMatrix(int i, DenseMatrix &elmat) const
Compute the boundary trace face matrix of the given boundary element.
void MultTranspose(const Vector &x, Vector &y) const override
Matrix transpose vector multiplication: .
void ComputeElementMatrix(int i, DenseMatrix &elmat) const
Compute the element matrix of the given element.
Array< Array< int > * > boundary_face_integs_marker
Entries are not owned.
void SetAssemblyLevel(AssemblyLevel assembly_level)
Set the desired assembly level. The default is AssemblyLevel::LEGACY.
int extern_bfs
Indicates the BilinearFormIntegrators stored in MixedBilinearForm::domain_integs, MixedBilinearForm::...
MatrixInverse * Inverse() const override
Returns a pointer to (approximation) of the matrix inverse: (currently unimplemented and returns NUL...
void EliminateTrialVDofs(const Array< int > &vdofs, const Vector &sol, Vector &rhs)
Eliminate the given trial vdofs. NOTE: here, vdofs is a list of DOFs.
void AssembleDiagonal_ADAt(const Vector &D, Vector &diag) const
Assemble the diagonal of ADA^T into diag, where A is this mixed bilinear form and D is a diagonal.
const Operator * GetOutputProlongation() const override
Get the test finite element space prolongation matrix.
Array< BilinearFormIntegrator * > interior_face_integs
Interior face integrators.
void ComputeTraceFaceMatrix(int i, DenseMatrix &elmat) const
Compute the trace face matrix of the given face element.
void EliminateTrialEssentialBC(const Array< int > &bdr_attr_is_ess, const Vector &sol, Vector &rhs)
Eliminate essential boundary trial DOFs from the system.
void AddBdrTraceFaceIntegrator(BilinearFormIntegrator *bfi)
Adds a boundary trace face integrator. Assumes ownership of bfi.
Array< Array< int > * > boundary_integs_marker
Entries are not owned.
Array< BilinearFormIntegrator * > trace_face_integs
Trace face (skeleton) integrators.
Array< BilinearFormIntegrator * > boundary_trace_face_integs
Boundary trace face (skeleton) integrators.
const Operator * GetRestriction() const override
Get the input finite element space restriction matrix.
Array< BilinearFormIntegrator * > domain_integs
Domain integrators.
SparseMatrix * mat
Owned.
void Update()
Must be called after making changes to trial_fes or test_fes.
Array< Array< int > * > domain_integs_marker
Entries are not owned.
const Operator * GetProlongation() const override
Get the input finite element space prolongation matrix.
void ComputeBdrFaceMatrix(int i, DenseMatrix &elmat) const
Compute the boundary face matrix of the given boundary element.
Array< BilinearFormIntegrator * > boundary_integs
Boundary integrators.
void EliminateEssentialBCFromTrialDofs(const Array< int > &marked_vdofs, const Vector &sol, Vector &rhs)
Similar to EliminateTrialVDofs(const Array<int> &, const Vector &, Vector &) but here ess_dofs is a m...
void AssembleElementMatrix(int i, const DenseMatrix &elmat, int skip_zeros=1)
Assemble the given element matrix.
Array< Array< int > * > boundary_trace_face_integs_marker
Entries are not owned.
virtual void FormRectangularLinearSystem(const Array< int > &trial_tdof_list, const Array< int > &test_tdof_list, Vector &x, Vector &b, OperatorHandle &A, Vector &X, Vector &B)
Form the linear system A X = B, corresponding to this mixed bilinear form and the linear form b(....
SparseMatrix * mat_e
Owned.
FiniteElementSpace * trial_fes
Not owned.
void GetBlocks(Array2D< SparseMatrix * > &blocks) const
Extract the associated matrix as SparseMatrix blocks. The number of block rows and columns is given b...
std::unique_ptr< MixedBilinearFormExtension > ext
void EliminateTestEssentialBC(const Array< int > &bdr_attr_is_ess)
Eliminate essential boundary test DOFs from the system matrix.
void AddTraceFaceIntegrator(BilinearFormIntegrator *bfi)
Add a trace face integrator. Assumes ownership of bfi.
void EliminateTestVDofs(const Array< int > &vdofs)
Eliminate the given test vdofs. NOTE: here, vdofs is a list of DOFs.
void Mult(const Vector &x, Vector &y) const override
Matrix multiplication: .
virtual ~MixedBilinearForm()
Deletes internal matrices, bilinear integrators, and the BilinearFormExtension.
FiniteElementSpace * test_fes
Not owned.
void AddDomainIntegrator(BilinearFormIntegrator *bfi)
Adds a domain integrator. Assumes ownership of bfi.
AssemblyLevel assembly
The form assembly level (full, partial, etc.)
void ComputeBdrElementMatrix(int i, DenseMatrix &elmat) const
Compute the boundary element matrix of the given boundary element.
int GetNP() const
Return the number of patches.
Definition nurbs.hpp:936
Pointer to an Operator of a specified type.
Definition handle.hpp:34
void Reset(OpType *A, bool own_A=true)
Reset the OperatorHandle to the given OpType pointer, A.
Definition handle.hpp:145
Abstract operator.
Definition operator.hpp:27
int width
Dimension of the input / number of columns in the matrix.
Definition operator.hpp:30
void FormSystemOperator(const Array< int > &ess_tdof_list, Operator *&A)
Return in A a parallel (on truedofs) version of this square operator.
Definition operator.cpp:242
int Height() const
Get the height (size of output) of the Operator. Synonym with NumRows().
Definition operator.hpp:68
int height
Dimension of the output / number of rows in the matrix.
Definition operator.hpp:29
virtual void Mult(const Vector &x, Vector &y) const =0
Operator application: y=A(x).
DiagonalPolicy
Defines operator diagonal policy upon elimination of rows and/or columns.
Definition operator.hpp:50
@ DIAG_ONE
Set the diagonal value to one.
Definition operator.hpp:52
@ DIAG_KEEP
Keep the diagonal value.
Definition operator.hpp:53
int Width() const
Get the width (size of input) of the Operator. Synonym with NumCols().
Definition operator.hpp:74
void InitTVectors(const Operator *Po, const Operator *Ri, const Operator *Pi, Vector &x, Vector &b, Vector &X, Vector &B) const
Initializes memory for true vectors of linear system.
Definition operator.cpp:22
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:102
Data and methods for partially-assembled bilinear forms.
Partial assembly extension for DiscreteLinearOperator.
Data and methods for partially-assembled mixed bilinear forms.
Data type sparse matrix.
Definition sparsemat.hpp:51
int GetRow(const int row, Array< int > &cols, Vector &srow) const override
Extract all column indices and values from a given row.
void GetDiag(Vector &d) const
Returns the Diagonal of A.
void PartMult(const Array< int > &rows, const Vector &x, Vector &y) const
bool ColumnsAreSorted() const
Returns whether or not the columns are sorted.
void MultTranspose(const Vector &x, Vector &y) const override
Multiply a vector with the transposed matrix. y = At * x.
bool Finalized() const
Returns whether or not CSR format has been finalized.
void SetSubMatrix(const Array< int > &rows, const Array< int > &cols, const DenseMatrix &subm, int skip_zeros=1)
void AddSubMatrix(const Array< int > &rows, const Array< int > &cols, const DenseMatrix &subm, int skip_zeros=1)
void BooleanMult(const Array< int > &x, Array< int > &y) const
y = A * x, treating all entries as booleans (zero=false, nonzero=true).
void AddMultTranspose(const Vector &x, Vector &y, const real_t a=1.0) const override
y += At * x (default) or y += a * At * x
void AddMult(const Vector &x, Vector &y, const real_t a=1.0) const override
y += A * x (default) or y += a * A * x
void Mult(const Vector &x, Vector &y) const override
Matrix vector multiplication.
void EliminateRow(int row, const real_t sol, Vector &rhs)
Eliminates a column from the transpose matrix.
void GetBlocks(Array2D< SparseMatrix * > &blocks) const
void AbsMultTranspose(const Vector &x, Vector &y) const override
y = |At| * x, using entry-wise absolute values of the transpose of matrix A
void Finalize(int skip_zeros=1) override
Finalize the matrix initialization, switching the storage format from LIL to CSR.
void EliminateCols(const Array< int > &cols, const Vector *x=NULL, Vector *b=NULL)
Eliminate all columns i for which cols[i] != 0.
int * GetJ()
Return the array J.
void AddRow(const int row, const Array< int > &cols, const Vector &srow)
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
int * GetI()
Definition table.hpp:127
void SortRows()
Sort the column (TYPE II) indices in each row.
Definition table.cpp:245
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
void SyncMemory(const Vector &v) const
Update the memory location of the vector to match v.
Definition vector.hpp:272
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:633
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
void MakeRef(Vector &base, int offset, int size)
Reset the Vector to be a reference to a sub-vector of base.
Definition vector.hpp:709
const int * ess_tdof_list
Mesh * GetMesh(int type)
Definition ex29.cpp:218
real_t b
Definition lissajous.cpp:42
real_t a
Definition lissajous.cpp:41
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 TransformDual(const DofTransformation &ran_dof_trans, const DofTransformation &dom_dof_trans, DenseMatrix &elmat)
Definition doftrans.cpp:152
void Transpose(const Table &A, Table &At, int ncols_A_)
Transpose a Table.
Definition table.cpp:443
AssemblyLevel
Enumeration defining the assembly level for bilinear and nonlinear form classes derived from Operator...
void RAP(const DenseMatrix &A, const DenseMatrix &P, DenseMatrix &RAP)
bool IsIdentityProlongation(const Operator *P)
Definition operator.hpp:892
float real_t
Definition config.hpp:46
void TransformPrimal(const DofTransformation &ran_dof_trans, const DofTransformation &dom_dof_trans, DenseMatrix &elmat)
Definition doftrans.cpp:137
@ NATIVE
Native ordering as defined by the FiniteElement.
std::function< real_t(const Vector &)> f(real_t mass_coeff)
Definition lor_mms.hpp:30
SparseMatrix * TransposeMult(const SparseMatrix &A, const SparseMatrix &B)
C = A^T B.
real_t p(const Vector &x, real_t t)
real_t sol(const Vector &x)