MFEM v4.9.0
Finite element discretization library
Loading...
Searching...
No Matches
bilinearform.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// 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,
161 const Array<int> &ess_tdof_list)
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);
176 hybridization->Init(ess_tdof_list);
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 {
732 fes -> GetElementVDofs (tr -> Elem1No, vdofs);
733 fe1 = fes -> GetFE (tr -> Elem1No);
734 // The fe2 object is really a dummy and not used on the boundaries,
735 // but we can't dereference a NULL pointer, and we don't want to
736 // actually make a fake element.
737 fe2 = fe1;
738 for (int k = 0; k < boundary_face_integs.Size(); k++)
739 {
741 (*boundary_face_integs_marker[k])[bdr_attr-1] == 0)
742 { continue; }
743
744 boundary_face_integs[k] -> AssembleFaceMatrix (*fe1, *fe2, *tr,
745 elemmat);
746 mat -> AddSubMatrix (vdofs, vdofs, elemmat, skip_zeros);
747 }
748 }
749 }
750 }
751
752#ifdef MFEM_USE_LEGACY_OPENMP
753 if (free_element_matrices)
754 {
756 }
757#endif
758}
759
761{
762 // Do not remove zero entries to preserve the symmetric structure of the
763 // matrix which in turn will give rise to symmetric structure in the new
764 // matrix. This ensures that subsequent calls to EliminateRowCol will work
765 // correctly.
766 Finalize(0);
767 MFEM_ASSERT(mat, "the BilinearForm is not assembled");
768
770 if (!P) { return; } // conforming mesh
771
772 SparseMatrix *R = Transpose(*P);
773 SparseMatrix *RA = mfem::Mult(*R, *mat);
774 delete mat;
775 if (mat_e)
776 {
777 SparseMatrix *RAe = mfem::Mult(*R, *mat_e);
778 delete mat_e;
779 mat_e = RAe;
780 }
781 delete R;
782 mat = mfem::Mult(*RA, *P);
783 delete RA;
784 if (mat_e)
785 {
786 SparseMatrix *RAeP = mfem::Mult(*mat_e, *P);
787 delete mat_e;
788 mat_e = RAeP;
789 }
790
791 height = mat->Height();
792 width = mat->Width();
793}
794
796{
797 MFEM_ASSERT(diag.Size() == fes->GetTrueVSize(),
798 "Vector for holding diagonal has wrong size!");
800 if (!ext)
801 {
802 MFEM_ASSERT(mat, "the BilinearForm is not assembled!");
803 MFEM_ASSERT(cP == nullptr || mat->Height() == cP->Width(),
804 "BilinearForm::ConformingAssemble() is not called!");
805 mat->GetDiag(diag);
806 return;
807 }
808 // Here, we have extension, ext.
809 if (!cP)
810 {
811 ext->AssembleDiagonal(diag);
812 return;
813 }
814 // Here, we have extension, ext, and conforming prolongation, cP.
815
816 // For an AMR mesh, a convergent diagonal is assembled with |P^T| d_l,
817 // where |P^T| has the entry-wise absolute values of the conforming
818 // prolongation transpose operator.
819 Vector local_diag(cP->Height());
820 ext->AssembleDiagonal(local_diag);
821 cP->AbsMultTranspose(local_diag, diag);
822}
823
825 Vector &b, OperatorHandle &A, Vector &X,
826 Vector &B, int copy_interior)
827{
828 if (ext)
829 {
830 if (hybridization)
831 {
832 FormSystemMatrix(ess_tdof_list, A);
833 ConstrainedOperator A_constrained(this, ess_tdof_list);
834 A_constrained.EliminateRHS(x, b);
835 hybridization->ReduceRHS(b, B);
836 X.SetSize(B.Size());
837 X = 0.0;
838 }
839 else
840 {
841 ext->FormLinearSystem(ess_tdof_list, x, b, A, X, B, copy_interior);
842 }
843 return;
844 }
846 FormSystemMatrix(ess_tdof_list, A);
847
848 // Transform the system and perform the elimination in B, based on the
849 // essential BC values from x. Restrict the BC part of x in X, and set the
850 // non-BC part to zero. Since there is no good initial guess for the Lagrange
851 // multipliers, set X = 0.0 for hybridization.
852 if (static_cond)
853 {
854 // Schur complement reduction to the exposed dofs
855 static_cond->ReduceSystem(x, b, X, B, copy_interior);
856 }
857 else if (!P) // conforming space
858 {
859 if (hybridization)
860 {
861 // Reduction to the Lagrange multipliers system
862 EliminateVDofsInRHS(ess_tdof_list, x, b);
863 hybridization->ReduceRHS(b, B);
864 X.SetSize(B.Size());
865 X = 0.0;
866 }
867 else
868 {
869 // A, X and B point to the same data as mat, x and b
870 EliminateVDofsInRHS(ess_tdof_list, x, b);
871 X.MakeRef(x, 0, x.Size());
872 B.MakeRef(b, 0, b.Size());
873 if (!copy_interior) { X.SetSubVectorComplement(ess_tdof_list, 0.0); }
874 }
875 }
876 else // non-conforming space
877 {
878 if (hybridization)
879 {
880 // Reduction to the Lagrange multipliers system
882 Vector conf_b(P->Width()), conf_x(P->Width());
883 P->MultTranspose(b, conf_b);
884 R->Mult(x, conf_x);
885 EliminateVDofsInRHS(ess_tdof_list, conf_x, conf_b);
886 R->MultTranspose(conf_b, b); // store eliminated rhs in b
887 hybridization->ReduceRHS(conf_b, B);
888 X.SetSize(B.Size());
889 X = 0.0;
890 }
891 else
892 {
893 // Variational restriction with P
895 B.SetSize(P->Width());
896 P->MultTranspose(b, B);
897 X.SetSize(R->Height());
898 R->Mult(x, X);
899 EliminateVDofsInRHS(ess_tdof_list, X, B);
900 if (!copy_interior) { X.SetSubVectorComplement(ess_tdof_list, 0.0); }
901 }
902 }
903}
904
907{
908 if (ext)
909 {
910 if (hybridization)
911 {
912 const int remove_zeros = 0;
913 Finalize(remove_zeros);
914 A.Reset(&hybridization->GetMatrix(), false);
915 }
916 else
917 {
918 ext->FormSystemMatrix(ess_tdof_list, A);
919 }
920 return;
921 }
922
923 // Finish the matrix assembly and perform BC elimination, storing the
924 // eliminated part of the matrix.
925 if (static_cond)
926 {
927 if (!static_cond->HasEliminatedBC())
928 {
929 static_cond->SetEssentialTrueDofs(ess_tdof_list);
930 static_cond->Finalize(); // finalize Schur complement (to true dofs)
931 static_cond->EliminateReducedTrueDofs(diag_policy);
932 static_cond->Finalize(); // finalize eliminated part
933 }
934 A.Reset(&static_cond->GetMatrix(), false);
935 }
936 else
937 {
938 if (!mat_e)
939 {
941 if (P) { ConformingAssemble(); }
942 EliminateVDofs(ess_tdof_list, diag_policy);
943 const int remove_zeros = 0;
944 Finalize(remove_zeros);
945 }
946 if (hybridization)
947 {
948 A.Reset(&hybridization->GetMatrix(), false);
949 }
950 else
951 {
952 A.Reset(mat, false);
953 }
954 }
955}
956
958 const Vector &b, Vector &x)
959{
960 if (ext && !hybridization)
961 {
962 ext->RecoverFEMSolution(X, b, x);
963 return;
964 }
965
967 if (!P) // conforming space
968 {
969 if (static_cond)
970 {
971 // Private dofs back solve
972 static_cond->ComputeSolution(b, X, x);
973 }
974 else if (hybridization)
975 {
976 // Primal unknowns recovery
977 hybridization->ComputeSolution(b, X, x);
978 }
979 else
980 {
981 // X and x point to the same data
982
983 // If the validity flags of X's Memory were changed (e.g. if it was
984 // moved to device memory) then we need to tell x about that.
985 x.SyncMemory(X);
986 }
987 }
988 else // non-conforming space
989 {
990 if (static_cond)
991 {
992 // Private dofs back solve
993 static_cond->ComputeSolution(b, X, x);
994 }
995 else if (hybridization)
996 {
997 // Primal unknowns recovery
998 Vector conf_b(P->Width()), conf_x(P->Width());
999 P->MultTranspose(b, conf_b);
1001 R->Mult(x, conf_x); // get essential b.c. from x
1002 hybridization->ComputeSolution(conf_b, X, conf_x);
1003 x.SetSize(P->Height());
1004 P->Mult(conf_x, x);
1005 }
1006 else
1007 {
1008 // Apply conforming prolongation
1009 x.SetSize(P->Height());
1010 P->Mult(X, x);
1011 }
1012 }
1013}
1014
1016{
1017 if (element_matrices) { return; }
1018
1019 if (auto *ea_ext = dynamic_cast<EABilinearFormExtension*>(ext.get()))
1020 {
1021 element_matrices.reset(new DenseTensor);
1022 ea_ext->GetElementMatrices(*element_matrices, ElementDofOrdering::NATIVE, true);
1023 return;
1024 }
1025
1026 if (domain_integs.Size() == 0 || fes->GetNE() == 0)
1027 {
1028 element_matrices.reset(new DenseTensor);
1029 return;
1030 }
1031
1032 int num_elements = fes->GetNE();
1033 int num_dofs_per_el = fes->GetTypicalFE()->GetDof() * fes->GetVDim();
1034
1035 element_matrices.reset(new DenseTensor(num_dofs_per_el, num_dofs_per_el,
1036 num_elements));
1037
1038 DenseMatrix tmp;
1040
1041#ifdef MFEM_USE_LEGACY_OPENMP
1042 #pragma omp parallel for private(tmp,eltrans)
1043#endif
1044 for (int i = 0; i < num_elements; i++)
1045 {
1046 DenseMatrix elmat(element_matrices->GetData(i),
1047 num_dofs_per_el, num_dofs_per_el);
1048 const FiniteElement &fe = *fes->GetFE(i);
1049#ifdef MFEM_DEBUG
1050 if (num_dofs_per_el != fe.GetDof()*fes->GetVDim())
1051 mfem_error("BilinearForm::ComputeElementMatrices:"
1052 " all elements must have same number of dofs");
1053#endif
1054 fes->GetElementTransformation(i, &eltrans);
1055
1056 domain_integs[0]->AssembleElementMatrix(fe, eltrans, elmat);
1057 for (int k = 1; k < domain_integs.Size(); k++)
1058 {
1059 // note: some integrators may not be thread-safe
1060 domain_integs[k]->AssembleElementMatrix(fe, eltrans, tmp);
1061 elmat += tmp;
1062 }
1063 elmat.ClearExternalData();
1064 }
1065}
1066
1068{
1069 ComputeElementMatrices(); // Won't recompute if element_matrices exists
1070 return *element_matrices;
1071}
1072
1074 const Vector &sol, Vector &rhs,
1075 DiagonalPolicy dpolicy)
1076{
1077 Array<int> ess_dofs, conf_ess_dofs;
1078 fes->GetEssentialVDofs(bdr_attr_is_ess, ess_dofs);
1079
1080 if (fes->GetVSize() == height)
1081 {
1082 EliminateEssentialBCFromDofs(ess_dofs, sol, rhs, dpolicy);
1083 }
1084 else
1085 {
1086 fes->GetRestrictionMatrix()->BooleanMult(ess_dofs, conf_ess_dofs);
1087 EliminateEssentialBCFromDofs(conf_ess_dofs, sol, rhs, dpolicy);
1088 }
1089}
1090
1092 DiagonalPolicy dpolicy)
1093{
1094 Array<int> ess_dofs, conf_ess_dofs;
1095 fes->GetEssentialVDofs(bdr_attr_is_ess, ess_dofs);
1096
1097 if (fes->GetVSize() == height)
1098 {
1099 EliminateEssentialBCFromDofs(ess_dofs, dpolicy);
1100 }
1101 else
1102 {
1103 fes->GetRestrictionMatrix()->BooleanMult(ess_dofs, conf_ess_dofs);
1104 EliminateEssentialBCFromDofs(conf_ess_dofs, dpolicy);
1105 }
1106}
1107
1109 real_t value)
1110{
1111 Array<int> ess_dofs, conf_ess_dofs;
1112 fes->GetEssentialVDofs(bdr_attr_is_ess, ess_dofs);
1113
1114 if (fes->GetVSize() == height)
1115 {
1116 EliminateEssentialBCFromDofsDiag(ess_dofs, value);
1117 }
1118 else
1119 {
1120 fes->GetRestrictionMatrix()->BooleanMult(ess_dofs, conf_ess_dofs);
1121 EliminateEssentialBCFromDofsDiag(conf_ess_dofs, value);
1122 }
1123}
1124
1126 const Vector &sol, Vector &rhs,
1127 DiagonalPolicy dpolicy)
1128{
1129 vdofs_.HostRead();
1130 for (int i = 0; i < vdofs_.Size(); i++)
1131 {
1132 int vdof = vdofs_[i];
1133 if ( vdof >= 0 )
1134 {
1135 mat -> EliminateRowCol (vdof, sol(vdof), rhs, dpolicy);
1136 }
1137 else
1138 {
1139 mat -> EliminateRowCol (-1-vdof, sol(-1-vdof), rhs, dpolicy);
1140 }
1141 }
1142}
1143
1145 DiagonalPolicy dpolicy)
1146{
1147 if (mat_e == NULL)
1148 {
1149 mat_e = new SparseMatrix(height);
1150 }
1151
1152 vdofs_.HostRead();
1153 for (int i = 0; i < vdofs_.Size(); i++)
1154 {
1155 int vdof = vdofs_[i];
1156 if ( vdof >= 0 )
1157 {
1158 mat -> EliminateRowCol (vdof, *mat_e, dpolicy);
1159 }
1160 else
1161 {
1162 mat -> EliminateRowCol (-1-vdof, *mat_e, dpolicy);
1163 }
1164 }
1165}
1166
1168 const Array<int> &ess_dofs, const Vector &sol, Vector &rhs,
1169 DiagonalPolicy dpolicy)
1170{
1171 MFEM_ASSERT(ess_dofs.Size() == height, "incorrect dof Array size");
1172 MFEM_ASSERT(sol.Size() == height, "incorrect sol Vector size");
1173 MFEM_ASSERT(rhs.Size() == height, "incorrect rhs Vector size");
1174
1175 for (int i = 0; i < ess_dofs.Size(); i++)
1176 if (ess_dofs[i] < 0)
1177 {
1178 mat -> EliminateRowCol (i, sol(i), rhs, dpolicy);
1179 }
1180}
1181
1183 DiagonalPolicy dpolicy)
1184{
1185 MFEM_ASSERT(ess_dofs.Size() == height,
1186 "incorrect dof Array size: " << ess_dofs.Size() << ' ' << height);
1187
1188 for (int i = 0; i < ess_dofs.Size(); i++)
1189 if (ess_dofs[i] < 0)
1190 {
1191 mat -> EliminateRowCol (i, dpolicy);
1192 }
1193}
1194
1196 real_t value)
1197{
1198 MFEM_ASSERT(ess_dofs.Size() == height,
1199 "incorrect dof Array size: " << ess_dofs.Size() << ' ' << height);
1200
1201 for (int i = 0; i < ess_dofs.Size(); i++)
1202 if (ess_dofs[i] < 0)
1203 {
1204 mat -> EliminateRowColDiag (i, value);
1205 }
1206}
1207
1209 const Array<int> &vdofs_, const Vector &x, Vector &b)
1210{
1211 mat_e->AddMult(x, b, -1.);
1212 mat->PartMult(vdofs_, x, b);
1213}
1214
1215void BilinearForm::Mult(const Vector &x, Vector &y) const
1216{
1217 if (ext)
1218 {
1219 ext->Mult(x, y);
1220 }
1221 else
1222 {
1223 mat->Mult(x, y);
1224 }
1225}
1226
1228{
1229 if (ext)
1230 {
1231 ext->MultTranspose(x, y);
1232 }
1233 else
1234 {
1235 y = 0.0;
1236 AddMultTranspose (x, y);
1237 }
1238}
1239
1241{
1242 bool full_update;
1243
1244 if (nfes && nfes != fes)
1245 {
1246 full_update = true;
1247 fes = nfes;
1248 }
1249 else
1250 {
1251 // Check for different size (e.g. assembled form on non-conforming space)
1252 // or different sequence number.
1253 full_update = (fes->GetVSize() != Height() ||
1254 sequence < fes->GetSequence());
1255 }
1256
1257 delete mat_e;
1258 mat_e = NULL;
1260 static_cond.reset();
1261
1262 if (full_update)
1263 {
1264 delete mat;
1265 mat = NULL;
1266 hybridization.reset();
1268 }
1269 else
1270 {
1271 if (mat) { *mat = 0.0; }
1272 if (hybridization) { hybridization->Reset(); }
1273 }
1274
1275 height = width = fes->GetVSize();
1276
1277 if (ext) { ext->Update(); }
1278}
1279
1281{
1282 diag_policy = policy;
1283}
1284
1286{
1287 delete mat_e;
1288 delete mat;
1289
1290 if (!extern_bfs)
1291 {
1292 int k;
1293 for (k=0; k < domain_integs.Size(); k++) { delete domain_integs[k]; }
1294 for (k=0; k < boundary_integs.Size(); k++) { delete boundary_integs[k]; }
1295 for (k=0; k < interior_face_integs.Size(); k++)
1296 { delete interior_face_integs[k]; }
1297 for (k=0; k < boundary_face_integs.Size(); k++)
1298 { delete boundary_face_integs[k]; }
1299 }
1300}
1301
1302
1303MixedBilinearForm::MixedBilinearForm (FiniteElementSpace *tr_fes,
1304 FiniteElementSpace *te_fes)
1305 : Matrix(te_fes->GetVSize(), tr_fes->GetVSize())
1306{
1307 trial_fes = tr_fes;
1308 test_fes = te_fes;
1309 mat = NULL;
1310 mat_e = NULL;
1311 extern_bfs = 0;
1313 ext = NULL;
1314}
1315
1316MixedBilinearForm::MixedBilinearForm (FiniteElementSpace *tr_fes,
1317 FiniteElementSpace *te_fes,
1318 MixedBilinearForm * mbf)
1319 : Matrix(te_fes->GetVSize(), tr_fes->GetVSize())
1320{
1321 trial_fes = tr_fes;
1322 test_fes = te_fes;
1323 mat = NULL;
1324 mat_e = NULL;
1325 extern_bfs = 1;
1326
1327 // Copy the pointers to the integrators
1330
1333
1335
1338
1340 ext = NULL;
1341}
1342
1344{
1345 if (ext)
1346 {
1347 MFEM_ABORT("the assembly level has already been set!");
1348 }
1349 assembly = assembly_level;
1350 switch (assembly)
1351 {
1353 break;
1355 // ext.reset(new FAMixedBilinearFormExtension(this));
1356 // Use the original BilinearForm implementation for now
1357 break;
1359 MFEM_ABORT("Element assembly not supported yet... stay tuned!");
1360 // ext.reset(new EAMixedBilinearFormExtension(this));
1361 break;
1363 ext.reset(new PAMixedBilinearFormExtension(this));
1364 break;
1366 MFEM_ABORT("Matrix-free action not supported yet... stay tuned!");
1367 // ext.reset(new MFMixedBilinearFormExtension(this));
1368 break;
1369 default:
1370 MFEM_ABORT("Unknown assembly level");
1371 }
1372}
1373
1375{
1376 return (*mat)(i, j);
1377}
1378
1379const real_t & MixedBilinearForm::Elem (int i, int j) const
1380{
1381 return (*mat)(i, j);
1382}
1383
1384void MixedBilinearForm::Mult(const Vector & x, Vector & y) const
1385{
1386 y = 0.0;
1387 AddMult(x, y);
1388}
1389
1391 const real_t a) const
1392{
1393 if (ext)
1394 {
1395 ext->AddMult(x, y, a);
1396 }
1397 else
1398 {
1399 mat->AddMult(x, y, a);
1400 }
1401}
1402
1404{
1405 y = 0.0;
1406 AddMultTranspose(x, y);
1407}
1408
1410 const real_t a) const
1411{
1412 if (ext)
1413 {
1414 ext->AddMultTranspose(x, y, a);
1415 }
1416 else
1417 {
1418 mat->AddMultTranspose(x, y, a);
1419 }
1420}
1421
1423{
1425 {
1426 MFEM_WARNING("MixedBilinearForm::Inverse not possible with this "
1427 "assembly level!");
1428 return NULL;
1429 }
1430 else
1431 {
1432 return mat -> Inverse ();
1433 }
1434}
1435
1436void MixedBilinearForm::Finalize (int skip_zeros)
1437{
1439 {
1440 mat -> Finalize (skip_zeros);
1441 }
1442}
1443
1445{
1446 MFEM_VERIFY(trial_fes->GetOrdering() == Ordering::byNODES &&
1448 "MixedBilinearForm::GetBlocks: both trial and test spaces "
1449 "must use Ordering::byNODES!");
1450
1451 blocks.SetSize(test_fes->GetVDim(), trial_fes->GetVDim());
1452
1453 mat->GetBlocks(blocks);
1454}
1455
1457{
1458 domain_integs.Append(bfi);
1459 domain_integs_marker.Append(NULL); // NULL marker means apply everywhere
1460}
1461
1463 Array<int> &elem_marker)
1464{
1465 domain_integs.Append(bfi);
1466 domain_integs_marker.Append(&elem_marker);
1467}
1468
1470{
1471 boundary_integs.Append(bfi);
1472 boundary_integs_marker.Append(NULL); // NULL marker means apply everywhere
1473}
1474
1476 Array<int> &bdr_marker)
1477{
1478 boundary_integs.Append(bfi);
1479 boundary_integs_marker.Append(&bdr_marker);
1480}
1481
1486
1488{
1489 boundary_face_integs.Append(bfi);
1490 boundary_face_integs_marker.Append(NULL); // NULL marker means apply everywhere
1491}
1492
1494 Array<int> &bdr_marker)
1495{
1496 boundary_face_integs.Append(bfi);
1497 boundary_face_integs_marker.Append(&bdr_marker);
1498}
1499
1504
1506{
1507 boundary_trace_face_integs.Append(bfi);
1508 // NULL marker means apply everywhere
1510}
1511
1518
1520{
1521 if (ext)
1522 {
1523 ext->Assemble();
1524 return;
1525 }
1526
1527 ElementTransformation *eltrans;
1528 DenseMatrix elmat;
1529
1530 Mesh *mesh = test_fes -> GetMesh();
1531
1532 if (mat == NULL)
1533 {
1534 mat = new SparseMatrix(height, width);
1535 }
1536
1537 if (domain_integs.Size())
1538 {
1539 for (int k = 0; k < domain_integs.Size(); k++)
1540 {
1541 if (domain_integs_marker[k] != NULL)
1542 {
1543 MFEM_VERIFY(domain_integs_marker[k]->Size() ==
1544 (mesh->attributes.Size() ? mesh->attributes.Max() : 0),
1545 "invalid element marker for domain integrator #"
1546 << k << ", counting from zero");
1547 }
1548 }
1549
1550 DofTransformation dom_dof_trans, ran_dof_trans;
1551 for (int i = 0; i < test_fes -> GetNE(); i++)
1552 {
1553 const int elem_attr = mesh->GetAttribute(i);
1554 trial_fes->GetElementVDofs (i, trial_vdofs, dom_dof_trans);
1555 test_fes->GetElementVDofs (i, test_vdofs, ran_dof_trans);
1556 eltrans = test_fes -> GetElementTransformation (i);
1557
1559 elmat = 0.0;
1560 for (int k = 0; k < domain_integs.Size(); k++)
1561 {
1562 if (domain_integs_marker[k] == NULL ||
1563 (*(domain_integs_marker[k]))[elem_attr-1] == 1)
1564 {
1565 domain_integs[k] -> AssembleElementMatrix2 (*trial_fes -> GetFE(i),
1566 *test_fes -> GetFE(i),
1567 *eltrans, elemmat);
1568 elmat += elemmat;
1569 }
1570 }
1571 TransformDual(ran_dof_trans, dom_dof_trans, elmat);
1572 mat -> AddSubMatrix (test_vdofs, trial_vdofs, elmat, skip_zeros);
1573 }
1574 }
1575
1576 if (boundary_integs.Size())
1577 {
1578 // Which boundary attributes need to be processed?
1579 Array<int> bdr_attr_marker(mesh->bdr_attributes.Size() ?
1580 mesh->bdr_attributes.Max() : 0);
1581 bdr_attr_marker = 0;
1582 for (int k = 0; k < boundary_integs.Size(); k++)
1583 {
1584 if (boundary_integs_marker[k] == NULL)
1585 {
1586 bdr_attr_marker = 1;
1587 break;
1588 }
1589 Array<int> &bdr_marker = *boundary_integs_marker[k];
1590 MFEM_ASSERT(bdr_marker.Size() == bdr_attr_marker.Size(),
1591 "invalid boundary marker for boundary integrator #"
1592 << k << ", counting from zero");
1593 for (int i = 0; i < bdr_attr_marker.Size(); i++)
1594 {
1595 bdr_attr_marker[i] |= bdr_marker[i];
1596 }
1597 }
1598
1599 DofTransformation dom_dof_trans, ran_dof_trans;
1600 for (int i = 0; i < test_fes -> GetNBE(); i++)
1601 {
1602 const int bdr_attr = mesh->GetBdrAttribute(i);
1603 if (bdr_attr_marker[bdr_attr-1] == 0) { continue; }
1604
1605 trial_fes->GetBdrElementVDofs (i, trial_vdofs, dom_dof_trans);
1606 test_fes->GetBdrElementVDofs (i, test_vdofs, ran_dof_trans);
1607 eltrans = test_fes -> GetBdrElementTransformation (i);
1608
1610 elmat = 0.0;
1611 for (int k = 0; k < boundary_integs.Size(); k++)
1612 {
1613 if (boundary_integs_marker[k] &&
1614 (*boundary_integs_marker[k])[bdr_attr-1] == 0) { continue; }
1615
1616 boundary_integs[k]->AssembleElementMatrix2 (*trial_fes -> GetBE(i),
1617 *test_fes -> GetBE(i),
1618 *eltrans, elemmat);
1619 elmat += elemmat;
1620 }
1621 TransformDual(ran_dof_trans, dom_dof_trans, elmat);
1622 mat -> AddSubMatrix (test_vdofs, trial_vdofs, elmat, skip_zeros);
1623 }
1624 }
1625
1626 if (interior_face_integs.Size())
1627 {
1629 Array<int> trial_vdofs2, test_vdofs2;
1630 const FiniteElement *trial_fe1, *trial_fe2, *test_fe1, *test_fe2;
1631
1632 int nfaces = mesh->GetNumFaces();
1633 for (int i = 0; i < nfaces; i++)
1634 {
1635 ftr = mesh->GetInteriorFaceTransformations(i);
1636 if (ftr != NULL)
1637 {
1640 trial_fe1 = trial_fes->GetFE(ftr->Elem1No);
1641 test_fe1 = test_fes->GetFE(ftr->Elem1No);
1642 if (ftr->Elem2No >= 0)
1643 {
1644 trial_fes->GetElementVDofs(ftr->Elem2No, trial_vdofs2);
1645 test_fes->GetElementVDofs(ftr->Elem2No, test_vdofs2);
1646 trial_vdofs.Append(trial_vdofs2);
1647 test_vdofs.Append(test_vdofs2);
1648 trial_fe2 = trial_fes->GetFE(ftr->Elem2No);
1649 test_fe2 = test_fes->GetFE(ftr->Elem2No);
1650 }
1651 else
1652 {
1653 // The test_fe2 object is really a dummy and not used on the
1654 // boundaries, but we can't dereference a NULL pointer, and we don't
1655 // want to actually make a fake element.
1656 trial_fe2 = trial_fe1;
1657 test_fe2 = test_fe1;
1658 }
1659 for (int k = 0; k < interior_face_integs.Size(); k++)
1660 {
1661 interior_face_integs[k]->AssembleFaceMatrix(*trial_fe1, *test_fe1, *trial_fe2,
1662 *test_fe2,
1663 *ftr, elemmat);
1665 }
1666 }
1667 }
1668 }
1669
1670 if (boundary_face_integs.Size())
1671 {
1673 Array<int> tr_vdofs2, te_vdofs2;
1674 const FiniteElement *trial_fe1, *trial_fe2, *test_fe1, *test_fe2;
1675
1676 // Which boundary attributes need to be processed?
1677 Array<int> bdr_attr_marker(mesh->bdr_attributes.Size() ?
1678 mesh->bdr_attributes.Max() : 0);
1679 bdr_attr_marker = 0;
1680 for (int k = 0; k < boundary_face_integs.Size(); k++)
1681 {
1682 if (boundary_face_integs_marker[k] == NULL)
1683 {
1684 bdr_attr_marker = 1;
1685 break;
1686 }
1687 Array<int> &bdr_marker = *boundary_face_integs_marker[k];
1688 MFEM_ASSERT(bdr_marker.Size() == bdr_attr_marker.Size(),
1689 "invalid boundary marker for boundary face integrator #"
1690 << k << ", counting from zero");
1691 for (int i = 0; i < bdr_attr_marker.Size(); i++)
1692 {
1693 bdr_attr_marker[i] |= bdr_marker[i];
1694 }
1695 }
1696
1697 for (int i = 0; i < trial_fes -> GetNBE(); i++)
1698 {
1699 const int bdr_attr = mesh->GetBdrAttribute(i);
1700 if (bdr_attr_marker[bdr_attr-1] == 0) { continue; }
1701
1702 ftr = mesh -> GetBdrFaceTransformations (i);
1703 if (ftr != NULL)
1704 {
1707 trial_fe1 = trial_fes->GetFE(ftr->Elem1No);
1708 test_fe1 = test_fes->GetFE(ftr->Elem1No);
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 for (int k = 0; k < boundary_face_integs.Size(); k++)
1715 {
1717 (*boundary_face_integs_marker[k])[bdr_attr-1] == 0) { continue; }
1718
1719 boundary_face_integs[k]->AssembleFaceMatrix(*trial_fe1, *test_fe1, *trial_fe2,
1720 *test_fe2,
1721 *ftr, elemmat);
1723 }
1724 }
1725 }
1726 }
1727
1728 if (trace_face_integs.Size())
1729 {
1731 Array<int> test_vdofs2;
1732 const FiniteElement *trial_face_fe, *test_fe1, *test_fe2;
1733
1734 int nfaces = mesh->GetNumFaces();
1735 for (int i = 0; i < nfaces; i++)
1736 {
1737 ftr = mesh->GetFaceElementTransformations(i);
1740 trial_face_fe = trial_fes->GetFaceElement(i);
1741 test_fe1 = test_fes->GetFE(ftr->Elem1No);
1742 if (ftr->Elem2No >= 0)
1743 {
1744 test_fes->GetElementVDofs(ftr->Elem2No, test_vdofs2);
1745 test_vdofs.Append(test_vdofs2);
1746 test_fe2 = test_fes->GetFE(ftr->Elem2No);
1747 }
1748 else
1749 {
1750 // The test_fe2 object is really a dummy and not used on the
1751 // boundaries, but we can't dereference a NULL pointer, and we don't
1752 // want to actually make a fake element.
1753 test_fe2 = test_fe1;
1754 }
1755 for (int k = 0; k < trace_face_integs.Size(); k++)
1756 {
1757 trace_face_integs[k]->AssembleFaceMatrix(*trial_face_fe, *test_fe1,
1758 *test_fe2, *ftr, elemmat);
1760 }
1761 }
1762 }
1763
1764 if (boundary_trace_face_integs.Size())
1765 {
1767 Array<int> te_vdofs2;
1768 const FiniteElement *trial_face_fe, *test_fe1, *test_fe2;
1769
1770 // Which boundary attributes need to be processed?
1771 Array<int> bdr_attr_marker(mesh->bdr_attributes.Size() ?
1772 mesh->bdr_attributes.Max() : 0);
1773 bdr_attr_marker = 0;
1774 for (int k = 0; k < boundary_trace_face_integs.Size(); k++)
1775 {
1776 if (boundary_trace_face_integs_marker[k] == NULL)
1777 {
1778 bdr_attr_marker = 1;
1779 break;
1780 }
1782 MFEM_ASSERT(bdr_marker.Size() == bdr_attr_marker.Size(),
1783 "invalid boundary marker for boundary trace face"
1784 "integrator #" << k << ", counting from zero");
1785 for (int i = 0; i < bdr_attr_marker.Size(); i++)
1786 {
1787 bdr_attr_marker[i] |= bdr_marker[i];
1788 }
1789 }
1790
1791 for (int i = 0; i < trial_fes -> GetNBE(); i++)
1792 {
1793 const int bdr_attr = mesh->GetBdrAttribute(i);
1794 if (bdr_attr_marker[bdr_attr-1] == 0) { continue; }
1795
1796 ftr = mesh->GetBdrFaceTransformations(i);
1797 if (ftr)
1798 {
1799 const int iface = mesh->GetBdrElementFaceIndex(i);
1802 trial_face_fe = trial_fes->GetFaceElement(iface);
1803 test_fe1 = test_fes->GetFE(ftr->Elem1No);
1804 // The test_fe2 object is really a dummy and not used on the
1805 // boundaries, but we can't dereference a NULL pointer, and we don't
1806 // want to actually make a fake element.
1807 test_fe2 = test_fe1;
1808 for (int k = 0; k < boundary_trace_face_integs.Size(); k++)
1809 {
1811 (*boundary_trace_face_integs_marker[k])[bdr_attr-1] == 0)
1812 { continue; }
1813
1814 boundary_trace_face_integs[k]->AssembleFaceMatrix(*trial_face_fe,
1815 *test_fe1,
1816 *test_fe2,
1817 *ftr, elemmat);
1819 }
1820 }
1821 }
1822 }
1823}
1824
1826 Vector &diag) const
1827{
1828 if (ext)
1829 {
1830 MFEM_ASSERT(diag.Size() == test_fes->GetTrueVSize(),
1831 "Vector for holding diagonal has wrong size!");
1832 MFEM_ASSERT(D.Size() == trial_fes->GetTrueVSize(),
1833 "Vector for holding diagonal has wrong size!");
1834 const Operator *P_trial = trial_fes->GetProlongationMatrix();
1835 const Operator *P_test = test_fes->GetProlongationMatrix();
1836 if (!IsIdentityProlongation(P_trial))
1837 {
1838 Vector local_D(P_trial->Height());
1839 P_trial->Mult(D, local_D);
1840
1841 if (!IsIdentityProlongation(P_test))
1842 {
1843 Vector local_diag(P_test->Height());
1844 ext->AssembleDiagonal_ADAt(local_D, local_diag);
1845 P_test->MultTranspose(local_diag, diag);
1846 }
1847 else
1848 {
1849 ext->AssembleDiagonal_ADAt(local_D, diag);
1850 }
1851 }
1852 else
1853 {
1854 if (!IsIdentityProlongation(P_test))
1855 {
1856 Vector local_diag(P_test->Height());
1857 ext->AssembleDiagonal_ADAt(D, local_diag);
1858 P_test->MultTranspose(local_diag, diag);
1859 }
1860 else
1861 {
1862 ext->AssembleDiagonal_ADAt(D, diag);
1863 }
1864 }
1865 }
1866 else
1867 {
1868 MFEM_ABORT("Not implemented. Maybe assemble your bilinear form into a "
1869 "matrix and use SparseMatrix functions?");
1870 }
1871}
1872
1874{
1876 {
1877 MFEM_WARNING("Conforming assemble not supported for this assembly level!");
1878 return;
1879 }
1880
1881 Finalize();
1882
1884 if (P2)
1885 {
1886 SparseMatrix *R = Transpose(*P2);
1887 SparseMatrix *RA = mfem::Mult(*R, *mat);
1888 delete R;
1889 delete mat;
1890 mat = RA;
1891 }
1892
1894 if (P1)
1895 {
1896 SparseMatrix *RAP = mfem::Mult(*mat, *P1);
1897 delete mat;
1898 mat = RAP;
1899 }
1900
1901 height = mat->Height();
1902 width = mat->Width();
1903}
1904
1905
1907{
1908 const FiniteElement &trial_fe = *trial_fes->GetFE(i);
1909 const FiniteElement &test_fe = *test_fes->GetFE(i);
1910
1911 if (domain_integs.Size())
1912 {
1914 domain_integs[0]->AssembleElementMatrix2(trial_fe, test_fe, *eltrans,
1915 elmat);
1916 for (int k = 1; k < domain_integs.Size(); k++)
1917 {
1918 domain_integs[k]->AssembleElementMatrix2(trial_fe, test_fe, *eltrans,
1919 elemmat);
1920 elmat += elemmat;
1921 }
1922 }
1923 else
1924 {
1925 const int tr_dofs = trial_fe.GetDof() * trial_fes->GetVDim();
1926 const int te_dofs = test_fe.GetDof() * test_fes->GetVDim();
1927
1928 elmat.SetSize(te_dofs, tr_dofs);
1929 elmat = 0.0;
1930 }
1931}
1932
1934{
1935 const FiniteElement &trial_be = *trial_fes->GetBE(i);
1936 const FiniteElement &test_be = *test_fes->GetBE(i);
1937
1938 if (boundary_integs.Size())
1939 {
1941 boundary_integs[0]->AssembleElementMatrix2(trial_be, test_be, *eltrans,
1942 elmat);
1943 for (int k = 1; k < boundary_integs.Size(); k++)
1944 {
1945 boundary_integs[k]->AssembleElementMatrix2(trial_be, test_be, *eltrans,
1946 elemmat);
1947 elmat += elemmat;
1948 }
1949 }
1950 else
1951 {
1952 const int tr_dofs = trial_be.GetDof() * trial_fes->GetVDim();
1953 const int te_dofs = test_be.GetDof() * test_fes->GetVDim();
1954
1955 elmat.SetSize(te_dofs, tr_dofs);
1956 elmat = 0.0;
1957 }
1958}
1959
1961{
1963 Mesh *mesh = test_fes -> GetMesh();
1964 ftr = mesh->GetFaceElementTransformations(i);
1965 MFEM_ASSERT(ftr, "No associated face transformations.");
1966
1967 const FiniteElement *trial_fe1, *trial_fe2, *test_fe1, *test_fe2;
1968
1969 trial_fe1 = trial_fes->GetFE(ftr->Elem1No);
1970 test_fe1 = test_fes->GetFE(ftr->Elem1No);
1971 if (ftr->Elem2No >= 0)
1972 {
1973 trial_fe2 = trial_fes->GetFE(ftr->Elem2No);
1974 test_fe2 = test_fes->GetFE(ftr->Elem2No);
1975 }
1976 else
1977 {
1978 // The test_fe2 object is really a dummy and not used on the
1979 // boundaries, but we can't dereference a NULL pointer, and we don't
1980 // want to actually make a fake element.
1981 trial_fe2 = trial_fe1;
1982 test_fe2 = test_fe1;
1983 }
1984
1985 if (interior_face_integs.Size())
1986 {
1987 interior_face_integs[0]->AssembleFaceMatrix(*trial_fe1, *test_fe1, *trial_fe2,
1988 *test_fe2,
1989 *ftr, elmat);
1990 for (int k = 1; k < interior_face_integs.Size(); k++)
1991 {
1992 interior_face_integs[k]->AssembleFaceMatrix(*trial_fe1, *test_fe1, *trial_fe2,
1993 *test_fe2,
1994 *ftr, elemmat);
1995 elmat += elemmat;
1996 }
1997 }
1998 else
1999 {
2000 int tr_dofs = trial_fe1->GetDof() * trial_fes->GetVDim();
2001 int te_dofs = test_fe1->GetDof() * test_fes->GetVDim();
2002 if (ftr->Elem2No >= 0)
2003 {
2004 tr_dofs += trial_fe2->GetDof() * trial_fes->GetVDim();
2005 te_dofs += test_fe2->GetDof() * test_fes->GetVDim();
2006 }
2007
2008 elmat.SetSize(te_dofs, tr_dofs);
2009 elmat = 0.0;
2010 }
2011}
2012
2014{
2016 Mesh *mesh = test_fes -> GetMesh();
2017 ftr = mesh->GetBdrFaceTransformations(i);
2018 MFEM_ASSERT(ftr, "No associated boundary face.");
2019
2020 const FiniteElement *trial_fe1, *trial_fe2, *test_fe1, *test_fe2;
2021
2022 trial_fe1 = trial_fes->GetFE(ftr->Elem1No);
2023 test_fe1 = test_fes->GetFE(ftr->Elem1No);
2024 // The test_fe2 object is really a dummy and not used on the
2025 // boundaries, but we can't dereference a NULL pointer, and we don't
2026 // want to actually make a fake element.
2027 trial_fe2 = trial_fe1;
2028 test_fe2 = test_fe1;
2029
2030 if (boundary_face_integs.Size())
2031 {
2032 boundary_face_integs[0]->AssembleFaceMatrix(*trial_fe1, *test_fe1, *trial_fe2,
2033 *test_fe2,
2034 *ftr, elmat);
2035 for (int k = 1; k < boundary_face_integs.Size(); k++)
2036 {
2037 boundary_face_integs[k]->AssembleFaceMatrix(*trial_fe1, *test_fe1, *trial_fe2,
2038 *test_fe2,
2039 *ftr, elemmat);
2040 elmat += elemmat;
2041 }
2042 }
2043 else
2044 {
2045 const int tr_dofs = trial_fe1->GetDof() * trial_fes->GetVDim();
2046 const int te_dofs = test_fe1->GetDof() * test_fes->GetVDim();
2047
2048 elmat.SetSize(te_dofs, tr_dofs);
2049 elmat = 0.0;
2050 }
2051}
2052
2054{
2056 Mesh *mesh = test_fes -> GetMesh();
2057 ftr = mesh->GetFaceElementTransformations(i);
2058 MFEM_ASSERT(ftr, "No associated face transformation.");
2059
2060 const FiniteElement *trial_face_fe, *test_fe1, *test_fe2;
2061
2062 trial_face_fe = trial_fes->GetFaceElement(i);
2063 test_fe1 = test_fes->GetFE(ftr->Elem1No);
2064 if (ftr->Elem2No >= 0)
2065 {
2066 test_fe2 = test_fes->GetFE(ftr->Elem2No);
2067 }
2068 else
2069 {
2070 // The test_fe2 object is really a dummy and not used on the
2071 // boundaries, but we can't dereference a NULL pointer, and we don't
2072 // want to actually make a fake element.
2073 test_fe2 = test_fe1;
2074 }
2075
2076 if (trace_face_integs.Size())
2077 {
2078 trace_face_integs[0]->AssembleFaceMatrix(*trial_face_fe, *test_fe1, *test_fe2,
2079 *ftr, elmat);
2080 for (int k = 1; k < trace_face_integs.Size(); k++)
2081 {
2082 trace_face_integs[k]->AssembleFaceMatrix(*trial_face_fe, *test_fe1, *test_fe2,
2083 *ftr, elemmat);
2084 elmat += elemmat;
2085 }
2086 }
2087 else
2088 {
2089 const int tr_face_dofs = trial_face_fe->GetDof() * trial_fes->GetVDim();
2090 int te_dofs = test_fe1->GetDof() * test_fes->GetVDim();
2091 if (ftr->Elem2No >= 0)
2092 {
2093 te_dofs += test_fe2->GetDof() * test_fes->GetVDim();
2094 }
2095
2096 elmat.SetSize(te_dofs, tr_face_dofs);
2097 elmat = 0.0;
2098 }
2099}
2100
2102 DenseMatrix &elmat) const
2103{
2105 Mesh *mesh = test_fes -> GetMesh();
2106 ftr = mesh->GetBdrFaceTransformations(i);
2107 MFEM_ASSERT(ftr, "No associated boundary face.");
2108
2109 const FiniteElement *trial_face_fe, *test_fe1, *test_fe2;
2110 int iface = mesh->GetBdrElementFaceIndex(i);
2111 trial_face_fe = trial_fes->GetFaceElement(iface);
2112 test_fe1 = test_fes->GetFE(ftr->Elem1No);
2113 // The test_fe2 object is really a dummy and not used on the
2114 // boundaries, but we can't dereference a NULL pointer, and we don't
2115 // want to actually make a fake element.
2116 test_fe2 = test_fe1;
2117
2118 if (boundary_trace_face_integs.Size())
2119 {
2120 boundary_trace_face_integs[0]->AssembleFaceMatrix(*trial_face_fe, *test_fe1,
2121 *test_fe2,
2122 *ftr, elmat);
2123 for (int k = 1; k < boundary_trace_face_integs.Size(); k++)
2124 {
2125 boundary_trace_face_integs[k]->AssembleFaceMatrix(*trial_face_fe, *test_fe1,
2126 *test_fe2,
2127 *ftr, elemmat);
2128 elmat += elemmat;
2129 }
2130 }
2131 else
2132 {
2133 const int tr_face_dofs = trial_face_fe->GetDof() * trial_fes->GetVDim();
2134 int te_dofs = test_fe1->GetDof() * test_fes->GetVDim();
2135
2136 elmat.SetSize(te_dofs, tr_face_dofs);
2137 elmat = 0.0;
2138 }
2139}
2140
2142 int i, const DenseMatrix &elmat, int skip_zeros)
2143{
2144 AssembleElementMatrix(i, elmat, trial_vdofs, test_vdofs, skip_zeros);
2145}
2146
2148 int i, const DenseMatrix &elmat, Array<int> &trial_vdofs_,
2149 Array<int> &test_vdofs_, int skip_zeros)
2150{
2151 trial_fes->GetElementVDofs(i, trial_vdofs_);
2152 test_fes->GetElementVDofs(i, test_vdofs_);
2153 if (mat == NULL)
2154 {
2155 mat = new SparseMatrix(height, width);
2156 }
2157 mat->AddSubMatrix(test_vdofs_, trial_vdofs_, elmat, skip_zeros);
2158}
2159
2161 int i, const DenseMatrix &elmat, int skip_zeros)
2162{
2163 AssembleBdrElementMatrix(i, elmat, trial_vdofs, test_vdofs, skip_zeros);
2164}
2165
2167 int i, const DenseMatrix &elmat, Array<int> &trial_vdofs_,
2168 Array<int> &test_vdofs_, int skip_zeros)
2169{
2170 trial_fes->GetBdrElementVDofs(i, trial_vdofs_);
2171 test_fes->GetBdrElementVDofs(i, test_vdofs_);
2172 if (mat == NULL)
2173 {
2174 mat = new SparseMatrix(height, width);
2175 }
2176 mat->AddSubMatrix(test_vdofs_, trial_vdofs_, elmat, skip_zeros);
2177}
2178
2180 const Array<int> &bdr_attr_is_ess, const Vector &sol, Vector &rhs )
2181{
2182 Array<int> trial_ess_dofs;
2183 trial_fes->GetEssentialVDofs(bdr_attr_is_ess, trial_ess_dofs);
2184 mat->EliminateCols(trial_ess_dofs, &sol, &rhs);
2185}
2186
2188 &bdr_attr_is_ess)
2189{
2190 Array<int> trial_ess_dofs;
2191 trial_fes->GetEssentialVDofs(bdr_attr_is_ess, trial_ess_dofs);
2192 mat->EliminateCols(trial_ess_dofs);
2193}
2194
2196 const Vector &sol, Vector &rhs)
2197{
2198 Array<int> trial_vdofs_marker;
2200 trial_vdofs_marker);
2201 mat->EliminateCols(trial_vdofs_marker, &sol, &rhs);
2202}
2203
2205{
2206 if (mat_e == NULL)
2207 {
2208 mat_e = new SparseMatrix(mat->Height(), mat->Width());
2209 }
2210
2211 Array<int> trial_vdofs_marker;
2213 trial_vdofs_marker);
2214 mat->EliminateCols(trial_vdofs_marker, *mat_e);
2215 mat_e->Finalize();
2216}
2217
2219 const Vector &x, Vector &b)
2220{
2221 mat_e->AddMult(x, b, -1.);
2222}
2223
2225 const Array<int> &marked_vdofs, const Vector &sol, Vector &rhs)
2226{
2227 mat->EliminateCols(marked_vdofs, &sol, &rhs);
2228}
2229
2231 &bdr_attr_is_ess)
2232{
2233 int i, j, k;
2234 Array<int> te_vdofs;
2235
2236 for (i = 0; i < test_fes -> GetNBE(); i++)
2237 if (bdr_attr_is_ess[test_fes -> GetBdrAttribute (i)-1])
2238 {
2239 test_fes -> GetBdrElementVDofs (i, te_vdofs);
2240 for (j = 0; j < te_vdofs.Size(); j++)
2241 {
2242 if ( (k = te_vdofs[j]) < 0 )
2243 {
2244 k = -1-k;
2245 }
2246 mat -> EliminateRow (k);
2247 }
2248 }
2249}
2250
2252{
2253 for (int i=0; i<test_vdofs_.Size(); ++i)
2254 {
2255 mat->EliminateRow(test_vdofs_[i]);
2256 }
2257}
2258
2260 const Array<int> &trial_tdof_list,
2261 const Array<int> &test_tdof_list,
2262 OperatorHandle &A)
2263
2264{
2265 if (ext)
2266 {
2267 ext->FormRectangularSystemOperator(trial_tdof_list, test_tdof_list, A);
2268 return;
2269 }
2270
2273
2274 mat->Finalize();
2275
2276 if (test_P && trial_P)
2277 {
2278 SparseMatrix *m = RAP(*test_P, *mat, *trial_P);
2279 delete mat;
2280 mat = m;
2281 }
2282 else if (test_P)
2283 {
2284 SparseMatrix *m = TransposeMult(*test_P, *mat);
2285 delete mat;
2286 mat = m;
2287 }
2288 else if (trial_P)
2289 {
2290 SparseMatrix *m = mfem::Mult(*mat, *trial_P);
2291 delete mat;
2292 mat = m;
2293 }
2294
2295 EliminateTrialVDofs(trial_tdof_list);
2296 EliminateTestVDofs(test_tdof_list);
2297
2298 A.Reset(mat, false);
2299}
2300
2302 const Array<int> &trial_tdof_list,
2303 const Array<int> &test_tdof_list,
2304 Vector &x, Vector &b,
2305 OperatorHandle &A,
2306 Vector &X, Vector &B)
2307{
2308 if (ext)
2309 {
2310 ext->FormRectangularLinearSystem(trial_tdof_list, test_tdof_list,
2311 x, b, A, X, B);
2312 return;
2313 }
2314
2315 const Operator *Pi = this->GetProlongation();
2316 const Operator *Po = this->GetOutputProlongation();
2317 const Operator *Ri = this->GetRestriction();
2318 InitTVectors(Po, Ri, Pi, x, b, X, B);
2319
2320 if (!mat_e)
2321 {
2322 FormRectangularSystemMatrix(trial_tdof_list, test_tdof_list,
2323 A); // Set A = mat_e
2324 }
2325 // Eliminate essential BCs with B -= Ab xb
2326 EliminateTrialVDofsInRHS(trial_tdof_list, X, B);
2327
2328 B.SetSubVector(test_tdof_list, 0.0);
2329}
2330
2332{
2333 delete mat;
2334 mat = NULL;
2335 delete mat_e;
2336 mat_e = NULL;
2339 if (ext) { ext->Update(); }
2340}
2341
2343{
2344 if (mat) { delete mat; }
2345 if (mat_e) { delete mat_e; }
2346 if (!extern_bfs)
2347 {
2348 int i;
2349 for (i = 0; i < domain_integs.Size(); i++) { delete domain_integs[i]; }
2350 for (i = 0; i < boundary_integs.Size(); i++)
2351 { delete boundary_integs[i]; }
2352 for (i = 0; i < interior_face_integs.Size(); i++)
2353 { delete interior_face_integs[i]; }
2354 for (i = 0; i < boundary_face_integs.Size(); i++)
2355 { delete boundary_face_integs[i]; }
2356 for (i = 0; i < trace_face_integs.Size(); i++)
2357 { delete trace_face_integs[i]; }
2358 for (i = 0; i < boundary_trace_face_integs.Size(); i++)
2359 { delete boundary_trace_face_integs[i]; }
2360 }
2361}
2362
2364{
2365 if (ext)
2366 {
2367 MFEM_ABORT("the assembly level has already been set!");
2368 }
2369 assembly = assembly_level;
2370 switch (assembly)
2371 {
2374 // Use the original implementation for now
2375 break;
2377 MFEM_ABORT("Element assembly not supported yet... stay tuned!");
2378 break;
2380 ext.reset(new PADiscreteLinearOperatorExtension(this));
2381 break;
2383 MFEM_ABORT("Matrix-free action not supported yet... stay tuned!");
2384 break;
2385 default:
2386 MFEM_ABORT("Unknown assembly level");
2387 }
2388}
2389
2391{
2392 if (ext)
2393 {
2394 ext->Assemble();
2395 return;
2396 }
2397
2398 ElementTransformation *eltrans;
2399 DenseMatrix elmat;
2400
2401 Mesh *mesh = test_fes->GetMesh();
2402
2403 if (mat == NULL)
2404 {
2405 mat = new SparseMatrix(height, width);
2406 }
2407
2408 if (domain_integs.Size())
2409 {
2410 for (int k = 0; k < domain_integs.Size(); k++)
2411 {
2412 if (domain_integs_marker[k] != NULL)
2413 {
2414 MFEM_VERIFY(domain_integs_marker[k]->Size() ==
2415 (mesh->attributes.Size() ? mesh->attributes.Max() : 0),
2416 "invalid element marker for domain integrator #"
2417 << k << ", counting from zero");
2418 }
2419 }
2420
2421 DofTransformation dom_dof_trans;
2422 DofTransformation ran_dof_trans;
2423 for (int i = 0; i < test_fes->GetNE(); i++)
2424 {
2425 const int elem_attr = mesh->GetAttribute(i);
2426 trial_fes->GetElementVDofs(i, trial_vdofs, dom_dof_trans);
2427 test_fes->GetElementVDofs(i, test_vdofs, ran_dof_trans);
2428 eltrans = test_fes->GetElementTransformation(i);
2429
2431 elmat = 0.0;
2432 for (int k = 0; k < domain_integs.Size(); k++)
2433 {
2434 if (domain_integs_marker[k] == NULL ||
2435 (*(domain_integs_marker[k]))[elem_attr-1] == 1)
2436 {
2437 domain_integs[k]->AssembleElementMatrix2(*trial_fes->GetFE(i),
2438 *test_fes->GetFE(i),
2439 *eltrans, elemmat);
2440 elmat += elemmat;
2441 }
2442 }
2443 TransformPrimal(ran_dof_trans, dom_dof_trans, elemmat);
2445 }
2446 }
2447
2448 if (trace_face_integs.Size())
2449 {
2450 const int nfaces = test_fes->GetMesh()->GetNumFaces();
2451 for (int i = 0; i < nfaces; i++)
2452 {
2455 eltrans = test_fes->GetMesh()->GetFaceTransformation(i);
2456
2458 elmat = 0.0;
2459 for (int k = 0; k < trace_face_integs.Size(); k++)
2460 {
2461 trace_face_integs[k]->AssembleElementMatrix2(*trial_fes->GetFaceElement(i),
2463 *eltrans, elemmat);
2464 elmat += elemmat;
2465 }
2466 mat->SetSubMatrix(test_vdofs, trial_vdofs, elmat, skip_zeros);
2467 }
2468 }
2469}
2470
2471}
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
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:385
int Size() const
Return the logical size of the array.
Definition array.hpp:166
int Append(const T &el)
Append element 'el' to array, resize if necessary.
Definition array.hpp:912
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 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(),...
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
real_t * GetData() const
Returns the matrix data array. Warning: this method casts away constness.
Definition densemat.hpp:126
void SetSize(int s)
Change the size of the DenseMatrix to s x s.
Definition densemat.hpp:116
void ClearExternalData()
Definition densemat.hpp:103
int Size() const
For backward compatibility define Size to be synonym of Width()
Definition densemat.hpp:110
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:208
const SparseMatrix * GetConformingRestriction() const
The returned SparseMatrix is owned by the FiniteElementSpace.
Definition fespace.cpp:1433
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
const FiniteElement * GetBE(int i) const
Returns pointer to the FiniteElement in the FiniteElementCollection associated with i'th boundary fac...
Definition fespace.cpp:3870
virtual int GetTrueVSize() const
Return the number of vector true (conforming) dofs.
Definition fespace.hpp:829
ElementTransformation * GetElementTransformation(int i) const
Definition fespace.hpp:905
virtual const SparseMatrix * GetRestrictionMatrix() const
The returned SparseMatrix is owned by the FiniteElementSpace.
Definition fespace.hpp:719
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:779
const NURBSExtension * GetNURBSext() const
Definition fespace.hpp:646
virtual const Operator * GetProlongationMatrix() const
Definition fespace.hpp:696
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
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:3824
Ordering::Type GetOrdering() const
Return the ordering method.
Definition fespace.hpp:854
ElementTransformation * GetBdrElementTransformation(int i) const
Returns ElementTransformation for the i-th boundary element.
Definition fespace.hpp:914
int GetNE() const
Returns number of elements in the mesh.
Definition fespace.hpp:869
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:331
const FiniteElement * GetFaceElement(int i) const
Returns pointer to the FiniteElement in the FiniteElementCollection associated with i'th face in the ...
Definition fespace.cpp:3903
const SparseMatrix * GetConformingProlongation() const
Definition fespace.cpp:1426
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
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:3860
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:319
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:554
void GetPatchVDofs(int i, Array< int > &vdofs) const
Returns indices of degrees of freedom in vdofs for NURBS patch i.
Definition fespace.cpp:325
Abstract class for all finite elements.
Definition fe_base.hpp:247
int GetDof() const
Returns the number of degrees of freedom in the finite element.
Definition fe_base.hpp:337
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:65
virtual FaceElementTransformations * GetFaceElementTransformations(int FaceNo, int mask=31)
Definition mesh.cpp:1104
Array< int > bdr_attributes
A list of all unique boundary attributes used by the Mesh.
Definition mesh.hpp:304
NURBSExtension * NURBSext
Optional NURBS mesh extension.
Definition mesh.hpp:312
int GetNumFaces() const
Return the number of faces (3D), edges (2D) or vertices (1D).
Definition mesh.cpp:6846
int GetAttribute(int i) const
Return the attribute of element i.
Definition mesh.hpp:1484
int GetBdrAttribute(int i) const
Return the attribute of boundary element i.
Definition mesh.hpp:1490
int GetBdrElementFaceIndex(int be_idx) const
Return the local face (codimension-1) index for the given boundary element index.
Definition mesh.hpp:1689
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:1223
FaceElementTransformations * GetInteriorFaceTransformations(int FaceNo)
See GetFaceElementTransformations().
Definition mesh.cpp:1203
Table * GetFaceToElementTable() const
Definition mesh.cpp:7801
Array< int > attributes
A list of all unique element attributes used by the Mesh.
Definition mesh.hpp:302
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:824
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:25
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).
DiagonalPolicy
Defines operator diagonal policy upon elimination of rows and/or columns.
Definition operator.hpp:48
@ DIAG_ONE
Set the diagonal value to one.
Definition operator.hpp:50
@ DIAG_KEEP
Keep the diagonal value.
Definition operator.hpp:51
int Width() const
Get the width (size of input) of the Operator. Synonym with NumCols().
Definition operator.hpp:72
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:100
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: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
void MakeRef(Vector &base, int offset, int size)
Reset the Vector to be a reference to a sub-vector of base.
Definition vector.hpp:660
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:829
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)